|
|
1.10.4.2! jtc 1: /* $NetBSD: getcap.c,v 1.10.4.1 1996/09/16 18:40:22 jtc Exp $ */
1.9 cgd 2:
1.1 cgd 3: /*-
1.9 cgd 4: * Copyright (c) 1992, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software contributed to Berkeley by
8: * Casey Leedom of Lawrence Livermore National Laboratory.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: */
38:
39: #if defined(LIBC_SCCS) && !defined(lint)
1.9 cgd 40: #if 0
41: static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94";
42: #else
1.10.4.2! jtc 43: static char rcsid[] = "$NetBSD: getcap.c,v 1.10.4.1 1996/09/16 18:40:22 jtc Exp $";
1.9 cgd 44: #endif
1.1 cgd 45: #endif /* LIBC_SCCS and not lint */
46:
1.10.4.1 jtc 47: #include "namespace.h"
1.1 cgd 48: #include <sys/types.h>
49:
50: #include <ctype.h>
51: #include <db.h>
52: #include <errno.h>
53: #include <fcntl.h>
54: #include <limits.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
58: #include <unistd.h>
1.10.4.2! jtc 59:
! 60: #ifdef __weak_alias
! 61: __weak_alias(cgetcap,_cgetcap);
! 62: __weak_alias(cgetclose,_cgetclose);
! 63: __weak_alias(cgetent,_cgetent);
! 64: __weak_alias(cgetfirst,_cgetfirst);
! 65: __weak_alias(cgetmatch,_cgetmatch);
! 66: __weak_alias(cgetnext,_cgetnext);
! 67: __weak_alias(cgetnum,_cgetnum);
! 68: __weak_alias(cgetset,_cgetset);
! 69: __weak_alias(cgetstr,_cgetstr);
! 70: __weak_alias(cgetustr,_cgetustr);
! 71: #endif
1.1 cgd 72:
73: #define BFRAG 1024
74: #define BSIZE 1024
75: #define ESC ('[' & 037) /* ASCII ESC */
76: #define MAX_RECURSION 32 /* maximum getent recursion */
77: #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
78:
79: #define RECOK (char)0
80: #define TCERR (char)1
81: #define SHADOW (char)2
82:
83: static size_t topreclen; /* toprec length */
84: static char *toprec; /* Additional record specified by cgetset() */
85: static int gottoprec; /* Flag indicating retrieval of toprecord */
86:
87: static int cdbget __P((DB *, char **, char *));
88: static int getent __P((char **, u_int *, char **, int, char *, int, char *));
89: static int nfcmp __P((char *, char *));
90:
91: /*
92: * Cgetset() allows the addition of a user specified buffer to be added
93: * to the database array, in effect "pushing" the buffer on top of the
94: * virtual database. 0 is returned on success, -1 on failure.
95: */
96: int
97: cgetset(ent)
98: char *ent;
99: {
100: if (ent == NULL) {
101: if (toprec)
102: free(toprec);
103: toprec = NULL;
104: topreclen = 0;
105: return (0);
106: }
107: topreclen = strlen(ent);
108: if ((toprec = malloc (topreclen + 1)) == NULL) {
109: errno = ENOMEM;
110: return (-1);
111: }
112: gottoprec = 0;
113: (void)strcpy(toprec, ent);
114: return (0);
115: }
116:
117: /*
118: * Cgetcap searches the capability record buf for the capability cap with
119: * type `type'. A pointer to the value of cap is returned on success, NULL
120: * if the requested capability couldn't be found.
121: *
122: * Specifying a type of ':' means that nothing should follow cap (:cap:).
123: * In this case a pointer to the terminating ':' or NUL will be returned if
124: * cap is found.
125: *
126: * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
127: * return NULL.
128: */
129: char *
130: cgetcap(buf, cap, type)
131: char *buf, *cap;
132: int type;
133: {
134: register char *bp, *cp;
135:
136: bp = buf;
137: for (;;) {
138: /*
139: * Skip past the current capability field - it's either the
140: * name field if this is the first time through the loop, or
141: * the remainder of a field whose name failed to match cap.
142: */
143: for (;;)
144: if (*bp == '\0')
145: return (NULL);
146: else
147: if (*bp++ == ':')
148: break;
149:
150: /*
151: * Try to match (cap, type) in buf.
152: */
153: for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
154: continue;
155: if (*cp != '\0')
156: continue;
157: if (*bp == '@')
158: return (NULL);
159: if (type == ':') {
160: if (*bp != '\0' && *bp != ':')
161: continue;
162: return(bp);
163: }
164: if (*bp != type)
165: continue;
166: bp++;
167: return (*bp == '@' ? NULL : bp);
168: }
169: /* NOTREACHED */
170: }
171:
172: /*
173: * Cgetent extracts the capability record name from the NULL terminated file
174: * array db_array and returns a pointer to a malloc'd copy of it in buf.
175: * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
176: * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success,
177: * -1 if the requested record couldn't be found, -2 if a system error was
178: * encountered (couldn't open/read a file, etc.), and -3 if a potential
179: * reference loop is detected.
180: */
181: int
182: cgetent(buf, db_array, name)
183: char **buf, **db_array, *name;
184: {
185: u_int dummy;
186:
187: return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
188: }
189:
190: /*
191: * Getent implements the functions of cgetent. If fd is non-negative,
192: * *db_array has already been opened and fd is the open file descriptor. We
193: * do this to save time and avoid using up file descriptors for tc=
194: * recursions.
195: *
196: * Getent returns the same success/failure codes as cgetent. On success, a
197: * pointer to a malloc'ed capability record with all tc= capabilities fully
198: * expanded and its length (not including trailing ASCII NUL) are left in
199: * *cap and *len.
200: *
201: * Basic algorithm:
202: * + Allocate memory incrementally as needed in chunks of size BFRAG
203: * for capability buffer.
204: * + Recurse for each tc=name and interpolate result. Stop when all
205: * names interpolated, a name can't be found, or depth exceeds
206: * MAX_RECURSION.
207: */
208: static int
209: getent(cap, len, db_array, fd, name, depth, nfield)
210: char **cap, **db_array, *name, *nfield;
211: u_int *len;
212: int fd, depth;
213: {
214: DB *capdbp;
215: DBT key, data;
216: register char *r_end, *rp, **db_p;
1.7 cgd 217: int myfd, eof, foundit, retval, clen;
218: char *record, *cbuf;
1.1 cgd 219: int tc_not_resolved;
220: char pbuf[_POSIX_PATH_MAX];
221:
222: /*
223: * Return with ``loop detected'' error if we've recursed more than
224: * MAX_RECURSION times.
225: */
226: if (depth > MAX_RECURSION)
227: return (-3);
228:
229: /*
230: * Check if we have a top record from cgetset().
231: */
232: if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
233: if ((record = malloc (topreclen + BFRAG)) == NULL) {
234: errno = ENOMEM;
235: return (-2);
236: }
237: (void)strcpy(record, toprec);
238: myfd = 0;
239: db_p = db_array;
240: rp = record + topreclen + 1;
241: r_end = rp + BFRAG;
242: goto tc_exp;
243: }
244: /*
245: * Allocate first chunk of memory.
246: */
247: if ((record = malloc(BFRAG)) == NULL) {
248: errno = ENOMEM;
249: return (-2);
250: }
251: r_end = record + BFRAG;
252: foundit = 0;
253: /*
254: * Loop through database array until finding the record.
255: */
256:
257: for (db_p = db_array; *db_p != NULL; db_p++) {
258: eof = 0;
259:
260: /*
261: * Open database if not already open.
262: */
263:
264: if (fd >= 0) {
1.10.4.1 jtc 265: (void)lseek(fd, (off_t)0, SEEK_SET);
1.1 cgd 266: myfd = 0;
267: } else {
268: (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
269: if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
270: != NULL) {
271: free(record);
272: retval = cdbget(capdbp, &record, name);
1.8 cgd 273: if (retval < 0) {
274: /* no record available */
275: (void)capdbp->close(capdbp);
1.9 cgd 276: return (retval);
1.8 cgd 277: }
278: /* save the data; close frees it */
1.7 cgd 279: clen = strlen(record);
1.8 cgd 280: cbuf = malloc(clen + 1);
281: memcpy(cbuf, record, clen + 1);
1.7 cgd 282: if (capdbp->close(capdbp) < 0) {
283: free(cbuf);
284: return (-2);
285: }
286: *len = clen;
287: *cap = cbuf;
1.1 cgd 288: return (retval);
289: } else {
290: fd = open(*db_p, O_RDONLY, 0);
291: if (fd < 0) {
292: /* No error on unfound file. */
1.10 mycroft 293: continue;
1.1 cgd 294: }
295: myfd = 1;
296: }
297: }
298: /*
299: * Find the requested capability record ...
300: */
301: {
302: char buf[BUFSIZ];
303: register char *b_end, *bp;
304: register int c;
305:
306: /*
307: * Loop invariants:
308: * There is always room for one more character in record.
309: * R_end always points just past end of record.
310: * Rp always points just past last character in record.
311: * B_end always points just past last character in buf.
312: * Bp always points at next character in buf.
313: */
314: b_end = buf;
315: bp = buf;
316: for (;;) {
317:
318: /*
319: * Read in a line implementing (\, newline)
320: * line continuation.
321: */
322: rp = record;
323: for (;;) {
324: if (bp >= b_end) {
325: int n;
326:
327: n = read(fd, buf, sizeof(buf));
328: if (n <= 0) {
329: if (myfd)
330: (void)close(fd);
331: if (n < 0) {
332: free(record);
333: return (-2);
334: } else {
335: fd = -1;
336: eof = 1;
337: break;
338: }
339: }
340: b_end = buf+n;
341: bp = buf;
342: }
343:
344: c = *bp++;
345: if (c == '\n') {
346: if (rp > record && *(rp-1) == '\\') {
347: rp--;
348: continue;
349: } else
350: break;
351: }
352: *rp++ = c;
353:
354: /*
355: * Enforce loop invariant: if no room
356: * left in record buffer, try to get
357: * some more.
358: */
359: if (rp >= r_end) {
360: u_int pos;
361: size_t newsize;
362:
363: pos = rp - record;
364: newsize = r_end - record + BFRAG;
365: record = realloc(record, newsize);
366: if (record == NULL) {
367: errno = ENOMEM;
368: if (myfd)
369: (void)close(fd);
370: return (-2);
371: }
372: r_end = record + newsize;
373: rp = record + pos;
374: }
375: }
376: /* loop invariant let's us do this */
377: *rp++ = '\0';
378:
379: /*
380: * If encountered eof check next file.
381: */
382: if (eof)
383: break;
384:
385: /*
386: * Toss blank lines and comments.
387: */
388: if (*record == '\0' || *record == '#')
389: continue;
390:
391: /*
392: * See if this is the record we want ...
393: */
394: if (cgetmatch(record, name) == 0) {
395: if (nfield == NULL || !nfcmp(nfield, record)) {
396: foundit = 1;
397: break; /* found it! */
398: }
399: }
400: }
401: }
402: if (foundit)
403: break;
404: }
405:
406: if (!foundit)
407: return (-1);
408:
409: /*
410: * Got the capability record, but now we have to expand all tc=name
411: * references in it ...
412: */
413: tc_exp: {
414: register char *newicap, *s;
415: register int newilen;
416: u_int ilen;
417: int diff, iret, tclen;
418: char *icap, *scan, *tc, *tcstart, *tcend;
419:
420: /*
421: * Loop invariants:
422: * There is room for one more character in record.
423: * R_end points just past end of record.
424: * Rp points just past last character in record.
425: * Scan points at remainder of record that needs to be
426: * scanned for tc=name constructs.
427: */
428: scan = record;
429: tc_not_resolved = 0;
430: for (;;) {
431: if ((tc = cgetcap(scan, "tc", '=')) == NULL)
432: break;
433:
434: /*
435: * Find end of tc=name and stomp on the trailing `:'
436: * (if present) so we can use it to call ourselves.
437: */
438: s = tc;
439: for (;;)
440: if (*s == '\0')
441: break;
442: else
443: if (*s++ == ':') {
444: *(s - 1) = '\0';
445: break;
446: }
447: tcstart = tc - 3;
448: tclen = s - tcstart;
449: tcend = s;
450:
451: iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
452: NULL);
453: newicap = icap; /* Put into a register. */
454: newilen = ilen;
455: if (iret != 0) {
456: /* an error */
457: if (iret < -1) {
458: if (myfd)
459: (void)close(fd);
460: free(record);
461: return (iret);
462: }
463: if (iret == 1)
464: tc_not_resolved = 1;
465: /* couldn't resolve tc */
466: if (iret == -1) {
467: *(s - 1) = ':';
468: scan = s - 1;
469: tc_not_resolved = 1;
470: continue;
471:
472: }
473: }
474: /* not interested in name field of tc'ed record */
475: s = newicap;
476: for (;;)
477: if (*s == '\0')
478: break;
479: else
480: if (*s++ == ':')
481: break;
482: newilen -= s - newicap;
483: newicap = s;
484:
485: /* make sure interpolated record is `:'-terminated */
486: s += newilen;
487: if (*(s-1) != ':') {
488: *s = ':'; /* overwrite NUL with : */
489: newilen++;
490: }
491:
492: /*
493: * Make sure there's enough room to insert the
494: * new record.
495: */
496: diff = newilen - tclen;
497: if (diff >= r_end - rp) {
498: u_int pos, tcpos, tcposend;
499: size_t newsize;
500:
501: pos = rp - record;
502: newsize = r_end - record + diff + BFRAG;
503: tcpos = tcstart - record;
504: tcposend = tcend - record;
505: record = realloc(record, newsize);
506: if (record == NULL) {
507: errno = ENOMEM;
508: if (myfd)
509: (void)close(fd);
510: free(icap);
511: return (-2);
512: }
513: r_end = record + newsize;
514: rp = record + pos;
515: tcstart = record + tcpos;
516: tcend = record + tcposend;
517: }
518:
519: /*
520: * Insert tc'ed record into our record.
521: */
522: s = tcstart + newilen;
523: bcopy(tcend, s, rp - tcend);
524: bcopy(newicap, tcstart, newilen);
525: rp += diff;
526: free(icap);
527:
528: /*
529: * Start scan on `:' so next cgetcap works properly
530: * (cgetcap always skips first field).
531: */
532: scan = s-1;
533: }
534:
535: }
536: /*
537: * Close file (if we opened it), give back any extra memory, and
538: * return capability, length and success.
539: */
540: if (myfd)
541: (void)close(fd);
542: *len = rp - record - 1; /* don't count NUL */
543: if (r_end > rp)
544: if ((record =
545: realloc(record, (size_t)(rp - record))) == NULL) {
546: errno = ENOMEM;
547: return (-2);
548: }
549:
550: *cap = record;
551: if (tc_not_resolved)
552: return (1);
553: return (0);
554: }
555:
556: static int
557: cdbget(capdbp, bp, name)
558: DB *capdbp;
559: char **bp, *name;
560: {
561: DBT key, data;
562: char *buf;
563: int st;
564:
565: key.data = name;
566: key.size = strlen(name);
567:
568: for (;;) {
569: /* Get the reference. */
570: switch(capdbp->get(capdbp, &key, &data, 0)) {
571: case -1:
572: return (-2);
573: case 1:
574: return (-1);
575: }
576:
577: /* If not an index to another record, leave. */
578: if (((char *)data.data)[0] != SHADOW)
579: break;
580:
581: key.data = (char *)data.data + 1;
582: key.size = data.size - 1;
583: }
584:
585: *bp = (char *)data.data + 1;
586: return (((char *)(data.data))[0] == TCERR ? 1 : 0);
587: }
588:
589: /*
590: * Cgetmatch will return 0 if name is one of the names of the capability
591: * record buf, -1 if not.
592: */
593: int
594: cgetmatch(buf, name)
595: char *buf, *name;
596: {
597: register char *np, *bp;
598:
599: /*
600: * Start search at beginning of record.
601: */
602: bp = buf;
603: for (;;) {
604: /*
605: * Try to match a record name.
606: */
607: np = name;
608: for (;;)
609: if (*np == '\0')
610: if (*bp == '|' || *bp == ':' || *bp == '\0')
611: return (0);
612: else
613: break;
614: else
615: if (*bp++ != *np++)
616: break;
617:
618: /*
619: * Match failed, skip to next name in record.
620: */
621: bp--; /* a '|' or ':' may have stopped the match */
622: for (;;)
623: if (*bp == '\0' || *bp == ':')
624: return (-1); /* match failed totally */
625: else
626: if (*bp++ == '|')
627: break; /* found next name */
628: }
629: }
630:
631:
632:
633:
634:
635: int
636: cgetfirst(buf, db_array)
637: char **buf, **db_array;
638: {
639: (void)cgetclose();
640: return (cgetnext(buf, db_array));
641: }
642:
643: static FILE *pfp;
644: static int slash;
645: static char **dbp;
646:
647: int
648: cgetclose()
649: {
650: if (pfp != NULL) {
651: (void)fclose(pfp);
652: pfp = NULL;
653: }
654: dbp = NULL;
655: gottoprec = 0;
656: slash = 0;
657: return(0);
658: }
659:
660: /*
661: * Cgetnext() gets either the first or next entry in the logical database
662: * specified by db_array. It returns 0 upon completion of the database, 1
663: * upon returning an entry with more remaining, and -1 if an error occurs.
664: */
665: int
666: cgetnext(bp, db_array)
667: register char **bp;
668: char **db_array;
669: {
670: size_t len;
671: int status, i, done;
672: char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
673: u_int dummy;
674:
675: if (dbp == NULL)
676: dbp = db_array;
677:
678: if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
679: (void)cgetclose();
680: return (-1);
681: }
682: for(;;) {
683: if (toprec && !gottoprec) {
684: gottoprec = 1;
685: line = toprec;
686: } else {
1.6 cgd 687: line = fgetln(pfp, &len);
1.1 cgd 688: if (line == NULL && pfp) {
689: (void)fclose(pfp);
690: if (ferror(pfp)) {
691: (void)cgetclose();
692: return (-1);
693: } else {
694: if (*++dbp == NULL) {
695: (void)cgetclose();
696: return (0);
697: } else if ((pfp =
698: fopen(*dbp, "r")) == NULL) {
699: (void)cgetclose();
700: return (-1);
701: } else
702: continue;
703: }
1.5 cgd 704: } else
705: line[len - 1] = '\0';
706: if (len == 1) {
1.1 cgd 707: slash = 0;
708: continue;
709: }
710: if (isspace(*line) ||
711: *line == ':' || *line == '#' || slash) {
1.5 cgd 712: if (line[len - 2] == '\\')
1.1 cgd 713: slash = 1;
714: else
715: slash = 0;
716: continue;
717: }
1.5 cgd 718: if (line[len - 2] == '\\')
1.1 cgd 719: slash = 1;
720: else
721: slash = 0;
722: }
723:
724:
725: /*
726: * Line points to a name line.
727: */
728: i = 0;
729: done = 0;
730: np = nbuf;
731: for (;;) {
732: for (cp = line; *cp != '\0'; cp++) {
733: if (*cp == ':') {
734: *np++ = ':';
735: done = 1;
736: break;
737: }
738: if (*cp == '\\')
739: break;
740: *np++ = *cp;
741: }
742: if (done) {
743: *np = '\0';
744: break;
745: } else { /* name field extends beyond the line */
1.6 cgd 746: line = fgetln(pfp, &len);
1.1 cgd 747: if (line == NULL && pfp) {
748: (void)fclose(pfp);
749: if (ferror(pfp)) {
750: (void)cgetclose();
751: return (-1);
752: }
1.5 cgd 753: } else
754: line[len - 1] = '\0';
1.1 cgd 755: }
756: }
757: rp = buf;
758: for(cp = nbuf; *cp != NULL; cp++)
759: if (*cp == '|' || *cp == ':')
760: break;
761: else
762: *rp++ = *cp;
763:
764: *rp = '\0';
765: /*
766: * XXX
767: * Last argument of getent here should be nbuf if we want true
768: * sequential access in the case of duplicates.
769: * With NULL, getent will return the first entry found
770: * rather than the duplicate entry record. This is a
771: * matter of semantics that should be resolved.
772: */
773: status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
774: if (status == -2 || status == -3)
775: (void)cgetclose();
776:
777: return (status + 1);
778: }
779: /* NOTREACHED */
780: }
781:
782: /*
783: * Cgetstr retrieves the value of the string capability cap from the
784: * capability record pointed to by buf. A pointer to a decoded, NUL
785: * terminated, malloc'd copy of the string is returned in the char *
786: * pointed to by str. The length of the string not including the trailing
787: * NUL is returned on success, -1 if the requested string capability
788: * couldn't be found, -2 if a system error was encountered (storage
789: * allocation failure).
790: */
791: int
792: cgetstr(buf, cap, str)
793: char *buf, *cap;
794: char **str;
795: {
796: register u_int m_room;
797: register char *bp, *mp;
798: int len;
799: char *mem;
800:
801: /*
802: * Find string capability cap
803: */
804: bp = cgetcap(buf, cap, '=');
805: if (bp == NULL)
806: return (-1);
807:
808: /*
809: * Conversion / storage allocation loop ... Allocate memory in
810: * chunks SFRAG in size.
811: */
812: if ((mem = malloc(SFRAG)) == NULL) {
813: errno = ENOMEM;
814: return (-2); /* couldn't even allocate the first fragment */
815: }
816: m_room = SFRAG;
817: mp = mem;
818:
819: while (*bp != ':' && *bp != '\0') {
820: /*
821: * Loop invariants:
822: * There is always room for one more character in mem.
823: * Mp always points just past last character in mem.
824: * Bp always points at next character in buf.
825: */
826: if (*bp == '^') {
827: bp++;
828: if (*bp == ':' || *bp == '\0')
829: break; /* drop unfinished escape */
830: *mp++ = *bp++ & 037;
831: } else if (*bp == '\\') {
832: bp++;
833: if (*bp == ':' || *bp == '\0')
834: break; /* drop unfinished escape */
835: if ('0' <= *bp && *bp <= '7') {
836: register int n, i;
837:
838: n = 0;
839: i = 3; /* maximum of three octal digits */
840: do {
841: n = n * 8 + (*bp++ - '0');
842: } while (--i && '0' <= *bp && *bp <= '7');
843: *mp++ = n;
844: }
845: else switch (*bp++) {
846: case 'b': case 'B':
847: *mp++ = '\b';
848: break;
849: case 't': case 'T':
850: *mp++ = '\t';
851: break;
852: case 'n': case 'N':
853: *mp++ = '\n';
854: break;
855: case 'f': case 'F':
856: *mp++ = '\f';
857: break;
858: case 'r': case 'R':
859: *mp++ = '\r';
860: break;
861: case 'e': case 'E':
862: *mp++ = ESC;
863: break;
864: case 'c': case 'C':
865: *mp++ = ':';
866: break;
867: default:
868: /*
869: * Catches '\', '^', and
870: * everything else.
871: */
872: *mp++ = *(bp-1);
873: break;
874: }
875: } else
876: *mp++ = *bp++;
877: m_room--;
878:
879: /*
880: * Enforce loop invariant: if no room left in current
881: * buffer, try to get some more.
882: */
883: if (m_room == 0) {
884: size_t size = mp - mem;
885:
886: if ((mem = realloc(mem, size + SFRAG)) == NULL)
887: return (-2);
888: m_room = SFRAG;
889: mp = mem + size;
890: }
891: }
892: *mp++ = '\0'; /* loop invariant let's us do this */
893: m_room--;
894: len = mp - mem - 1;
895:
896: /*
897: * Give back any extra memory and return value and success.
898: */
899: if (m_room != 0)
900: if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
901: return (-2);
902: *str = mem;
903: return (len);
904: }
905:
906: /*
907: * Cgetustr retrieves the value of the string capability cap from the
908: * capability record pointed to by buf. The difference between cgetustr()
909: * and cgetstr() is that cgetustr does not decode escapes but rather treats
910: * all characters literally. A pointer to a NUL terminated malloc'd
911: * copy of the string is returned in the char pointed to by str. The
912: * length of the string not including the trailing NUL is returned on success,
913: * -1 if the requested string capability couldn't be found, -2 if a system
914: * error was encountered (storage allocation failure).
915: */
916: int
917: cgetustr(buf, cap, str)
918: char *buf, *cap, **str;
919: {
920: register u_int m_room;
921: register char *bp, *mp;
922: int len;
923: char *mem;
924:
925: /*
926: * Find string capability cap
927: */
928: if ((bp = cgetcap(buf, cap, '=')) == NULL)
929: return (-1);
930:
931: /*
932: * Conversion / storage allocation loop ... Allocate memory in
933: * chunks SFRAG in size.
934: */
935: if ((mem = malloc(SFRAG)) == NULL) {
936: errno = ENOMEM;
937: return (-2); /* couldn't even allocate the first fragment */
938: }
939: m_room = SFRAG;
940: mp = mem;
941:
942: while (*bp != ':' && *bp != '\0') {
943: /*
944: * Loop invariants:
945: * There is always room for one more character in mem.
946: * Mp always points just past last character in mem.
947: * Bp always points at next character in buf.
948: */
949: *mp++ = *bp++;
950: m_room--;
951:
952: /*
953: * Enforce loop invariant: if no room left in current
954: * buffer, try to get some more.
955: */
956: if (m_room == 0) {
957: size_t size = mp - mem;
958:
959: if ((mem = realloc(mem, size + SFRAG)) == NULL)
960: return (-2);
961: m_room = SFRAG;
962: mp = mem + size;
963: }
964: }
965: *mp++ = '\0'; /* loop invariant let's us do this */
966: m_room--;
967: len = mp - mem - 1;
968:
969: /*
970: * Give back any extra memory and return value and success.
971: */
972: if (m_room != 0)
973: if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
974: return (-2);
975: *str = mem;
976: return (len);
977: }
978:
979: /*
980: * Cgetnum retrieves the value of the numeric capability cap from the
981: * capability record pointed to by buf. The numeric value is returned in
982: * the long pointed to by num. 0 is returned on success, -1 if the requested
983: * numeric capability couldn't be found.
984: */
985: int
986: cgetnum(buf, cap, num)
987: char *buf, *cap;
988: long *num;
989: {
990: register long n;
991: register int base, digit;
992: register char *bp;
993:
994: /*
995: * Find numeric capability cap
996: */
997: bp = cgetcap(buf, cap, '#');
998: if (bp == NULL)
999: return (-1);
1000:
1001: /*
1002: * Look at value and determine numeric base:
1003: * 0x... or 0X... hexadecimal,
1004: * else 0... octal,
1005: * else decimal.
1006: */
1007: if (*bp == '0') {
1008: bp++;
1009: if (*bp == 'x' || *bp == 'X') {
1010: bp++;
1011: base = 16;
1012: } else
1013: base = 8;
1014: } else
1015: base = 10;
1016:
1017: /*
1018: * Conversion loop ...
1019: */
1020: n = 0;
1021: for (;;) {
1022: if ('0' <= *bp && *bp <= '9')
1023: digit = *bp - '0';
1024: else if ('a' <= *bp && *bp <= 'f')
1025: digit = 10 + *bp - 'a';
1026: else if ('A' <= *bp && *bp <= 'F')
1027: digit = 10 + *bp - 'A';
1028: else
1029: break;
1030:
1031: if (digit >= base)
1032: break;
1033:
1034: n = n * base + digit;
1035: bp++;
1036: }
1037:
1038: /*
1039: * Return value and success.
1040: */
1041: *num = n;
1042: return (0);
1043: }
1044:
1045:
1046: /*
1047: * Compare name field of record.
1048: */
1049: static int
1050: nfcmp(nf, rec)
1051: char *nf, *rec;
1052: {
1053: char *cp, tmp;
1054: int ret;
1055:
1056: for (cp = rec; *cp != ':'; cp++)
1057: ;
1058:
1059: tmp = *(cp + 1);
1060: *(cp + 1) = '\0';
1061: ret = strcmp(nf, rec);
1062: *(cp + 1) = tmp;
1063:
1064: return (ret);
1065: }