netdir.c (7c478bd9) netdir.c (61961e0f)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *

--- 5 unchanged lines hidden (view full) ---

14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *

--- 5 unchanged lines hidden (view full) ---

14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
22/*
23/*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28/* All Rights Reserved */
29
30/*
31 * Portions of this source code were derived from Berkeley 4.3 BSD

--- 15 unchanged lines hidden (view full) ---

47#include <sys/types.h>
48#include <errno.h>
49#include <tiuser.h>
50#include <netdir.h>
51#include <netconfig.h>
52#include <string.h>
53#include <sys/file.h>
54#include <dlfcn.h>
25 * Use is subject to license terms.
26 */
27
28/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29/* All Rights Reserved */
30
31/*
32 * Portions of this source code were derived from Berkeley 4.3 BSD

--- 15 unchanged lines hidden (view full) ---

48#include <sys/types.h>
49#include <errno.h>
50#include <tiuser.h>
51#include <netdir.h>
52#include <netconfig.h>
53#include <string.h>
54#include <sys/file.h>
55#include <dlfcn.h>
55#include <rpc/trace.h>
56#include <stdlib.h>
56#include <malloc.h>
57#include <syslog.h>
58#include <nss_netdir.h>
59#include <netinet/in.h>
60#include <netdb.h>
61
62/* messaging stuff. */
63

--- 30 unchanged lines hidden (view full) ---

94 * interface.
95 */
96
97#undef _nderror
98
99int _nderror;
100
101int *
57#include <malloc.h>
58#include <syslog.h>
59#include <nss_netdir.h>
60#include <netinet/in.h>
61#include <netdb.h>
62
63/* messaging stuff. */
64

--- 30 unchanged lines hidden (view full) ---

