1/*
2 * misc.c - common miscellaneous functions for lsof
3 */
4
5
6/*
7 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
8 * 47907.  All rights reserved.
9 *
10 * Written by Victor A. Abell
11 *
12 * This software is not subject to any license of the American Telephone
13 * and Telegraph Company or the Regents of the University of California.
14 *
15 * Permission is granted to anyone to use this software for any purpose on
16 * any computer system, and to alter it and redistribute it freely, subject
17 * to the following restrictions:
18 *
19 * 1. Neither the authors nor Purdue University are responsible for any
20 *    consequences of the use of this software.
21 *
22 * 2. The origin of this software must not be misrepresented, either by
23 *    explicit claim or by omission.  Credit to the authors and Purdue
24 *    University must appear in documentation and sources.
25 *
26 * 3. Altered versions must be plainly marked as such, and must not be
27 *    misrepresented as being the original software.
28 *
29 * 4. This notice may not be removed or altered.
30 */
31
32#ifndef lint
33static char copyright[] =
34"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
35static char *rcsid = "$Id: misc.c,v 1.27 2013/01/02 17:14:59 abe Exp $";
36#endif
37
38
39#include "lsof.h"
40
41#if	defined(HASWIDECHAR)
42# if	defined(WIDECHARINCL)
43#include WIDECHARINCL
44# endif	/* defined(WIDECHARINCL) */
45# if	defined(HASWCTYPE_H)
46#include <wctype.h>
47# endif	/* defined(HASWCTYPE_H) */
48#endif	/* defined(HASWIDECHAR) */
49
50
51/*
52 * Local definitions
53 */
54
55#if	!defined(MAXSYMLINKS)
56#define	MAXSYMLINKS	32
57#endif	/* !defined(MAXSYMLINKS) */
58
59
60/*
61 * Local function prototypes
62 */
63
64_PROTOTYPE(static void closePipes,(void));
65_PROTOTYPE(static int dolstat,(char *path, char *buf, int len));
66_PROTOTYPE(static int dostat,(char *path, char *buf, int len));
67_PROTOTYPE(static int doreadlink,(char *path, char *buf, int len));
68_PROTOTYPE(static int doinchild,(int (*fn)(), char *fp, char *rbuf, int rbln));
69
70#if	defined(HASINTSIGNAL)
71_PROTOTYPE(static int handleint,(int sig));
72#else	/* !defined(HASINTSIGNAL) */
73_PROTOTYPE(static void handleint,(int sig));
74#endif	/* defined(HASINTSIGNAL) */
75
76_PROTOTYPE(static char *safepup,(unsigned int c, int *cl));
77
78
79/*
80 * Local variables
81 */
82
83static pid_t Cpid = 0;			/* child PID */
84static jmp_buf Jmp_buf;			/* jump buffer */
85static int Pipes[] =			/* pipes for child process */
86	{ -1, -1, -1, -1 };
87static int CtSigs[] = { 0, SIGINT, SIGKILL };
88					/* child termination signals (in order
89					 * of application) -- the first is a
90					 * dummy to allow pipe closure to
91					 * cause the child to exit */
92#define	NCTSIGS	(sizeof(CtSigs) / sizeof(int))
93
94
95#if	defined(HASNLIST)
96/*
97 * build-Nl() - build kernel name list table
98 */
99
100static struct drive_Nl *Build_Nl = (struct drive_Nl *)NULL;
101					/* the default Drive_Nl address */
102
103void
104build_Nl(d)
105	struct drive_Nl *d;		/* data to drive the construction */
106{
107	struct drive_Nl *dp;
108	int i, n;
109
110	for (dp = d, n = 0; dp->nn; dp++, n++)
111	    ;
112	if (n < 1) {
113	    (void) fprintf(stderr,
114		"%s: can't calculate kernel name list length\n", Pn);
115	    Exit(1);
116	}
117	if (!(Nl = (struct NLIST_TYPE *)calloc((n + 1),
118					       sizeof(struct NLIST_TYPE))))
119	{
120	    (void) fprintf(stderr,
121		"%s: can't allocate %d bytes to kernel name list structure\n",
122		Pn, (int)((n + 1) * sizeof(struct NLIST_TYPE)));
123	    Exit(1);
124	}
125	for (dp = d, i = 0; i < n; dp++, i++) {
126	    Nl[i].NL_NAME = dp->knm;
127	}
128	Nll = (int)((n + 1) * sizeof(struct NLIST_TYPE));
129	Build_Nl = d;
130}
131#endif	/* defined(HASNLIST) */
132
133
134/*
135 * childx() - make child process exit (if possible)
136 */
137
138void
139childx()
140{
141	static int at, sx;
142	pid_t wpid;
143
144	if (Cpid > 1) {
145
146	/*
147	 * First close the pipes to and from the child.  That should cause the
148	 * child to exit.  Compute alarm time shares.
149	 */
150	    (void) closePipes();
151	    if ((at = TmLimit / NCTSIGS) < TMLIMMIN)
152		at = TMLIMMIN;
153	/*
154	 * Loop, waiting for the child to exit.  After the first pass, help
155	 * the child exit by sending it signals.
156	 */
157	    for (sx = 0; sx < NCTSIGS; sx++) {
158		if (setjmp(Jmp_buf)) {
159
160		/*
161		 * An alarm has rung.  Disable further alarms.
162		 *
163		 * If there are more signals to send, continue the signal loop.
164		 *
165		 * If the last signal has been sent, issue a warning (unless
166		 * warninge have been suppressed) and exit the signal loop.
167		 */
168		    (void) alarm(0);
169		    (void) signal(SIGALRM, SIG_DFL);
170		    if (sx < (NCTSIGS - 1))
171			continue;
172		    if (!Fwarn)
173			(void) fprintf(stderr,
174			    "%s: WARNING -- child process %d may be hung.\n",
175			    Pn, (int)Cpid);
176		    break;
177	        }
178	    /*
179	     * Send the next signal to the child process, after the first pass
180	     * through the loop.
181	     *
182	     * Wrap the wait() with an alarm.
183	     */
184		if (sx)
185		    (void) kill(Cpid, CtSigs[sx]);
186		(void) signal(SIGALRM, handleint);
187		(void) alarm(at);
188		wpid = (pid_t) wait(NULL);
189		(void) alarm(0);
190		(void) signal(SIGALRM, SIG_DFL);
191		if (wpid == Cpid)
192		    break;
193	    }
194	    Cpid = 0;
195	}
196}
197
198
199/*
200 * closePipes() - close open pipe file descriptors
201 */
202
203static void
204closePipes()
205{
206	int i;
207
208	for (i = 0; i < 4; i++) {
209	    if (Pipes[i] >= 0) {
210		(void) close(Pipes[i]);
211		Pipes[i] = -1;
212	    }
213	}
214}
215
216
217/*
218 * compdev() - compare Devtp[] entries
219 */
220
221int
222compdev(a1, a2)
223	COMP_P *a1, *a2;
224{
225	struct l_dev **p1 = (struct l_dev **)a1;
226	struct l_dev **p2 = (struct l_dev **)a2;
227
228	if ((dev_t)((*p1)->rdev) < (dev_t)((*p2)->rdev))
229	    return(-1);
230	if ((dev_t)((*p1)->rdev) > (dev_t)((*p2)->rdev))
231	    return(1);
232	if ((INODETYPE)((*p1)->inode) < (INODETYPE)((*p2)->inode))
233	    return(-1);
234	if ((INODETYPE)((*p1)->inode) > (INODETYPE)((*p2)->inode))
235	    return(1);
236	return(strcmp((*p1)->name, (*p2)->name));
237}
238
239
240/*
241 * doinchild() -- do a function in a child process
242 */
243
244static int
245doinchild(fn, fp, rbuf, rbln)
246	int (*fn)();			/* function to perform */
247	char *fp;			/* function parameter */
248	char *rbuf;			/* response buffer */
249	int rbln;			/* response buffer length */
250{
251	int en, rv;
252/*
253 * Check reply buffer size.
254 */
255	if (!Fovhd && rbln > MAXPATHLEN) {
256	    (void) fprintf(stderr,
257		"%s: doinchild error; response buffer too large: %d\n",
258		Pn, rbln);
259	    Exit(1);
260	}
261/*
262 * Set up to handle an alarm signal; handle an alarm signal; build
263 * pipes for exchanging information with a child process; start the
264 * child process; and perform functions in the child process.
265 */
266	if (!Fovhd) {
267	    if (setjmp(Jmp_buf)) {
268
269	    /*
270	     * Process an alarm that has rung.
271	     */
272		(void) alarm(0);
273		(void) signal(SIGALRM, SIG_DFL);
274		(void) childx();
275		errno = ETIMEDOUT;
276		return(1);
277	    } else if (!Cpid) {
278
279	    /*
280	     * Create pipes to exchange function information with a child
281	     * process.
282	     */
283		if (pipe(Pipes) < 0 || pipe(&Pipes[2]) < 0) {
284		    (void) fprintf(stderr, "%s: can't open pipes: %s\n",
285			Pn, strerror(errno));
286		    Exit(1);
287		}
288	    /*
289	     * Fork a child to execute functions.
290	     */
291		if ((Cpid = fork()) == 0) {
292
293		/*
294		 * Begin the child process.
295		 */
296
297		    int fd, nd, r_al, r_rbln;
298		    char r_arg[MAXPATHLEN+1], r_rbuf[MAXPATHLEN+1];
299		    int (*r_fn)();
300		/*
301		 * Close all open file descriptors except Pipes[0] and
302		 * Pipes[3].
303		 */
304		    for (fd = 0, nd = GET_MAX_FD(); fd < nd; fd++) {
305			if (fd == Pipes[0] || fd == Pipes[3])
306			    continue;
307			(void) close(fd);
308			if (fd == Pipes[1])
309			    Pipes[1] = -1;
310			else if (fd == Pipes[2])
311			    Pipes[2] = -1;
312		    }
313		    if (Pipes[1] >= 0) {
314			(void) close(Pipes[1]);
315			Pipes[1] = -1;
316		    }
317		    if (Pipes[2] >= 0) {
318			(void) close(Pipes[2]);
319			Pipes[2] = -1;
320		    }
321		/*
322		 * Read function requests, process them, and return replies.
323		 */
324		    for (;;) {
325			if (read(Pipes[0], (char *)&r_fn, sizeof(r_fn))
326			    != (int)sizeof(r_fn)
327			||  read(Pipes[0], (char *)&r_al, sizeof(int))
328			    != (int)sizeof(int)
329			||  r_al < 1
330			||  r_al > (int)sizeof(r_arg)
331			||  read(Pipes[0], r_arg, r_al) != r_al
332			||  read(Pipes[0], (char *)&r_rbln, sizeof(r_rbln))
333			    != (int)sizeof(r_rbln)
334			||  r_rbln < 1 || r_rbln > (int)sizeof(r_rbuf))
335			    break;
336			rv = r_fn(r_arg, r_rbuf, r_rbln);
337			en = errno;
338			if (write(Pipes[3], (char *)&rv, sizeof(rv))
339			    != sizeof(rv)
340			||  write(Pipes[3], (char *)&en, sizeof(en))
341			    != sizeof(en)
342			||  write(Pipes[3], r_rbuf, r_rbln) != r_rbln)
343			    break;
344		    }
345		    (void) _exit(0);
346		}
347	    /*
348	     * Continue in the parent process to finish the setup.
349	     */
350		if (Cpid < 0) {
351		    (void) fprintf(stderr, "%s: can't fork: %s\n",
352			Pn, strerror(errno));
353		    Exit(1);
354		}
355		(void) close(Pipes[0]);
356		(void) close(Pipes[3]);
357		Pipes[0] = Pipes[3] = -1;
358	    }
359	}
360	if (!Fovhd) {
361	    int len;
362
363	/*
364	 * Send a function to the child and wait for the response.
365	 */
366	    len  = strlen(fp) + 1;
367	    (void) signal(SIGALRM, handleint);
368	    (void) alarm(TmLimit);
369	    if (write(Pipes[1], (char *)&fn, sizeof(fn)) != sizeof(fn)
370	    ||  write(Pipes[1], (char *)&len, sizeof(len)) != sizeof(len)
371	    ||  write(Pipes[1], fp, len) != len
372	    ||  write(Pipes[1], (char *)&rbln, sizeof(rbln)) != sizeof(rbln)
373	    ||  read(Pipes[2], (char *)&rv, sizeof(rv)) != sizeof(rv)
374	    ||  read(Pipes[2], (char *)&en, sizeof(en)) != sizeof(en)
375	    ||  read(Pipes[2], rbuf, rbln) != rbln) {
376		(void) alarm(0);
377		(void) signal(SIGALRM, SIG_DFL);
378		(void) childx();
379		errno = ECHILD;
380		return(-1);
381	    }
382	} else {
383
384	/*
385	 * Do the operation directly -- not in a child.
386	 */
387	    (void) signal(SIGALRM, handleint);
388	    (void) alarm(TmLimit);
389	    rv = fn(fp, rbuf, rbln);
390	    en = errno;
391	}
392/*
393 * Function completed, response collected -- complete the operation.
394 */
395	(void) alarm(0);
396	(void) signal(SIGALRM, SIG_DFL);
397	errno = en;
398	return(rv);
399}
400
401
402/*
403 * dolstat() - do an lstat() function
404 */
405
406static int
407dolstat(path, rbuf, rbln)
408	char *path;			/* path */
409	char *rbuf;			/* response buffer */
410	int rbln;			/* response buffer length */
411
412/* ARGSUSED */
413
414{
415	return(lstat(path, (struct stat *)rbuf));
416}
417
418
419/*
420 * doreadlink() -- do a readlink() function
421 */
422
423static int
424doreadlink(path, rbuf, rbln)
425	char *path;			/* path */
426	char *rbuf;			/* response buffer */
427	int rbln;			/* response buffer length */
428{
429	return(readlink(path, rbuf, rbln));
430}
431
432
433/*
434 * dostat() - do a stat() function
435 */
436
437static int
438dostat(path, rbuf, rbln)
439	char *path;			/* path */
440	char *rbuf;			/* response buffer */
441	int rbln;			/* response buffer length */
442
443/* ARGSUSED */
444
445{
446	return(stat(path, (struct stat *)rbuf));
447}
448
449
450#if	defined(WILLDROPGID)
451/*
452 * dropgid() - drop setgid permission
453 */
454
455void
456dropgid()
457{
458	if (!Setuidroot && Setgid) {
459	    if (setgid(Mygid) < 0) {
460		(void) fprintf(stderr, "%s: can't setgid(%d): %s\n",
461		    Pn, (int)Mygid, strerror(errno));
462		Exit(1);
463	    }
464	    Setgid = 0;
465	}
466}
467#endif	/* defined(WILLDROPGID) */
468
469
470/*
471 * enter_dev_ch() - enter device characters in file structure
472 */
473
474void
475enter_dev_ch(m)
476	char *m;
477{
478	char *mp;
479
480	if (!m || *m == '\0')
481	    return;
482	if (!(mp = mkstrcpy(m, (MALLOC_S *)NULL))) {
483	    (void) fprintf(stderr, "%s: no more dev_ch space at PID %d: \n",
484		Pn, Lp->pid);
485	    safestrprt(m, stderr, 1);
486	    Exit(1);
487	}
488	if (Lf->dev_ch)
489	   (void) free((FREE_P *)Lf->dev_ch);
490	Lf->dev_ch = mp;
491}
492
493
494/*
495 * enter_IPstate() -- enter a TCP or UDP state
496 */
497
498void
499enter_IPstate(ty, nm, nr)
500	char *ty;			/* type -- TCP or UDP */
501	char *nm;			/* state name (may be NULL) */
502	int nr;				/* state number */
503{
504
505#if	defined(USE_LIB_PRINT_TCPTPI)
506	TcpNstates = nr;
507#else	/* !defined(USE_LIB_PRINT_TCPTPI) */
508
509	int al, i, j, oc, nn, ns, off, tx;
510	char *cp;
511	MALLOC_S len;
512/*
513 * Check the type name and set the type index.
514 */
515	if (!ty) {
516	    (void) fprintf(stderr,
517		"%s: no type specified to enter_IPstate()\n", Pn);
518	    Exit(1);
519	}
520	if (!strcmp(ty, "TCP"))
521	    tx = 0;
522	else if (!strcmp(ty, "UDP"))
523	    tx = 1;
524	else {
525	    (void) fprintf(stderr, "%s: unknown type for enter_IPstate: %s\n",
526		Pn, ty);
527	    Exit(1);
528	}
529/*
530 * If the name argument is NULL, reduce the allocated table to its minimum
531 * size.
532 */
533	if (!nm) {
534	    if (tx) {
535		if (UdpSt) {
536		    if (!UdpNstates) {
537			(void) free((MALLOC_P *)UdpSt);
538			UdpSt = (char **)NULL;
539		    }
540		    if (UdpNstates < UdpStAlloc) {
541			len = (MALLOC_S)(UdpNstates * sizeof(char *));
542			if (!(UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len)))
543			{
544			    (void) fprintf(stderr,
545				"%s: can't reduce UdpSt[]\n", Pn);
546			    Exit(1);
547			}
548		    }
549		    UdpStAlloc = UdpNstates;
550		}
551	    } else {
552		if (TcpSt) {
553		    if (!TcpNstates) {
554			(void) free((MALLOC_P *)TcpSt);
555			TcpSt = (char **)NULL;
556		    }
557		    if (TcpNstates < TcpStAlloc) {
558			len = (MALLOC_S)(TcpNstates * sizeof(char *));
559			if (!(TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len)))
560			{
561			    (void) fprintf(stderr,
562				"%s: can't reduce TcpSt[]\n", Pn);
563			    Exit(1);
564			}
565		    }
566		    TcpStAlloc = TcpNstates;
567		}
568	    }
569	    return;
570	}
571/*
572 * Check the name and number.
573 */
574	if ((len = (size_t)strlen(nm)) < 1) {
575	    (void) fprintf(stderr,
576		"%s: bad %s name (\"%s\"), number=%d\n", Pn, ty, nm, nr);
577	    Exit(1);
578	}
579/*
580 * Make a copy of the name.
581 */
582	if (!(cp = mkstrcpy(nm, (MALLOC_S *)NULL))) {
583	    (void) fprintf(stderr,
584		"%s: enter_IPstate(): no %s space for %s\n",
585		Pn, ty, nm);
586	    Exit(1);
587	}
588/*
589 * Set the necessary offset for using nr as an index.  If it is
590 * a new offset, adjust previous entries.
591 */
592	if ((nr < 0) && ((off = -nr) > (tx ? UdpStOff : TcpStOff))) {
593	    if (tx ? UdpSt : TcpSt) {
594
595	    /*
596	     * A new, larger offset (smaller negative state number) could mean
597	     * a previously allocated state table must be enlarged and its
598	     * previous entries moved.
599	     */
600		oc = off - (tx ? UdpStOff : TcpStOff);
601		al = tx ? UdpStAlloc : TcpStAlloc;
602		ns = tx ? UdpNstates : TcpNstates;
603		if ((nn = ns + oc) >= al) {
604		    while ((nn + 5) > al) {
605			al += TCPUDPALLOC;
606		    }
607		    len = (MALLOC_S)(al * sizeof(char *));
608		    if (tx) {
609			if (!(UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len)))
610			    goto no_IP_space;
611			UdpStAlloc = al;
612		    } else {
613			if (!(TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len)))
614			    goto no_IP_space;
615			TcpStAlloc = al;
616		    }
617		    for (i = 0, j = oc; i < oc; i++, j++) {
618			if (tx) {
619			    if (i < UdpNstates)
620				UdpSt[j] = UdpSt[i];
621			    UdpSt[i] = (char *)NULL;
622			} else {
623			    if (i < TcpNstates)
624				TcpSt[j] = TcpSt[i];
625			    TcpSt[i] = (char *)NULL;
626			}
627		    }
628		    if (tx)
629			UdpNstates += oc;
630		    else
631			TcpNstates += oc;
632		}
633	    }
634	    if (tx)
635		UdpStOff = off;
636	    else
637		TcpStOff = off;
638	}
639/*
640 * Enter name as {Tc|Ud}pSt[nr + {Tc|Ud}pStOff].
641 *
642 * Allocate space, as required.
643 */
644	al = tx ? UdpStAlloc : TcpStAlloc;
645	off = tx ? UdpStOff : TcpStOff;
646	nn = nr + off + 1;
647	if (nn > al) {
648	    i = tx ? UdpNstates : TcpNstates;
649	    while ((nn + 5) > al) {
650		al += TCPUDPALLOC;
651	    }
652	    len = (MALLOC_S)(al * sizeof(char *));
653	    if (tx) {
654		if (UdpSt)
655		    UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len);
656		else
657		    UdpSt = (char **)malloc(len);
658		if (!UdpSt) {
659
660no_IP_space:
661
662		    (void) fprintf(stderr, "%s: no %s state space\n", Pn, ty);
663		    Exit(1);
664		}
665		UdpNstates = nn;
666		UdpStAlloc = al;
667	    } else {
668		if (TcpSt)
669		    TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len);
670		else
671		    TcpSt = (char **)malloc(len);
672		if (!TcpSt)
673		    goto no_IP_space;
674		TcpNstates = nn;
675		TcpStAlloc = al;
676	    }
677	    while (i < al) {
678		if (tx)
679		    UdpSt[i] = (char *)NULL;
680		else
681		    TcpSt[i] = (char *)NULL;
682		i++;
683	    }
684	} else {
685	    if (tx) {
686		if (nn > UdpNstates)
687		    UdpNstates = nn;
688	    } else {
689		if (nn > TcpNstates)
690		    TcpNstates = nn;
691	    }
692	}
693	if (tx) {
694	    if (UdpSt[nr + UdpStOff]) {
695
696dup_IP_state:
697
698		(void) fprintf(stderr,
699		    "%s: duplicate %s state %d (already %s): %s\n",
700		    Pn, ty, nr,
701		    tx ? UdpSt[nr + UdpStOff] : TcpSt[nr + TcpStOff],
702		    nm);
703	 	Exit(1);
704	    }
705	    UdpSt[nr + UdpStOff] = cp;
706	} else {
707	    if (TcpSt[nr + TcpStOff])
708		goto dup_IP_state;
709	    TcpSt[nr + TcpStOff] = cp;
710	}
711#endif	/* defined(USE_LIB_PRINT_TCPTPI) */
712
713}
714
715
716/*
717 * enter_nm() - enter name in local file structure
718 */
719
720void
721enter_nm(m)
722	char *m;
723{
724	char *mp;
725
726	if (!m || *m == '\0')
727	    return;
728	if (!(mp = mkstrcpy(m, (MALLOC_S *)NULL))) {
729	    (void) fprintf(stderr, "%s: no more nm space at PID %d for: ",
730		Pn, Lp->pid);
731	    safestrprt(m, stderr, 1);
732	    Exit(1);
733	}
734	if (Lf->nm)
735	    (void) free((FREE_P *)Lf->nm);
736	Lf->nm = mp;
737}
738
739
740/*
741 * Exit() - do a clean exit()
742 */
743
744void
745Exit(xv)
746	int xv;				/* exit() value */
747{
748	(void) childx();
749
750#if	defined(HASDCACHE)
751	if (DCrebuilt && !Fwarn)
752	    (void) fprintf(stderr, "%s: WARNING: %s was updated.\n",
753		Pn, DCpath[DCpathX]);
754#endif	/* defined(HASDCACHE) */
755
756	exit(xv);
757}
758
759
760#if	defined(HASNLIST)
761/*
762 * get_Nl_value() - get Nl value for nickname
763 */
764
765int
766get_Nl_value(nn, d, v)
767	char *nn;			/* nickname of requested entry */
768	struct drive_Nl *d;		/* drive_Nl table that built Nl
769					 * (if NULL, use Build_Nl) */
770	KA_T *v;			/* returned value (if NULL,
771					 * return nothing) */
772{
773	int i;
774
775	if (!Nl || !Nll)
776	    return(-1);
777	if (!d)
778	    d = Build_Nl;
779	for (i = 0; d->nn; d++, i++) {
780	    if (strcmp(d->nn, nn) == 0) {
781		if (v)
782		    *v = (KA_T)Nl[i].n_value;
783		return(i);
784	    }
785	}
786	return(-1);
787}
788#endif	/* defined(HASNLIST) */
789
790
791/*
792 * handleint() - handle an interrupt
793 */
794
795#if	defined(HASINTSIGNAL)
796static int
797#else
798static void
799#endif
800
801/* ARGSUSED */
802
803handleint(sig)
804	int sig;
805{
806	longjmp(Jmp_buf, 1);
807}
808
809
810/*
811 * hashbyname() - hash by name
812 */
813
814int
815hashbyname(nm, mod)
816	char *nm;			/* pointer to NUL-terminated name */
817	int mod;			/* hash modulus */
818{
819	int i, j;
820
821	for (i = j = 0; *nm; nm++) {
822	    i ^= (int)*nm << j;
823	    if (++j > 7)
824		j = 0;
825	}
826	return(((int)(i * 31415)) & (mod - 1));
827}
828
829
830/*
831 * is_nw_addr() - is this network address selected?
832 */
833
834int
835is_nw_addr(ia, p, af)
836	unsigned char *ia;		/* Internet address */
837	int p;				/* port */
838	int af;				/* address family -- e.g., AF_INET,
839					 * AF_INET6 */
840{
841	struct nwad *n;
842
843	if (!(n = Nwad))
844	    return(0);
845	for (; n; n = n->next) {
846	    if (n->proto) {
847		if (strcasecmp(n->proto, Lf->iproto) != 0)
848		    continue;
849	    }
850	    if (af && n->af && af != n->af)
851		continue;
852
853#if	defined(HASIPv6)
854	    if (af == AF_INET6) {
855		if (n->a[15] || n->a[14] || n->a[13] || n->a[12]
856		||  n->a[11] || n->a[10] || n->a[9]  || n->a[8]
857		||  n->a[7]  || n->a[6]  || n->a[5]  || n->a[4]
858		||  n->a[3]  || n->a[2]  || n->a[1]  || n->a[0]) {
859		    if (ia[15] != n->a[15] || ia[14] != n->a[14]
860		    ||  ia[13] != n->a[13] || ia[12] != n->a[12]
861		    ||  ia[11] != n->a[11] || ia[10] != n->a[10]
862		    ||  ia[9]  != n->a[9]  || ia[8]  != n->a[8]
863		    ||  ia[7]  != n->a[7]  || ia[6]  != n->a[6]
864		    ||  ia[5]  != n->a[5]  || ia[4]  != n->a[4]
865		    ||  ia[3]  != n->a[3]  || ia[2]  != n->a[2]
866		    ||  ia[1]  != n->a[1]  || ia[0]  != n->a[0])
867			continue;
868		}
869	    } else if (af == AF_INET)
870#endif	/* defined(HASIPv6) */
871
872	    {
873		if (n->a[3] || n->a[2] || n->a[1] || n->a[0]) {
874		    if (ia[3] != n->a[3] || ia[2] != n->a[2]
875		    ||  ia[1] != n->a[1] || ia[0] != n->a[0])
876			continue;
877		}
878	    }
879
880#if	defined(HASIPv6)
881	    else
882		continue;
883#endif	/* defined(HASIPv6) */
884
885	    if (n->sport == -1 || (p >= n->sport && p <= n->eport)) {
886		n->f = 1;
887		return(1);
888	    }
889	}
890	return(0);
891}
892
893
894/*
895 * mkstrcpy() - make a string copy in malloc()'d space
896 *
897 * return: copy pointer
898 *	   copy length (optional)
899 */
900
901char *
902mkstrcpy(src, rlp)
903	char *src;			/* source */
904	MALLOC_S *rlp;			/* returned length pointer (optional)
905					 * The returned length is an strlen()
906					 * equivalent */
907{
908	MALLOC_S len;
909	char *ns;
910
911	len = (MALLOC_S)(src ? strlen(src) : 0);
912	ns = (char *)malloc(len + 1);
913	if (ns) {
914	    if (src)
915		(void) snpf(ns, len + 1, "%s", src);
916	    else
917		*ns = '\0';
918	}
919	if (rlp)
920	    *rlp = len;
921	return(ns);
922}
923
924
925/*
926 * mkstrcat() - make a catenated copy of up to three strings under optional
927 *		string-by-string count control
928 *
929 * return: copy pointer
930 *	   copy string length (optional)
931 */
932
933char *
934mkstrcat(s1, l1, s2, l2, s3, l3, clp)
935	char *s1;			/* source string 1 */
936	int l1;				/* length of string 1 (-1 if none) */
937	char *s2;			/* source string 2 */
938	int l2;				/* length of string 2 (-1 if none) */
939	char *s3;			/* source string 3 (optional) */
940	int l3	;			/* length of string 3 (-1 if none) */
941	MALLOC_S *clp;			/* pointer to return of copy length
942					 * (optional) */
943{
944	MALLOC_S cl, len1, len2, len3;
945	char *cp;
946
947	if (s1)
948	    len1 = (MALLOC_S)((l1 >= 0) ? l1 : strlen(s1));
949	else
950	    len1 = (MALLOC_S)0;
951	if (s2)
952	    len2 = (MALLOC_S)((l2 >= 0) ? l2 : strlen(s2));
953	else
954	    len2 = (MALLOC_S)0;
955	if (s3)
956	    len3 = (MALLOC_S)((l3 >= 0) ? l3 : strlen(s3));
957	else
958	    len3 = (MALLOC_S)0;
959	cl = len1 + len2 + len3;
960	if ((cp = (char *)malloc(cl + 1))) {
961	    char *tp = cp;
962
963	    if (s1 && len1) {
964		(void) strncpy(tp, s1, len1);
965		tp += len1;
966	    }
967	    if (s2 && len2) {
968		(void) strncpy(tp, s2, len2);
969		tp += len2;
970	    }
971	    if (s3 && len3) {
972		(void) strncpy(tp, s3, len3);
973		tp += len3;
974	    }
975	    *tp = '\0';
976	}
977	if (clp)
978	    *clp = cl;
979	return(cp);
980}
981
982
983/*
984 * is_readable() -- is file readable
985 */
986
987int
988is_readable(path, msg)
989	char *path;			/* file path */
990	int msg;			/* issue warning message if 1 */
991{
992	if (access(path, R_OK) < 0) {
993	    if (!Fwarn && msg == 1)
994		(void) fprintf(stderr, ACCESSERRFMT, Pn, path, strerror(errno));
995	    return(0);
996	}
997	return(1);
998}
999
1000
1001/*
1002 * lstatsafely() - lstat path safely (i. e., with timeout)
1003 */
1004
1005int
1006lstatsafely(path, buf)
1007	char *path;			/* file path */
1008	struct stat *buf;		/* stat buffer address */
1009{
1010	if (Fblock) {
1011	    if (!Fwarn)
1012		(void) fprintf(stderr,
1013		    "%s: avoiding stat(%s): -b was specified.\n",
1014		    Pn, path);
1015	    errno = EWOULDBLOCK;
1016	    return(1);
1017	}
1018	return(doinchild(dolstat, path, (char *)buf, sizeof(struct stat)));
1019}
1020
1021
1022/*
1023 * Readlink() - read and interpret file system symbolic links
1024 */
1025
1026char *
1027Readlink(arg)
1028	char *arg;			/* argument to be interpreted */
1029{
1030	char abuf[MAXPATHLEN+1];
1031	int alen;
1032	char *ap;
1033	char *argp1, *argp2;
1034	int i, len, llen, slen;
1035	char lbuf[MAXPATHLEN+1];
1036	static char *op = (char *)NULL;
1037	static int ss = 0;
1038	char *s1;
1039	static char **stk = (char **)NULL;
1040	static int sx = 0;
1041	char tbuf[MAXPATHLEN+1];
1042/*
1043 * See if avoiding kernel blocks.
1044 */
1045	if (Fblock) {
1046	    if (!Fwarn) {
1047		(void) fprintf(stderr, "%s: avoiding readlink(", Pn);
1048		safestrprt(arg, stderr, 0);
1049		(void) fprintf(stderr, "): -b was specified.\n");
1050	    }
1051	    op = (char *)NULL;
1052	    return(arg);
1053	}
1054/*
1055 * Save the original path.
1056 */
1057	if (!op)
1058	    op = arg;
1059/*
1060 * Evaluate each component of the argument for a symbolic link.
1061 */
1062	for (alen = 0, ap = abuf, argp1 = argp2 = arg; *argp2; argp1 = argp2 ) {
1063	    for (argp2 = argp1 + 1; *argp2 && *argp2 != '/'; argp2++)
1064		;
1065	    if ((len = argp2 - arg) >= (int)sizeof(tbuf)) {
1066
1067path_too_long:
1068		if (!Fwarn) {
1069		    (void) fprintf(stderr,
1070			"%s: readlink() path too long: ", Pn);
1071		    safestrprt(op ? op : arg, stderr, 1);
1072		}
1073		op = (char *)NULL;
1074		return((char *)NULL);
1075	    }
1076	    (void) strncpy(tbuf, arg, len);
1077	    tbuf[len] = '\0';
1078	/*
1079	 * Dereference a symbolic link.
1080	 */
1081	    if ((llen=doinchild(doreadlink,tbuf,lbuf,sizeof(lbuf) - 1)) >= 0) {
1082
1083	    /*
1084	     * If the link is a new absolute path, replace
1085	     * the previous assembly with it.
1086	     */
1087		if (lbuf[0] == '/') {
1088		    (void) strncpy(abuf, lbuf, llen);
1089		    ap = &abuf[llen];
1090		    *ap = '\0';
1091		    alen = llen;
1092		    continue;
1093		}
1094		lbuf[llen] = '\0';
1095		s1 = lbuf;
1096	    } else {
1097		llen = argp2 - argp1;
1098		s1 = argp1;
1099	    }
1100	/*
1101	 * Make sure two components are separated by a `/'.
1102	 *
1103	 * If the first component is not a link, don't force
1104	 * a leading '/'.
1105	 *
1106	 * If the first component is a link and the source of
1107	 * the link has a leading '/', force a leading '/'.
1108	 */
1109	    if (*s1 == '/')
1110		slen = 1;
1111	    else {
1112		if (alen > 0) {
1113
1114		/*
1115		 * This is not the first component.
1116		 */
1117		    if (abuf[alen - 1] == '/')
1118			slen = 1;
1119		    else
1120			slen = 2;
1121		} else {
1122
1123		/*
1124		 * This is the first component.
1125		 */
1126		    if (s1 == lbuf && tbuf[0] == '/')
1127			slen = 2;
1128		    else
1129			slen = 1;
1130		}
1131	    }
1132	/*
1133	 * Add to the path assembly.
1134	 */
1135	    if ((alen + llen + slen) >= (int)sizeof(abuf))
1136		goto path_too_long;
1137	    if (slen == 2)
1138		*ap++ = '/';
1139	    (void) strncpy(ap, s1, llen);
1140	    ap += llen;
1141	    *ap = '\0';
1142	    alen += (llen + slen - 1);
1143	}
1144/*
1145 * If the assembled path and argument are the same, free all but the
1146 * last string in the stack, and return the argument.
1147 */
1148	if (strcmp(arg, abuf) == 0) {
1149	    for (i = 0; i < sx; i++) {
1150		if (i < (sx - 1))
1151		    (void) free((FREE_P *)stk[i]);
1152		stk[i] = (char *)NULL;
1153	    }
1154	    sx = 0;
1155	    op = (char *)NULL;
1156	    return(arg);
1157	}
1158/*
1159 * If the assembled path and argument are different, add it to the
1160 * string stack, then Readlink() it.
1161 */
1162	if (!(s1 = mkstrcpy(abuf, (MALLOC_S *)NULL))) {
1163
1164no_readlink_space:
1165
1166	    (void) fprintf(stderr, "%s: no Readlink string space for ", Pn);
1167	    safestrprt(abuf, stderr, 1);
1168	    Exit(1);
1169	}
1170	if (sx >= MAXSYMLINKS) {
1171
1172	/*
1173	 * If there are too many symbolic links, report an error, clear
1174	 * the stack, and return no path.
1175	 */
1176	    if (!Fwarn) {
1177		(void) fprintf(stderr,
1178		    "%s: too many (> %d) symbolic links in readlink() path: ",
1179			Pn, MAXSYMLINKS);
1180		safestrprt(op ? op : arg, stderr, 1);
1181	    }
1182	    for (i = 0; i < sx; i++) {
1183		(void) free((FREE_P *)stk[i]);
1184		stk[i] = (char *)NULL;
1185	    }
1186	    (void) free((FREE_P *)stk);
1187	    stk = (char **)NULL;
1188	    ss = sx = 0;
1189	    op = (char *)NULL;
1190	    return((char *)NULL);
1191	}
1192	if (++sx > ss) {
1193	    if (!stk)
1194		stk = (char **)malloc((MALLOC_S)(sizeof(char *) * sx));
1195	    else
1196		stk = (char **)realloc((MALLOC_P *)stk,
1197					(MALLOC_S)(sizeof(char *) * sx));
1198	    if (!stk)
1199		goto no_readlink_space;
1200	    ss = sx;
1201	}
1202	stk[sx - 1] = s1;
1203	return(Readlink(s1));
1204}
1205
1206
1207#if	defined(HASSTREAMS)
1208/*
1209 * readstdata() - read stream's stdata structure
1210 */
1211
1212int
1213readstdata(addr, buf)
1214	KA_T addr;			/* stdata address in kernel*/
1215	struct stdata *buf;		/* buffer addess */
1216{
1217	if (!addr
1218	||  kread(addr, (char *)buf, sizeof(struct stdata))) {
1219	    (void) snpf(Namech, Namechl, "no stream data in %s",
1220		print_kptr(addr, (char *)NULL, 0));
1221	    return(1);
1222	}
1223	return(0);
1224}
1225
1226
1227/*
1228 * readsthead() - read stream head
1229 */
1230
1231int
1232readsthead(addr, buf)
1233	KA_T addr;			/* starting queue pointer in kernel */
1234	struct queue *buf;		/* buffer for queue head */
1235{
1236	KA_T qp;
1237
1238	if (!addr) {
1239	    (void) snpf(Namech, Namechl, "no stream queue head");
1240	    return(1);
1241	}
1242	for (qp = addr; qp; qp = (KA_T)buf->q_next) {
1243	    if (kread(qp, (char *)buf, sizeof(struct queue))) {
1244		(void) snpf(Namech, Namechl, "bad stream queue link at %s",
1245		    print_kptr(qp, (char *)NULL, 0));
1246		return(1);
1247	    }
1248	}
1249	return(0);
1250}
1251
1252
1253/*
1254 * readstidnm() - read stream module ID name
1255 */
1256
1257int
1258readstidnm(addr, buf, len)
1259	KA_T addr;			/* module ID name address in kernel */
1260	char *buf;			/* receiving buffer address */
1261	READLEN_T len;			/* buffer length */
1262{
1263	if (!addr || kread(addr, buf, len)) {
1264	    (void) snpf(Namech, Namechl, "can't read module ID name from %s",
1265		print_kptr(addr, (char *)NULL, 0));
1266	    return(1);
1267	}
1268	return(0);
1269}
1270
1271
1272/*
1273 * readstmin() - read stream's module info
1274 */
1275
1276int
1277readstmin(addr, buf)
1278	KA_T addr;			/* module info address in kernel */
1279	struct module_info *buf;	/* receiving buffer address */
1280{
1281	if (!addr || kread(addr, (char *)buf, sizeof(struct module_info))) {
1282	    (void) snpf(Namech, Namechl, "can't read module info from %s",
1283		print_kptr(addr, (char *)NULL, 0));
1284	    return(1);
1285	}
1286	return(0);
1287}
1288
1289
1290/*
1291 * readstqinit() - read stream's queue information structure
1292 */
1293
1294int
1295readstqinit(addr, buf)
1296	KA_T addr;			/* queue info address in kernel */
1297	struct qinit *buf;		/* receiving buffer address */
1298{
1299	if (!addr || kread(addr, (char *)buf, sizeof(struct qinit))) {
1300	    (void) snpf(Namech, Namechl, "can't read queue info from %s",
1301		print_kptr(addr, (char *)NULL, 0));
1302	    return(1);
1303	}
1304	return(0);
1305}
1306#endif	/* HASSTREAMS */
1307
1308
1309/*
1310 * safepup() - safely print an unprintable character -- i.e., print it in a
1311 *	       printable form
1312 *
1313 * return: char * to printable equivalent
1314 *	   cl = strlen(printable equivalent)
1315 */
1316
1317static char *
1318safepup(c, cl)
1319	unsigned int c;			/* unprintable (i.e., !isprint())
1320					 * character */
1321	int *cl;			/* returned printable strlen -- NULL if
1322					 * no return needed */
1323{
1324	int len;
1325	char *rp;
1326	static char up[8];
1327
1328	if (c < 0x20) {
1329	    switch (c) {
1330	    case '\b':
1331		rp = "\\b";
1332		break;
1333	    case '\f':
1334		rp = "\\f";
1335		break;
1336	    case '\n':
1337		rp = "\\n";
1338		break;
1339	    case '\r':
1340		rp = "\\r";
1341		break;
1342	    case '\t':
1343		rp = "\\t";
1344		break;
1345	    default:
1346		(void) snpf(up, sizeof(up), "^%c", c + 0x40);
1347		rp = up;
1348	    }
1349	    len = 2;
1350	} else if (c == 0xff) {
1351	    rp = "^?";
1352	    len = 2;
1353	} else {
1354	    (void) snpf(up, sizeof(up), "\\x%02x", (int)(c & 0xff));
1355	    rp = up;
1356	    len = 4;
1357	}
1358	if (cl)
1359	    *cl = len;
1360	return(rp);
1361}
1362
1363
1364/*
1365 * safestrlen() - calculate a "safe" string length -- i.e., compute space for
1366 *		  non-printable characters when printed in a printable form
1367 */
1368
1369int
1370safestrlen(sp, flags)
1371	char *sp;			/* string pointer */
1372	int flags;			/* flags:
1373					 *   bit 0: 0 (0) = no NL
1374					 *	    1 (1) = add trailing NL
1375					 *	 1: 0 (0) = ' ' printable
1376					 *	    1 (2) = ' ' not printable
1377					 */
1378{
1379	char c;
1380	int len = 0;
1381
1382	c = (flags & 2) ? ' ' : '\0';
1383	if (sp) {
1384	    for (; *sp; sp++) {
1385		if (!isprint((unsigned char)*sp) || *sp == c) {
1386		    if (*sp < 0x20 || (unsigned char)*sp == 0xff)
1387			len += 2;		/* length of \. or ^. form */
1388		    else
1389			len += 4;		/* length of "\x%02x" printf */
1390		} else
1391		    len++;
1392	    }
1393	}
1394	return(len);
1395}
1396
1397
1398/*
1399 * safestrprt() - print a string "safely" to the indicated stream -- i.e.,
1400 *		  print unprintable characters in a printable form
1401 */
1402
1403void
1404safestrprt(sp, fs, flags)
1405	char *sp;			/* string to print pointer pointer */
1406	FILE *fs;			/* destination stream -- e.g., stderr
1407					 * or stdout */
1408	int flags;			/* flags:
1409					 *   bit 0: 0 (0) = no NL
1410					 *	    1 (1) = add trailing NL
1411					 *	 1: 0 (0) = ' ' printable
1412					 *	    1 (2) = ' ' not printable
1413					 *	 2: 0 (0) = print string as is
1414					 *	    1 (4) = surround string
1415					 *		    with '"'
1416					 *	 4: 0 (0) = print ending '\n'
1417					 *	    1 (8) = don't print ending
1418					 *		    '\n'
1419					 */
1420{
1421	char c;
1422	int lnc, lnt, sl;
1423
1424#if	defined(HASWIDECHAR)
1425	wchar_t w;
1426	int wcmx = MB_CUR_MAX;
1427#else	/* !defined(HASWIDECHAR) */
1428	static int wcmx = 1;
1429#endif	/* defined(HASWIDECHAR) */
1430
1431	c = (flags & 2) ? ' ' : '\0';
1432	if (flags & 4)
1433	    putc('"', fs);
1434	if (sp) {
1435	    for (sl = strlen(sp); *sp; sl -= lnc, sp += lnc) {
1436
1437#if	defined(HASWIDECHAR)
1438		if (wcmx > 1) {
1439		    lnc = mblen(sp, sl);
1440		    if (lnc > 1) {
1441			if ((mbtowc(&w, sp, sl) == lnc) && iswprint(w)) {
1442			    for (lnt = 0; lnt < lnc; lnt++) {
1443				putc((int)*(sp + lnt), fs);
1444			    }
1445			} else {
1446			    for (lnt = 0; lnt < lnc; lnt++) {
1447			        fputs(safepup((unsigned int)*(sp + lnt),
1448					      (int *)NULL), fs);
1449			    }
1450			}
1451			continue;
1452		    } else
1453			lnc = 1;
1454		} else
1455		    lnc = 1;
1456#else	/* !defined(HASWIDECHAR) */
1457		lnc = 1;
1458#endif	/* defined(HASWIDECHAR) */
1459
1460		if (isprint((unsigned char)*sp) && *sp != c)
1461		    putc((int)(*sp & 0xff), fs);
1462		else {
1463		    if ((flags & 8) && (*sp == '\n') && !*(sp + 1))
1464			break;
1465		    fputs(safepup((unsigned int)*sp, (int *)NULL), fs);
1466		}
1467	    }
1468	}
1469	if (flags & 4)
1470	    putc('"', fs);
1471	if (flags & 1)
1472	    putc('\n', fs);
1473}
1474
1475
1476/*
1477 * safestrprtn() - print a specified number of characters from a string
1478 *		   "safely" to the indicated stream
1479 */
1480
1481void
1482safestrprtn(sp, len, fs, flags)
1483	char *sp;			/* string to print pointer pointer */
1484	int len;			/* safe number of characters to
1485					 * print */
1486	FILE *fs;			/* destination stream -- e.g., stderr
1487					 * or stdout */
1488	int flags;			/* flags:
1489					 *   bit 0: 0 (0) = no NL
1490					 *	    1 (1) = add trailing NL
1491					 *	 1: 0 (0) = ' ' printable
1492					 *	    1 (2) = ' ' not printable
1493					 *	 2: 0 (0) = print string as is
1494					 *	    1 (4) = surround string
1495					 *		    with '"'
1496					 *	 4: 0 (0) = print ending '\n'
1497					 *	    1 (8) = don't print ending
1498					 *		    '\n'
1499					 */
1500{
1501	char c, *up;
1502	int cl, i;
1503
1504	if (flags & 4)
1505	    putc('"', fs);
1506	if (sp) {
1507	    c = (flags & 2) ? ' ' : '\0';
1508	    for (i = 0; i < len && *sp; sp++) {
1509		if (isprint((unsigned char)*sp) && *sp != c) {
1510		    putc((int)(*sp & 0xff), fs);
1511		    i++;
1512		} else {
1513		    if ((flags & 8) && (*sp == '\n') && !*(sp + 1))
1514			break;
1515		    up = safepup((unsigned int)*sp, &cl);
1516		    if ((i + cl) > len)
1517			break;
1518		    fputs(up, fs);
1519		    i += cl;
1520		}
1521	    }
1522	} else
1523	    i = 0;
1524	for (; i < len; i++)
1525	    putc(' ', fs);
1526	if (flags & 4)
1527	    putc('"', fs);
1528	if (flags & 1)
1529	    putc('\n', fs);
1530}
1531
1532
1533/*
1534 * statsafely() - stat path safely (i. e., with timeout)
1535 */
1536
1537int
1538statsafely(path, buf)
1539	char *path;			/* file path */
1540	struct stat *buf;		/* stat buffer address */
1541{
1542	if (Fblock) {
1543	    if (!Fwarn)
1544		(void) fprintf(stderr,
1545		    "%s: avoiding stat(%s): -b was specified.\n",
1546		    Pn, path);
1547	    errno = EWOULDBLOCK;
1548	    return(1);
1549	}
1550	return(doinchild(dostat, path, (char *)buf, sizeof(struct stat)));
1551}
1552
1553
1554/*
1555 * stkdir() - stack directory name
1556 */
1557
1558void
1559stkdir(p)
1560	char *p;		/* directory path */
1561{
1562	MALLOC_S len;
1563/*
1564 * Provide adequate space for directory stack pointers.
1565 */
1566	if (Dstkx >= Dstkn) {
1567	    Dstkn += 128;
1568	    len = (MALLOC_S)(Dstkn * sizeof(char *));
1569	    if (!Dstk)
1570		Dstk = (char **)malloc(len);
1571	    else
1572		Dstk = (char **)realloc((MALLOC_P *)Dstk, len);
1573	    if (!Dstk) {
1574		(void) fprintf(stderr,
1575		    "%s: no space for directory stack at: ", Pn);
1576		safestrprt(p, stderr, 1);
1577		Exit(1);
1578	    }
1579	}
1580/*
1581 * Allocate space for the name, copy it there and put its pointer on the stack.
1582 */
1583	if (!(Dstk[Dstkx] = mkstrcpy(p, (MALLOC_S *)NULL))) {
1584	    (void) fprintf(stderr, "%s: no space for: ", Pn);
1585	    safestrprt(p, stderr, 1);
1586	    Exit(1);
1587	}
1588	Dstkx++;
1589}
1590
1591
1592/*
1593 * x2dev() - convert hexadecimal ASCII string to device number
1594 */
1595
1596char *
1597x2dev(s, d)
1598	char *s;			/* ASCII string */
1599	dev_t *d;			/* device receptacle */
1600{
1601	char *cp, *cp1;
1602	int n;
1603	dev_t r;
1604
1605/*
1606 * Skip an optional leading 0x.  Count the number of hex digits up to the end
1607 * of the string, or to a space, or to a comma.  Return an error if an unknown
1608 * character is encountered.  If the count is larger than (2 * sizeof(dev_t))
1609 * -- e.g., because of sign extension -- ignore excess leading hex 0xf digits,
1610 * but return an error if an excess leading digit isn't 0xf.
1611 */
1612	if  (strncasecmp(s, "0x", 2) == 0)
1613		s += 2;
1614	for (cp = s, n = 0; *cp; cp++, n++) {
1615	    if (isdigit((unsigned char)*cp))
1616		continue;
1617	    if ((unsigned char)*cp >= 'a' && (unsigned char)*cp <= 'f')
1618		continue;
1619	    if ((unsigned char)*cp >= 'A' && (unsigned char)*cp <= 'F')
1620		continue;
1621	    if (*cp == ' ' || *cp == ',')
1622		break;
1623	    return((char *)NULL);
1624	}
1625	if (!n)
1626	    return((char *)NULL);
1627	if (n > (2 * (int)sizeof(dev_t))) {
1628	    cp1 = s;
1629	    s += (n - (2 * sizeof(dev_t)));
1630	    while (cp1 < s) {
1631		if (*cp1 != 'f' && *cp1 != 'F')
1632		    return((char *)NULL);
1633		cp1++;
1634	    }
1635	}
1636/*
1637 * Assemble the validated hex digits of the device number, starting at a point
1638 * in the string relevant to sizeof(dev_t).
1639 */
1640	for (r = 0; s < cp; s++) {
1641	    r = r << 4;
1642	    if (isdigit((unsigned char)*s))
1643		r |= (unsigned char)(*s - '0') & 0xf;
1644	    else {
1645		if (isupper((unsigned char)*s))
1646		    r |= ((unsigned char)(*s - 'A') + 10) & 0xf;
1647		else
1648		    r |= ((unsigned char)(*s - 'a') + 10) & 0xf;
1649	    }
1650	}
1651	*d = r;
1652	return(s);
1653}
1654