/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /*LINTLIBRARY*/ #ident "@(#)srchcfile.c 1.12 93/03/10 SMI" /* SVr4.0 1.7.1.1 */ #include #include #include #include #include #include #include #include #include "pkglocale.h" #define ERROR(s) \ { \ errstr = pkg_gt(s); \ (void) getend(fpin); \ return (-1); \ } static int eatwhite(FILE *fp); static int getend(FILE *fp); static int getnum(FILE *fp, int base, long *d, long bad); static int getstr(FILE *fp, char *sep, int n, char *str); static char mypath[PATH_MAX]; static char mylocal[PATH_MAX]; int srchcfile(struct cfent *ept, char *path, FILE *fpin, FILE *fpout) { struct pinfo *pinfo, *lastpinfo; long pos; char *pt, pkgname[PKGSIZ+1], classname[CLSSIZ+1]; int c, n, rdpath, anypath; /* * this code uses goto's instead of nested subroutines because * execution time of this routine is especially critical to * installation */ errstr = NULL; ept->volno = 0; ept->ftype = BADFTYPE; (void) strcpy(ept->pkg_class, BADCLASS); ept->pkg_class_idx = -1; ept->path = NULL; ept->ainfo.local = NULL; ept->ainfo.mode = BADMODE; (void) strcpy(ept->ainfo.owner, BADOWNER); (void) strcpy(ept->ainfo.group, BADGROUP); ept->cinfo.size = ept->cinfo.cksum = ept->cinfo.modtime = BADCONT; /* free up list of packages which reference this entry */ while (ept->pinfo) { pinfo = ept->pinfo->next; free(ept->pinfo); ept->pinfo = pinfo; } ept->pinfo = NULL; ept->npkgs = 0; /* * if path to search for is "*", then we will return the first path * we encounter as a match, otherwise we return an error */ anypath = 0; if (path && (path[0] != '/')) { if (!strcmp(path, "*")) anypath++; else { errstr = "illegal search path specified"; return (-1); } } rdpath = 0; for (;;) { if (feof(fpin)) return (0); /* no more entries */ /* save current position in file */ pos = ftell(fpin); /* grab path from first entry */ c = getc(fpin); if (c != '/') { /* * we check for EOF inside this if statement to * reduce normal execution time */ if (c == EOF) return (0); /* no more entries */ else if (isspace(c) || (c == '#') || (c == ':')) { /* line is a comment */ (void) getend(fpin); continue; } /* * we need to read this entry in the format which * specifies * ftype class path * so we set the rdpath variable and immediately * jump to the code which will parse this format. * When done, that code will return to Path_Done below */ ungetc(c, fpin); rdpath = 1; break; } /* copy first token into path element of passed structure */ pt = mypath; do { if (strchr("= \t\n", c)) break; *pt++ = (char) c; } while ((c = getc(fpin)) != EOF); *pt = '\0'; if (c == EOF) ERROR("incomplete entry") ept->path = mypath; Path_Done: /* * determine if we have read the pathname which identifies * the entry we are searching for */ if (anypath) n = 0; /* any pathname will do */ else if (path) n = strcmp(path, ept->path); else n = 1; /* no pathname will match */ if (n == 0) { /* * we want to return information about this path in * the structure provided, so parse any local path * and jump to code which parses rest of the input line */ if (c == '=') { /* parse local path specification */ if (getstr(fpin, NULL, PATH_MAX, mylocal)) ERROR("unable to read local/link path") ept->ainfo.local = mylocal; } break; /* scan into a structure */ } else if (n < 0) { /* * the entry we want would fit BEFORE the one we just * read, so we need to unread what we've read by * seeking back to the start of this entry */ if (fseek(fpin, pos, 0)) { errstr = pkg_gt("failure attempting fseek"); return (-1); } return (2); /* path would insert here */ } if (fpout) { /* * copy what we've read and the rest of this line * onto the specified output stream */ (void) fprintf(fpout, "%s%c", ept->path, c); if (rdpath) { (void) fprintf(fpout, "%c %s", ept->ftype, ept->pkg_class); } while ((c = getc(fpin)) != EOF) { putc(c, fpout); if (c == '\n') break; } } else { /* * since this isn't the entry we want, just read the * stream until we find the end of this entry and * then start this search loop again */ while ((c = getc(fpin)) != EOF) { if (c == '\n') break; } if (c == EOF) ERROR("missing newline at end of entry") } } if (rdpath < 2) { /* * since we are processing an oldstyle entry and we have * already read ftype, class, and path we just jump into * reading the other info */ switch (c = eatwhite(fpin)) { case EOF: errstr = pkg_gt("incomplete entry"); return (-1); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ERROR("volume number not expected") case 'i': ERROR("ftype not expected") case '?': case 'f': case 'v': case 'e': case 'l': case 's': case 'p': case 'c': case 'b': case 'd': case 'x': ept->ftype = (char) c; if (getstr(fpin, NULL, CLSSIZ, ept->pkg_class)) ERROR("unable to read class token") if (!rdpath) break; /* we already read the pathname */ if (getstr(fpin, "=", PATH_MAX, mypath)) ERROR("unable to read pathname field") ept->path = mypath; c = getc(fpin); rdpath++; goto Path_Done; default: errstr = pkg_gt("unknown ftype"); Error: (void) getend(fpin); return (-1); } } if (strchr("sl", ept->ftype) && (ept->ainfo.local == NULL)) ERROR("no link source specified"); if (strchr("cb", ept->ftype)) { #ifdef SUNOS41 ept->ainfo.xmajor = BADMAJOR; ept->ainfo.xminor = BADMINOR; if (getnum(fpin, 10, (long *)&ept->ainfo.xmajor, BADMAJOR) || getnum(fpin, 10, (long *)&ept->ainfo.xminor, BADMINOR)) #else ept->ainfo.major = BADMAJOR; ept->ainfo.minor = BADMINOR; if (getnum(fpin, 10, (long *)&ept->ainfo.major, BADMAJOR) || getnum(fpin, 10, (long *)&ept->ainfo.minor, BADMINOR)) #endif ERROR("unable to read major/minor device numbers") } if (strchr("cbdxpfve", ept->ftype)) { /* mode, owner, group should be here */ if (getnum(fpin, 8, (long *)&ept->ainfo.mode, BADMODE) || getstr(fpin, NULL, ATRSIZ, ept->ainfo.owner) || getstr(fpin, NULL, ATRSIZ, ept->ainfo.group)) ERROR("unable to read mode/owner/group") } if (strchr("ifve", ept->ftype)) { /* look for content description */ if (getnum(fpin, 10, (long *)&ept->cinfo.size, BADCONT) || getnum(fpin, 10, (long *)&ept->cinfo.cksum, BADCONT) || getnum(fpin, 10, (long *)&ept->cinfo.modtime, BADCONT)) ERROR("unable to read content info") } if (ept->ftype == 'i') { if (getend(fpin)) { errstr = pkg_gt("extra tokens on input line"); return (-1); } return (1); } /* determine list of packages which reference this entry */ lastpinfo = (struct pinfo *)0; while ((c = getstr(fpin, ":\\", PKGSIZ, pkgname)) <= 0) { if (c < 0) ERROR("package name too long") else if (c == 0) { /* a package was listed */ pinfo = (struct pinfo *)calloc(1, sizeof (struct pinfo)); if (!pinfo) ERROR("no memory for package information") if (!lastpinfo) ept->pinfo = pinfo; /* first one */ else lastpinfo->next = pinfo; /* link list */ lastpinfo = pinfo; if (strchr("-+*~!%", pkgname[0])) { pinfo->status = pkgname[0]; (void) strcpy(pinfo->pkg, pkgname+1); } else (void) strcpy(pinfo->pkg, pkgname); /* pkg/[:[ftype][:class] */ c = getc(fpin); if (c == '\\') { /* get alternate ftype */ pinfo->editflag++; c = getc(fpin); } if (c == ':') { /* get special classname */ (void) getstr(fpin, "", 12, classname); (void) strcpy(pinfo->aclass, classname); c = getc(fpin); } ept->npkgs++; if ((c == '\n') || (c == EOF)) return (1); else if (!isspace(c)) ERROR("bad end of entry") } } if (getend(fpin) && ept->pinfo) { errstr = pkg_gt("extra token(s) on input line"); return (-1); } return (1); } static int getnum(FILE *fp, int base, long *d, long bad) { int c; /* leading white space ignored */ c = eatwhite(fp); if (c == '?') { *d = bad; return (0); } if ((c == EOF) || (c == '\n') || !isdigit(c)) { (void) ungetc(c, fp); return (1); } *d = 0; while (isdigit(c)) { *d = (*d * base) + (c & 017); c = getc(fp); } (void) ungetc(c, fp); return (0); } static int getstr(FILE *fp, char *sep, int n, char *str) { int c; /* leading white space ignored */ c = eatwhite(fp); if ((c == EOF) || (c == '\n')) { (void) ungetc(c, fp); return (1); /* nothing there */ } /* fill up string until space, tab, or separator */ while (!strchr(" \t", c) && (!sep || !strchr(sep, c))) { if (n-- < 1) { *str = '\0'; return (-1); /* too long */ } *str++ = (char) c; c = getc(fp); if ((c == EOF) || (c == '\n')) break; /* no more on this line */ } *str = '\0'; (void) ungetc(c, fp); return (0); } static int getend(FILE *fp) { int c; int n; n = 0; do { if ((c = getc(fp)) == EOF) return (n); if (!isspace(c)) n++; } while (c != '\n'); return (n); } static int eatwhite(FILE *fp) { int c; /* this test works around a side effect of getc() */ if (feof(fp)) return (EOF); do c = getc(fp); while ((c == ' ') || (c == '\t')); return (c); }