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