95 * interface.
96 */
97
98#undef _nderror
99
100int _nderror;
101
102int *
102__nderror()
103__nderror(void)
103{
104 static pthread_key_t nderror_key = 0;
105 int *ret;
106
107 if (thr_main())
108 return (&_nderror);
109 ret = thr_get_storage(&nderror_key, sizeof (int), free);
110 /* if thr_get_storage fails we return the address of _nderror */

--- 8 unchanged lines hidden (view full) ---

119 * We have to be careful for the case of the same library being loaded
120 * with different names (e.g., straddr.so and /usr/lib/straddr.so).
121 * We check for this case by looking at the gbn and name fields.
122 * If the gbn address is the same, but the names are different, then we
123 * have accidentally reloaded the library. We dlclose the new version,
124 * and then update 'translate' with the old versions of the symbols.
125 */
126void
104{
105 static pthread_key_t nderror_key = 0;
106 int *ret;
107
108 if (thr_main())
109 return (&_nderror);
110 ret = thr_get_storage(&nderror_key, sizeof (int), free);
111 /* if thr_get_storage fails we return the address of _nderror */

--- 8 unchanged lines hidden (view full) ---

120 * We have to be careful for the case of the same library being loaded
121 * with different names (e.g., straddr.so and /usr/lib/straddr.so).
122 * We check for this case by looking at the gbn and name fields.
123 * If the gbn address is the same, but the names are different, then we
124 * have accidentally reloaded the library. We dlclose the new version,
125 * and then update 'translate' with the old versions of the symbols.
126 */
127void
127add_to_xlate_list(translate)
128struct translator *translate;
128add_to_xlate_list(struct translator *translate)
129{
130 struct translator *t;
131
132 for (t = xlate_list; t; t = t->next) {
133 if (strcmp(translate->tr_name, t->tr_name) == 0) {
134 return;
135 }
136 }

--- 16 unchanged lines hidden (view full) ---

153 *
154 * After all, any problem can be solved by one more layer of abstraction..
155 *
156 * This routine when called with a netconfig with "inet6" type of transports
157 * returns pure IPv6 addresses only and if no IPv6 address is found it
158 * returns none - Bug Id. 4276329
159 */
160int
129{
130 struct translator *t;
131
132 for (t = xlate_list; t; t = t->next) {
133 if (strcmp(translate->tr_name, t->tr_name) == 0) {
134 return;
135 }
136 }

--- 16 unchanged lines hidden (view full) ---

153 *
154 * After all, any problem can be solved by one more layer of abstraction..
155 *
156 * This routine when called with a netconfig with "inet6" type of transports
157 * returns pure IPv6 addresses only and if no IPv6 address is found it
158 * returns none - Bug Id. 4276329
159 */
160int
161netdir_getbyname(tp, serv, addrs)
162 struct netconfig *tp; /* The network config entry */
163 struct nd_hostserv *serv; /* the service, host pair */
164 struct nd_addrlist **addrs; /* the answer */
161netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
162 struct nd_addrlist **addrs)
165{
163{
166 trace1(TR_netdir_getbyname, 0);
167 if (tp == 0) {
168 _nderror = ND_BADARG;
164 if (tp == 0) {
165 _nderror = ND_BADARG;
169 trace1(TR_netdir_getbyname, 1);
170 return (_nderror);
171 }
172 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
166 return (_nderror);
167 }
168 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
173 (tp->nc_nlookups == 0)) {
169 (tp->nc_nlookups == 0)) {
174 struct nss_netdirbyname_in nssin;
175 union nss_netdirbyname_out nssout;
176
177 nssin.op_t = NETDIR_BY;
178 nssin.arg.nd_hs = serv;
179 /*
180 * In code path of case NETDIR_BY,
181 * it also calls DOOR_GETIPNODEBYNAME_R.
182 * So af_family and flags are set to
183 * get V4 addresses only.
184 */
185 nssin.arg.nss.host6.af_family = AF_INET;
186 nssin.arg.nss.host6.flags = 0;
187 nssout.nd_alist = addrs;
188 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout));
170 struct nss_netdirbyname_in nssin;
171 union nss_netdirbyname_out nssout;
172
173 nssin.op_t = NETDIR_BY;
174 nssin.arg.nd_hs = serv;
175 /*
176 * In code path of case NETDIR_BY,
177 * it also calls DOOR_GETIPNODEBYNAME_R.
178 * So af_family and flags are set to
179 * get V4 addresses only.
180 */
181 nssin.arg.nss.host6.af_family = AF_INET;
182 nssin.arg.nss.host6.flags = 0;
183 nssout.nd_alist = addrs;
184 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout));
189 } else if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
190 (tp->nc_nlookups == 0)) {
185 }
186 if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
187 (tp->nc_nlookups == 0)) {
191 struct nss_netdirbyname_in nssin;
192 union nss_netdirbyname_out nssout;
193
194 nssin.op_t = NETDIR_BY6;
195 nssin.arg.nd_hs = serv;
196 /* get both V4 & V6 addresses */
197 nssin.arg.nss.host6.af_family = AF_INET6;
198 nssin.arg.nss.host6.flags = (AI_ALL | AI_V4MAPPED);
199 nssout.nd_alist = addrs;
200 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout));
188 struct nss_netdirbyname_in nssin;
189 union nss_netdirbyname_out nssout;
190
191 nssin.op_t = NETDIR_BY6;
192 nssin.arg.nd_hs = serv;
193 /* get both V4 & V6 addresses */
194 nssin.arg.nss.host6.af_family = AF_INET6;
195 nssin.arg.nss.host6.flags = (AI_ALL | AI_V4MAPPED);
196 nssout.nd_alist = addrs;
197 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout));
201 } else {
202 trace1(TR_netdir_getbyname, 1);
203 return (__classic_netdir_getbyname(tp, serv, addrs));
204 }
198 }
199 return (__classic_netdir_getbyname(tp, serv, addrs));
205}
206
207/*
208 * This routine is the svr4_classic routine for resolving host/service/xprt
209 * triples into a bunch of netbufs that should connect you to that particular
210 * service. RPC uses it to contact the binder service (rpcbind).
211 *
212 * It's either called by the real netdir_getbyname() interface above
213 * or by gethost/servbyname when nametoaddr libs are specified in
214 * /etc/netconfig with an intent of bypassing the name service switch.
215 */
216int
200}
201
202/*
203 * This routine is the svr4_classic routine for resolving host/service/xprt
204 * triples into a bunch of netbufs that should connect you to that particular
205 * service. RPC uses it to contact the binder service (rpcbind).
206 *
207 * It's either called by the real netdir_getbyname() interface above
208 * or by gethost/servbyname when nametoaddr libs are specified in
209 * /etc/netconfig with an intent of bypassing the name service switch.
210 */
211int
217__classic_netdir_getbyname(tp, serv, addrs)
218 struct netconfig *tp; /* The network config entry */
219 struct nd_hostserv *serv; /* the service, host pair */
220 struct nd_addrlist **addrs; /* the answer */
212__classic_netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
213 struct nd_addrlist **addrs)
221{
222 struct translator *t; /* pointer to translator list */
223 struct nd_addrlist *nn; /* the results */
224 char *lr; /* routines to try */
225 int i; /* counts the routines */
226
214{
215 struct translator *t; /* pointer to translator list */
216 struct nd_addrlist *nn; /* the results */
217 char *lr; /* routines to try */
218 int i; /* counts the routines */
219
227 trace1(TR_netdir_getbyname, 0);
228 _nderror = ND_SYSTEM;
229 for (i = 0; i < tp->nc_nlookups; i++) {
230 lr = *((tp->nc_lookups) + i);
231 for (t = xlate_list; t; t = t->next) {
232 if (strcmp(lr, t->tr_name) == 0) {
233 nn = (*(t->gbn))(tp, serv);
234 if (nn) {
235 *addrs = nn;
220 _nderror = ND_SYSTEM;
221 for (i = 0; i < tp->nc_nlookups; i++) {
222 lr = *((tp->nc_lookups) + i);
223 for (t = xlate_list; t; t = t->next) {
224 if (strcmp(lr, t->tr_name) == 0) {
225 nn = (*(t->gbn))(tp, serv);
226 if (nn) {
227 *addrs = nn;
236 trace1(TR_netdir_getbyname, 1);
237 return (0);
228 return (0);
238 } else {
239 if (_nderror < 0) {
240 trace1(TR_netdir_getbyname, 1);
241 return (_nderror);
242 }
243 break;
244 }
229 }
230 if (_nderror < 0) {
231 return (_nderror);
232 }
233 break;
245 }
246 }
247 /* If we didn't find it try loading it */
248 if (!t) {
249 if ((t = load_xlate(lr)) != NULL) {
250 /* add it to the list */
234 }
235 }
236 /* If we didn't find it try loading it */
237 if (!t) {
238 if ((t = load_xlate(lr)) != NULL) {
239 /* add it to the list */
251 mutex_lock(&xlate_lock);
240 (void) mutex_lock(&xlate_lock);
252 add_to_xlate_list(t);
241 add_to_xlate_list(t);
253 mutex_unlock(&xlate_lock);
242 (void) mutex_unlock(&xlate_lock);
254 nn = (*(t->gbn))(tp, serv);
255 if (nn) {
256 *addrs = nn;
243 nn = (*(t->gbn))(tp, serv);
244 if (nn) {
245 *addrs = nn;
257 trace1(TR_netdir_getbyname, 1);
258 return (0);
246 return (0);
259 } else {
260 if (_nderror < 0) {
261 trace1(TR_netdir_getbyname, 1);
262 return (_nderror);
263 }
264 }
247 }
248 if (_nderror < 0) {
249 return (_nderror);
250 }
265 } else {
266 if (_nderror == ND_SYSTEM) { /* retry cache */
267 _nderror = ND_OK;
268 i--;
269 continue;
270 }
271 }
272 }
273 }
251 } else {
252 if (_nderror == ND_SYSTEM) { /* retry cache */
253 _nderror = ND_OK;
254 i--;
255 continue;
256 }
257 }
258 }
259 }
274 trace1(TR_netdir_getbyname, 1);
275 return (_nderror); /* No one works */
276}
277
278/*
279 * This routine is similar to the one above except that it tries to resolve
280 * the name by the address passed.
281 */
282int
260 return (_nderror); /* No one works */
261}
262
263/*
264 * This routine is similar to the one above except that it tries to resolve
265 * the name by the address passed.
266 */
267int
283netdir_getbyaddr(tp, serv, addr)
284 struct netconfig *tp; /* The netconfig entry */
285 struct nd_hostservlist **serv; /* the answer(s) */
286 struct netbuf *addr; /* the address we have */
268netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
269 struct netbuf *addr)
287{
270{
288 trace1(TR_netdir_getbyaddr, 0);
289 if (tp == 0) {
290 _nderror = ND_BADARG;
271 if (tp == 0) {
272 _nderror = ND_BADARG;
291 trace1(TR_netdir_getbyaddr, 1);
292 return (_nderror);
293 }
294 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
295 (tp->nc_nlookups == 0)) {
296 struct nss_netdirbyaddr_in nssin;
297 union nss_netdirbyaddr_out nssout;
298
299 nssin.op_t = NETDIR_BY;
300 nssin.arg.nd_nbuf = addr;
301 nssout.nd_hslist = serv;
273 return (_nderror);
274 }
275 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
276 (tp->nc_nlookups == 0)) {
277 struct nss_netdirbyaddr_in nssin;
278 union nss_netdirbyaddr_out nssout;
279
280 nssin.op_t = NETDIR_BY;
281 nssin.arg.nd_nbuf = addr;
282 nssout.nd_hslist = serv;
302 trace1(TR_netdir_getbyaddr, 1);
303 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
283 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
304 } else if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
284 }
285 if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
305 (tp->nc_nlookups == 0)) {
306 struct nss_netdirbyaddr_in nssin;
307 union nss_netdirbyaddr_out nssout;
308
309 nssin.op_t = NETDIR_BY6;
310 nssin.arg.nd_nbuf = addr;
311 nssout.nd_hslist = serv;
286 (tp->nc_nlookups == 0)) {
287 struct nss_netdirbyaddr_in nssin;
288 union nss_netdirbyaddr_out nssout;
289
290 nssin.op_t = NETDIR_BY6;
291 nssin.arg.nd_nbuf = addr;
292 nssout.nd_hslist = serv;
312 trace1(TR_netdir_getbyaddr, 1);
313 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
293 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
314 } else {
315 trace1(TR_netdir_getbyaddr, 1);
316 return (__classic_netdir_getbyaddr(tp, serv, addr));
317 }
294 }
295 return (__classic_netdir_getbyaddr(tp, serv, addr));
318}
319/*
320 * This routine is similar to the one above except that it instructs the
321 * _get_hostserv_inetnetdir_byaddr not to do a service lookup.
322 */
323int
296}
297/*
298 * This routine is similar to the one above except that it instructs the
299 * _get_hostserv_inetnetdir_byaddr not to do a service lookup.
300 */
301int
324__netdir_getbyaddr_nosrv(tp, serv, addr)
325 struct netconfig *tp; /* The netconfig entry */
326 struct nd_hostservlist **serv; /* the answer(s) */
327 struct netbuf *addr; /* the address we have */
302__netdir_getbyaddr_nosrv(struct netconfig *tp, struct nd_hostservlist **serv,
303 struct netbuf *addr)
328{
304{
329 trace1(TR_netdir_getbyaddr, 0);
330 if (tp == 0) {
331 _nderror = ND_BADARG;
305 if (tp == 0) {
306 _nderror = ND_BADARG;
332 trace1(TR_netdir_getbyaddr, 1);
333 return (_nderror);
334 }
335 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
336 (tp->nc_nlookups == 0)) {
337 struct nss_netdirbyaddr_in nssin;
338 union nss_netdirbyaddr_out nssout;
339
340 nssin.op_t = NETDIR_BY_NOSRV;
341 nssin.arg.nd_nbuf = addr;
342 nssout.nd_hslist = serv;
307 return (_nderror);
308 }
309 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
310 (tp->nc_nlookups == 0)) {
311 struct nss_netdirbyaddr_in nssin;
312 union nss_netdirbyaddr_out nssout;
313
314 nssin.op_t = NETDIR_BY_NOSRV;
315 nssin.arg.nd_nbuf = addr;
316 nssout.nd_hslist = serv;
343 trace1(TR_netdir_getbyaddr, 1);
344 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
317 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
345 } else if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
318 }
319 if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
346 (tp->nc_nlookups == 0)) {
347 struct nss_netdirbyaddr_in nssin;
348 union nss_netdirbyaddr_out nssout;
349
350 nssin.op_t = NETDIR_BY_NOSRV6;
351 nssin.arg.nd_nbuf = addr;
352 nssout.nd_hslist = serv;
320 (tp->nc_nlookups == 0)) {
321 struct nss_netdirbyaddr_in nssin;
322 union nss_netdirbyaddr_out nssout;
323
324 nssin.op_t = NETDIR_BY_NOSRV6;
325 nssin.arg.nd_nbuf = addr;
326 nssout.nd_hslist = serv;
353 trace1(TR_netdir_getbyaddr, 1);
354 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
327 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
355 } else {
356 trace1(TR_netdir_getbyaddr, 1);
357 return (__classic_netdir_getbyaddr(tp, serv, addr));
358 }
328 }
329 return (__classic_netdir_getbyaddr(tp, serv, addr));
359}
360
361/*
362 * This routine is the svr4_classic routine for resolving a netbuf struct
363 * into a bunch of host/service name pairs.
364 *
365 * It's either called by the real netdir_getbyaddr() interface above
366 * or by gethost/servbyaddr when nametoaddr libs are specified in
367 * /etc/netconfig with an intent of bypassing the name service switch.
368 */
369int
330}
331
332/*
333 * This routine is the svr4_classic routine for resolving a netbuf struct
334 * into a bunch of host/service name pairs.
335 *
336 * It's either called by the real netdir_getbyaddr() interface above
337 * or by gethost/servbyaddr when nametoaddr libs are specified in
338 * /etc/netconfig with an intent of bypassing the name service switch.
339 */
340int
370__classic_netdir_getbyaddr(tp, serv, addr)
371 struct netconfig *tp; /* The netconfig entry */
372 struct nd_hostservlist **serv; /* the answer(s) */
373 struct netbuf *addr; /* the address we have */
341__classic_netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
342 struct netbuf *addr)
374{
375 struct translator *t; /* pointer to translator list */
376 struct nd_hostservlist *hs; /* the results */
377 char *lr; /* routines to try */
378 int i; /* counts the routines */
379
343{
344 struct translator *t; /* pointer to translator list */
345 struct nd_hostservlist *hs; /* the results */
346 char *lr; /* routines to try */
347 int i; /* counts the routines */
348
380 trace1(TR_netdir_getbyaddr, 0);
381 _nderror = ND_SYSTEM;
382 for (i = 0; i < tp->nc_nlookups; i++) {
383 lr = *((tp->nc_lookups) + i);
384 for (t = xlate_list; t; t = t->next) {
385 if (strcmp(lr, t->tr_name) == 0) {
386 hs = (*(t->gba))(tp, addr);
387 if (hs) {
388 *serv = hs;
349 _nderror = ND_SYSTEM;
350 for (i = 0; i < tp->nc_nlookups; i++) {
351 lr = *((tp->nc_lookups) + i);
352 for (t = xlate_list; t; t = t->next) {
353 if (strcmp(lr, t->tr_name) == 0) {
354 hs = (*(t->gba))(tp, addr);
355 if (hs) {
356 *serv = hs;
389 trace1(TR_netdir_getbyaddr, 1);
390 return (0);
357 return (0);
391 } else {
392 if (_nderror < 0) {
393 trace1(TR_netdir_getbyaddr, 1);
394 return (_nderror);
395 }
396 break;
397 }
358 }
359 if (_nderror < 0)
360 return (_nderror);
361 break;
398 }
399 }
400 /* If we didn't find it try loading it */
401 if (!t) {
402 if ((t = load_xlate(lr)) != NULL) {
403 /* add it to the list */
362 }
363 }
364 /* If we didn't find it try loading it */
365 if (!t) {
366 if ((t = load_xlate(lr)) != NULL) {
367 /* add it to the list */
404 mutex_lock(&xlate_lock);
368 (void) mutex_lock(&xlate_lock);
405 add_to_xlate_list(t);
369 add_to_xlate_list(t);
406 mutex_unlock(&xlate_lock);
370 (void) mutex_unlock(&xlate_lock);
407 hs = (*(t->gba))(tp, addr);
408 if (hs) {
409 *serv = hs;
371 hs = (*(t->gba))(tp, addr);
372 if (hs) {
373 *serv = hs;
410 trace1(TR_netdir_getbyaddr, 1);
411 return (0);
374 return (0);
412 } else {
413 if (_nderror < 0) {
414 trace1(TR_netdir_getbyaddr, 1);
415 return (_nderror);
416 }
417 }
375 }
376 if (_nderror < 0)
377 return (_nderror);
418 } else {
419 if (_nderror == ND_SYSTEM) { /* retry cache */
420 _nderror = ND_OK;
421 i--;
422 continue;
423 }
424 }
425 }
426 }
378 } else {
379 if (_nderror == ND_SYSTEM) { /* retry cache */
380 _nderror = ND_OK;
381 i--;
382 continue;
383 }
384 }
385 }
386 }
427 trace1(TR_netdir_getbyaddr, 1);
428 return (_nderror); /* No one works */
429}
430
431/*
432 * This is the library routine to do transport specific stuff.
433 * The code is same as the other similar routines except that it does
434 * not bother to try whole bunch of routines since if the first
435 * libray cannot resolve the option, then no one can.
436 *
437 * If it gets a netconfig structure for inet transports with nametoddr libs,
438 * it simply calls the inet-specific built in implementation.
439 */
440int
387 return (_nderror); /* No one works */
388}
389
390/*
391 * This is the library routine to do transport specific stuff.
392 * The code is same as the other similar routines except that it does
393 * not bother to try whole bunch of routines since if the first
394 * libray cannot resolve the option, then no one can.
395 *
396 * If it gets a netconfig structure for inet transports with nametoddr libs,
397 * it simply calls the inet-specific built in implementation.
398 */
399int
441netdir_options(tp, option, fd, par)
442 struct netconfig *tp; /* the netconfig entry */
443 int option; /* option number */
444 int fd; /* open file descriptor */
445 char *par; /* parameters if any */
400netdir_options(struct netconfig *tp, int option, int fd, char *par)
446{
447 struct translator *t; /* pointer to translator list */
448 char *lr; /* routines to try */
449 int i; /* counts the routines */
450
401{
402 struct translator *t; /* pointer to translator list */
403 char *lr; /* routines to try */
404 int i; /* counts the routines */
405
451 trace3(TR_netdir_options, 0, option, fd);
452 if (tp == 0) {
453 _nderror = ND_BADARG;
406 if (tp == 0) {
407 _nderror = ND_BADARG;
454 trace3(TR_netdir_options, 1, option, fd);
455 return (_nderror);
456 }
457
458 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
459 strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
460 (tp->nc_nlookups == 0)) {
408 return (_nderror);
409 }
410
411 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
412 strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
413 (tp->nc_nlookups == 0)) {
461 trace3(TR_netdir_options, 1, option, fd);
462 return (__inet_netdir_options(tp, option, fd, par));
463 }
464
465
466 for (i = 0; i < tp->nc_nlookups; i++) {
467 lr = *((tp->nc_lookups) + i);
468 for (t = xlate_list; t; t = t->next) {
414 return (__inet_netdir_options(tp, option, fd, par));
415 }
416
417
418 for (i = 0; i < tp->nc_nlookups; i++) {
419 lr = *((tp->nc_lookups) + i);
420 for (t = xlate_list; t; t = t->next) {
469 if (strcmp(lr, t->tr_name) == 0) {
470 trace3(TR_netdir_options, 1, option, fd);
421 if (strcmp(lr, t->tr_name) == 0)
471 return ((*(t->opt))(tp, option, fd, par));
422 return ((*(t->opt))(tp, option, fd, par));
472 }
473 }
474 /* If we didn't find it try loading it */
475 if (!t) {
476 if ((t = load_xlate(lr)) != NULL) {
477 /* add it to the list */
423 }
424 /* If we didn't find it try loading it */
425 if (!t) {
426 if ((t = load_xlate(lr)) != NULL) {
427 /* add it to the list */
478 mutex_lock(&xlate_lock);
428 (void) mutex_lock(&xlate_lock);
479 add_to_xlate_list(t);
429 add_to_xlate_list(t);
480 mutex_unlock(&xlate_lock);
481 trace3(TR_netdir_options, 1, option, fd);
430 (void) mutex_unlock(&xlate_lock);
482 return ((*(t->opt))(tp, option, fd, par));
431 return ((*(t->opt))(tp, option, fd, par));
483 } else {
484 if (_nderror == ND_SYSTEM) { /* retry cache */
485 _nderror = ND_OK;
486 i--;
487 continue;
488 }
489 }
432 }
433 if (_nderror == ND_SYSTEM) { /* retry cache */
434 _nderror = ND_OK;
435 i--;
436 continue;
437 }
490 }
491 }
438 }
439 }
492 trace3(TR_netdir_options, 1, option, fd);
493 return (_nderror); /* No one works */
494}
495
496/*
497 * This is the library routine for translating universal addresses to
498 * transport specific addresses. Again it uses the same code as above
499 * to search for the appropriate translation routine. Only it doesn't
500 * bother trying a whole bunch of routines since either the transport
501 * can translate it or it can't.
502 */
503struct netbuf *
440 return (_nderror); /* No one works */
441}
442
443/*
444 * This is the library routine for translating universal addresses to
445 * transport specific addresses. Again it uses the same code as above
446 * to search for the appropriate translation routine. Only it doesn't
447 * bother trying a whole bunch of routines since either the transport
448 * can translate it or it can't.
449 */
450struct netbuf *
504uaddr2taddr(tp, addr)
505 struct netconfig *tp; /* the netconfig entry */
506 char *addr; /* The address in question */
451uaddr2taddr(struct netconfig *tp, char *addr)
507{
508 struct translator *t; /* pointer to translator list */
509 struct netbuf *x; /* the answer we want */
510 char *lr; /* routines to try */
511 int i; /* counts the routines */
512
452{
453 struct translator *t; /* pointer to translator list */
454 struct netbuf *x; /* the answer we want */
455 char *lr; /* routines to try */
456 int i; /* counts the routines */
457
513 trace1(TR_uaddr2taddr, 0);
514 if (tp == 0) {
515 _nderror = ND_BADARG;
458 if (tp == 0) {
459 _nderror = ND_BADARG;
516 trace1(TR_uaddr2taddr, 1);
517 return (0);
518 }
519 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
520 strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
521 (tp->nc_nlookups == 0)) {
460 return (0);
461 }
462 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
463 strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
464 (tp->nc_nlookups == 0)) {
522 trace1(TR_uaddr2taddr, 1);
523 return (__inet_uaddr2taddr(tp, addr));
524 }
525 for (i = 0; i < tp->nc_nlookups; i++) {
526 lr = *((tp->nc_lookups) + i);
527 for (t = xlate_list; t; t = t->next) {
528 if (strcmp(lr, t->tr_name) == 0) {
529 x = (*(t->u2t))(tp, addr);
465 return (__inet_uaddr2taddr(tp, addr));
466 }
467 for (i = 0; i < tp->nc_nlookups; i++) {
468 lr = *((tp->nc_lookups) + i);
469 for (t = xlate_list; t; t = t->next) {
470 if (strcmp(lr, t->tr_name) == 0) {
471 x = (*(t->u2t))(tp, addr);
530 if (x) {
531 trace1(TR_uaddr2taddr, 1);
472 if (x)
532 return (x);
473 return (x);
533 }
534 if (_nderror < 0) {
535 trace1(TR_uaddr2taddr, 1);
474 if (_nderror < 0)
536 return (0);
475 return (0);
537 }
538 }
539 }
540 /* If we didn't find it try loading it */
541 if (!t) {
542 if ((t = load_xlate(lr)) != NULL) {
543 /* add it to the list */
476 }
477 }
478 /* If we didn't find it try loading it */
479 if (!t) {
480 if ((t = load_xlate(lr)) != NULL) {
481 /* add it to the list */
544 mutex_lock(&xlate_lock);
482 (void) mutex_lock(&xlate_lock);
545 add_to_xlate_list(t);
483 add_to_xlate_list(t);
546 mutex_unlock(&xlate_lock);
484 (void) mutex_unlock(&xlate_lock);
547 x = (*(t->u2t))(tp, addr);
485 x = (*(t->u2t))(tp, addr);
548 if (x) {
549 trace1(TR_uaddr2taddr, 1);
486 if (x)
550 return (x);
487 return (x);
551 }
552 if (_nderror < 0) {
553 trace1(TR_uaddr2taddr, 1);
488 if (_nderror < 0)
554 return (0);
489 return (0);
555 }
556 } else {
557 if (_nderror == ND_SYSTEM) { /* retry cache */
558 _nderror = ND_OK;
559 i--;
560 continue;
561 }
562 }
563 }
564 }
490 } else {
491 if (_nderror == ND_SYSTEM) { /* retry cache */
492 _nderror = ND_OK;
493 i--;
494 continue;
495 }
496 }
497 }
498 }
565 trace1(TR_uaddr2taddr, 1);
566 return (0); /* No one works */
567}
568
569/*
570 * This is the library routine for translating transport specific
571 * addresses to universal addresses. Again it uses the same code as above
572 * to search for the appropriate translation routine. Only it doesn't
573 * bother trying a whole bunch of routines since either the transport
574 * can translate it or it can't.
575 */
576char *
499 return (0); /* No one works */
500}
501
502/*
503 * This is the library routine for translating transport specific
504 * addresses to universal addresses. Again it uses the same code as above
505 * to search for the appropriate translation routine. Only it doesn't
506 * bother trying a whole bunch of routines since either the transport
507 * can translate it or it can't.
508 */
509char *
577taddr2uaddr(tp, addr)
578 struct netconfig *tp; /* the netconfig entry */
579 struct netbuf *addr; /* The address in question */
510taddr2uaddr(struct netconfig *tp, struct netbuf *addr)
580{
581 struct translator *t; /* pointer to translator list */
582 char *lr; /* routines to try */
583 char *x; /* the answer */
584 int i; /* counts the routines */
585
511{
512 struct translator *t; /* pointer to translator list */
513 char *lr; /* routines to try */
514 char *x; /* the answer */
515 int i; /* counts the routines */
516
586 trace1(TR_taddr2uaddr, 0);
587 if (tp == 0) {
588 _nderror = ND_BADARG;
517 if (tp == 0) {
518 _nderror = ND_BADARG;
589 trace1(TR_taddr2uaddr, 1);
590 return (0);
591 }
592 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
593 strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
594 (tp->nc_nlookups == 0)) {
519 return (0);
520 }
521 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
522 strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
523 (tp->nc_nlookups == 0)) {
595 trace1(TR_taddr2uaddr, 1);
596 return (__inet_taddr2uaddr(tp, addr));
597 }
598 for (i = 0; i < tp->nc_nlookups; i++) {
599 lr = *((tp->nc_lookups) + i);
600 for (t = xlate_list; t; t = t->next) {
601 if (strcmp(lr, t->tr_name) == 0) {
602 x = (*(t->t2u))(tp, addr);
524 return (__inet_taddr2uaddr(tp, addr));
525 }
526 for (i = 0; i < tp->nc_nlookups; i++) {
527 lr = *((tp->nc_lookups) + i);
528 for (t = xlate_list; t; t = t->next) {
529 if (strcmp(lr, t->tr_name) == 0) {
530 x = (*(t->t2u))(tp, addr);
603 if (x) {
604 trace1(TR_taddr2uaddr, 1);
531 if (x)
605 return (x);
532 return (x);
606 }
607 if (_nderror < 0) {
608 trace1(TR_taddr2uaddr, 1);
533 if (_nderror < 0)
609 return (0);
534 return (0);
610 }
611 }
612 }
613 /* If we didn't find it try loading it */
614 if (!t) {
615 if ((t = load_xlate(lr)) != NULL) {
616 /* add it to the list */
535 }
536 }
537 /* If we didn't find it try loading it */
538 if (!t) {
539 if ((t = load_xlate(lr)) != NULL) {
540 /* add it to the list */
617 mutex_lock(&xlate_lock);
541 (void) mutex_lock(&xlate_lock);
618 add_to_xlate_list(t);
542 add_to_xlate_list(t);
619 mutex_unlock(&xlate_lock);
543 (void) mutex_unlock(&xlate_lock);
620 x = (*(t->t2u))(tp, addr);
544 x = (*(t->t2u))(tp, addr);
621 if (x) {
622 trace1(TR_taddr2uaddr, 1);
545 if (x)
623 return (x);
546 return (x);
624 }
625 if (_nderror < 0) {
626 trace1(TR_taddr2uaddr, 1);
547 if (_nderror < 0)
627 return (0);
548 return (0);
628 }
629 } else {
630 if (_nderror == ND_SYSTEM) { /* retry cache */
631 _nderror = ND_OK;
632 i--;
633 continue;
634 }
635 }
636 }
637 }
549 } else {
550 if (_nderror == ND_SYSTEM) { /* retry cache */
551 _nderror = ND_OK;
552 i--;
553 continue;
554 }
555 }
556 }
557 }
638 trace1(TR_taddr2uaddr, 1);
639 return (0); /* No one works */
640}
641
642/*
643 * This is the routine that frees the objects that these routines allocate.
644 */
645void
558 return (0); /* No one works */
559}
560
561/*
562 * This is the routine that frees the objects that these routines allocate.
563 */
564void
646netdir_free(ptr, type)
647 void *ptr; /* generic pointer */
648 int type; /* thing we are freeing */
565netdir_free(void *ptr, int type)
649{
650 struct netbuf *na;
651 struct nd_addrlist *nas;
652 struct nd_hostserv *hs;
653 struct nd_hostservlist *hss;
654 int i;
655
566{
567 struct netbuf *na;
568 struct nd_addrlist *nas;
569 struct nd_hostserv *hs;
570 struct nd_hostservlist *hss;
571 int i;
572
656 trace2(TR_netdir_free, 0, type);
657 if (ptr == NULL) {
658 trace2(TR_netdir_free, 1, type);
573 if (ptr == NULL)
659 return;
574 return;
660 }
661 switch (type) {
662 case ND_ADDR :
663 na = (struct netbuf *)ptr;
664 if (na->buf)
665 free(na->buf);
575 switch (type) {
576 case ND_ADDR :
577 na = (struct netbuf *)ptr;
578 if (na->buf)
579 free(na->buf);
666 free((char *)na);
580 free(na);
667 break;
668
669 case ND_ADDRLIST :
670 nas = (struct nd_addrlist *)ptr;
671 /*
672 * XXX: We do NOT try to free all individual netbuf->buf
673 * pointers. Free only the first one since they are allocated
674 * using one calloc in
675 * libnsl/nss/netdir_inet.c:order_haddrlist().
676 * This potentially causes memory leaks if a nametoaddr
677 * implementation -- from a third party -- has a different
678 * allocation scheme.
679 */
680 if (nas->n_addrs->buf)
681 free(nas->n_addrs->buf);
581 break;
582
583 case ND_ADDRLIST :
584 nas = (struct nd_addrlist *)ptr;
585 /*
586 * XXX: We do NOT try to free all individual netbuf->buf
587 * pointers. Free only the first one since they are allocated
588 * using one calloc in
589 * libnsl/nss/netdir_inet.c:order_haddrlist().
590 * This potentially causes memory leaks if a nametoaddr
591 * implementation -- from a third party -- has a different
592 * allocation scheme.
593 */
594 if (nas->n_addrs->buf)
595 free(nas->n_addrs->buf);
682 free((char *)nas->n_addrs);
683 free((char *)nas);
596 free(nas->n_addrs);
597 free(nas);
684 break;
685
686 case ND_HOSTSERV :
687 hs = (struct nd_hostserv *)ptr;
688 if (hs->h_host)
689 free(hs->h_host);
690 if (hs->h_serv)
691 free(hs->h_serv);
598 break;
599
600 case ND_HOSTSERV :
601 hs = (struct nd_hostserv *)ptr;
602 if (hs->h_host)
603 free(hs->h_host);
604 if (hs->h_serv)
605 free(hs->h_serv);
692 free((char *)hs);
606 free(hs);
693 break;
694
695 case ND_HOSTSERVLIST :
696 hss = (struct nd_hostservlist *)ptr;
697 for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) {
698 if (hs->h_host)
699 free(hs->h_host);
700 if (hs->h_serv)
701 free(hs->h_serv);
702 }
607 break;
608
609 case ND_HOSTSERVLIST :
610 hss = (struct nd_hostservlist *)ptr;
611 for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) {
612 if (hs->h_host)
613 free(hs->h_host);
614 if (hs->h_serv)
615 free(hs->h_serv);
616 }
703 free((char *)hss->h_hostservs);
704 free((char *)hss);
617 free(hss->h_hostservs);
618 free(hss);
705 break;
706
707 default :
708 _nderror = ND_UKNWN;
709 break;
710 }
619 break;
620
621 default :
622 _nderror = ND_UKNWN;
623 break;
624 }
711 trace2(TR_netdir_free, 1, type);
712}
713
714/*
715 * load_xlate is a routine that will attempt to dynamically link in the
716 * file specified by the network configuration structure.
717 */
718static struct translator *
625}
626
627/*
628 * load_xlate is a routine that will attempt to dynamically link in the
629 * file specified by the network configuration structure.
630 */
631static struct translator *
719load_xlate(name)
720 char *name; /* file name to load */
632load_xlate(char *name)
721{
722 struct translator *t;
723 static struct xlate_list {
724 char *library;
725 struct xlate_list *next;
726 } *xlistp = NULL;
727 struct xlate_list *xlp, **xlastp;
728 static mutex_t xlist_lock = DEFAULTMUTEX;
729
633{
634 struct translator *t;
635 static struct xlate_list {
636 char *library;
637 struct xlate_list *next;
638 } *xlistp = NULL;
639 struct xlate_list *xlp, **xlastp;
640 static mutex_t xlist_lock = DEFAULTMUTEX;
641
730 trace1(TR_load_xlate, 0);
731 mutex_lock(&xlist_lock);
642 (void) mutex_lock(&xlist_lock);
732 /*
733 * We maintain a list of libraries we have loaded. Loading a library
734 * twice is double-plus ungood!
735 */
736 for (xlp = xlistp, xlastp = &xlistp; xlp != NULL;
737 xlastp = &xlp->next, xlp = xlp->next) {
738 if (xlp->library != NULL) {
739 if (strcmp(xlp->library, name) == 0) {
740 _nderror = ND_SYSTEM; /* seen this lib */
643 /*
644 * We maintain a list of libraries we have loaded. Loading a library
645 * twice is double-plus ungood!
646 */
647 for (xlp = xlistp, xlastp = &xlistp; xlp != NULL;
648 xlastp = &xlp->next, xlp = xlp->next) {
649 if (xlp->library != NULL) {
650 if (strcmp(xlp->library, name) == 0) {
651 _nderror = ND_SYSTEM; /* seen this lib */
741 mutex_unlock(&xlist_lock);
742 trace1(TR_load_xlate, 1);
652 (void) mutex_unlock(&xlist_lock);
743 return (0);
744 }
745 }
746 }
653 return (0);
654 }
655 }
656 }
747 t = (struct translator *)malloc(sizeof (struct translator));
657 t = malloc(sizeof (struct translator));
748 if (!t) {
749 _nderror = ND_NOMEM;
658 if (!t) {
659 _nderror = ND_NOMEM;
750 mutex_unlock(&xlist_lock);
751 trace1(TR_load_xlate, 1);
660 (void) mutex_unlock(&xlist_lock);
752 return (0);
753 }
754 t->tr_name = strdup(name);
755 if (!t->tr_name) {
756 _nderror = ND_NOMEM;
661 return (0);
662 }
663 t->tr_name = strdup(name);
664 if (!t->tr_name) {
665 _nderror = ND_NOMEM;
757 free((char *)t);
758 mutex_unlock(&xlist_lock);
759 trace1(TR_load_xlate, 1);
666 free(t);
667 (void) mutex_unlock(&xlist_lock);
760 return (NULL);
761 }
762
763 t->tr_fd = dlopen(name, RTLD_LAZY);
764 if (t->tr_fd == NULL) {
765 _nderror = ND_OPEN;
766 goto error;
767 }

--- 32 unchanged lines hidden (view full) ---

800 t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options");
801 if (!(t->opt)) {
802 _nderror = ND_NOSYM;
803 goto error;
804 }
805 /*
806 * Add this library to the list of loaded libraries.
807 */
668 return (NULL);
669 }
670
671 t->tr_fd = dlopen(name, RTLD_LAZY);
672 if (t->tr_fd == NULL) {
673 _nderror = ND_OPEN;
674 goto error;
675 }

--- 32 unchanged lines hidden (view full) ---

708 t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options");
709 if (!(t->opt)) {
710 _nderror = ND_NOSYM;
711 goto error;
712 }
713 /*
714 * Add this library to the list of loaded libraries.
715 */
808 *xlastp = (struct xlate_list *)malloc(sizeof (struct xlate_list));
716 *xlastp = malloc(sizeof (struct xlate_list));
809 if (*xlastp == NULL) {
810 _nderror = ND_NOMEM;
811 goto error;
812 }
813 (*xlastp)->library = strdup(name);
814 if ((*xlastp)->library == NULL) {
815 _nderror = ND_NOMEM;
816 free(*xlastp);
817 goto error;
818 }
819 (*xlastp)->next = NULL;
717 if (*xlastp == NULL) {
718 _nderror = ND_NOMEM;
719 goto error;
720 }
721 (*xlastp)->library = strdup(name);
722 if ((*xlastp)->library == NULL) {
723 _nderror = ND_NOMEM;
724 free(*xlastp);
725 goto error;
726 }
727 (*xlastp)->next = NULL;
820 mutex_unlock(&xlist_lock);
821 trace1(TR_load_xlate, 1);
728 (void) mutex_unlock(&xlist_lock);
822 return (t);
823error:
824 if (t->tr_fd != NULL)
825 (void) dlclose(t->tr_fd);
826 free(t->tr_name);
729 return (t);
730error:
731 if (t->tr_fd != NULL)
732 (void) dlclose(t->tr_fd);
733 free(t->tr_name);
827 free((char *)t);
828 mutex_unlock(&xlist_lock);
829 trace1(TR_load_xlate, 1);
734 free(t);
735 (void) mutex_unlock(&xlist_lock);
830 return (NULL);
831}
832
833
834#define NDERR_BUFSZ 512
835
836/*
837 * This is a routine that returns a string related to the current
838 * error in _nderror.
839 */
840char *
736 return (NULL);
737}
738
739
740#define NDERR_BUFSZ 512
741
742/*
743 * This is a routine that returns a string related to the current
744 * error in _nderror.
745 */
746char *
841netdir_sperror()
747netdir_sperror(void)
842{
843 static pthread_key_t nderrbuf_key = 0;
844 static char buf_main[NDERR_BUFSZ];
845 char *str;
846 char *dlerrstr;
847
748{
749 static pthread_key_t nderrbuf_key = 0;
750 static char buf_main[NDERR_BUFSZ];
751 char *str;
752 char *dlerrstr;
753
848 trace1(TR_netdir_sperror, 0);
849 str = thr_main()?
850 buf_main :
851 thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free);
754 str = thr_main()?
755 buf_main :
756 thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free);
852 if (str == NULL) {
853 trace1(TR_netdir_sperror, 1);
757 if (str == NULL)
854 return (NULL);
758 return (NULL);
855 }
856 dlerrstr = dlerror();
857 switch (_nderror) {
858 case ND_NOMEM :
859 (void) snprintf(str, NDERR_BUFSZ,
860 dgettext(__nsl_dom, "n2a: memory allocation failed"));
861 break;
862 case ND_OK :
863 (void) snprintf(str, NDERR_BUFSZ,

--- 46 unchanged lines hidden (view full) ---

910 dgettext(__nsl_dom, "n2a: system error"),
911 strerror(errno));
912 break;
913 default :
914 (void) snprintf(str, NDERR_BUFSZ, "%s#%d",
915 dgettext(__nsl_dom, "n2a: unknown error "), _nderror);
916 break;
917 }
759 dlerrstr = dlerror();
760 switch (_nderror) {
761 case ND_NOMEM :
762 (void) snprintf(str, NDERR_BUFSZ,
763 dgettext(__nsl_dom, "n2a: memory allocation failed"));
764 break;
765 case ND_OK :
766 (void) snprintf(str, NDERR_BUFSZ,

--- 46 unchanged lines hidden (view full) ---

813 dgettext(__nsl_dom, "n2a: system error"),
814 strerror(errno));
815 break;
816 default :
817 (void) snprintf(str, NDERR_BUFSZ, "%s#%d",
818 dgettext(__nsl_dom, "n2a: unknown error "), _nderror);
819 break;
820 }
918 trace1(TR_netdir_sperror, 1);
919 return (str);
920}
921
922/*
923 * This is a routine that prints out strings related to the current
924 * error in _nderror. Like perror() it takes a string to print with a
925 * colon first.
926 */
927void
821 return (str);
822}
823
824/*
825 * This is a routine that prints out strings related to the current
826 * error in _nderror. Like perror() it takes a string to print with a
827 * colon first.
828 */
829void
928netdir_perror(s)
929 char *s;
830netdir_perror(char *s)
930{
931 char *err;
932
831{
832 char *err;
833
933 trace1(TR_netdir_perror, 0);
934 err = netdir_sperror();
935 (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error");
834 err = netdir_sperror();
835 (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error");
936 trace1(TR_netdir_perror, 1);
937}
836}