#include "asd.h" #define CHUNK 64 /* type codes for installation subroutine */ #define BACKUP 0 #define INSTALL 1 void readtemp(); /* * The following declarations and functions manipulate * a list of directory names. This list is used to decide * which files should be backed up and which have already been. */ struct list { char *name; struct list *next; }; static struct list *dirs; /* is the name given a subdirectory of the name on the list? */ static int subsumed (name) register char *name; { register struct list *item; register char *p, *q; for (item = dirs; item; item = item->next) { p = item->name; q = name; while (*p && *p == *q) p++, q++; if (*p == '\0' && (*q == '/' || *q == '\0')) return 1; } return 0; } /* add the name given to the list */ static void addlist (name) register char *name; { register struct list *l; l = new (struct list); l->next = dirs; l->name = copy (name); dirs = l; } /* clear the entire list */ static void clearlist() { register struct list *l; while (l = dirs) { dirs = l->next; free (l->name); free ((char *) l); } } /* * install the given file */ process (file, fname) FILE *file; char *fname; { register int c, rc = 0; if (vflag) fprintf (stderr, "%s:\n", fname); while ((c = getc (file)) != EOF) { ungetc (c, file); rc += doarch (file); } return rc; } main (argc, argv) int argc; char **argv; { static char errbuf[BUFSIZ]; setbuf (stderr, errbuf); umask (0); return getargs (argc, argv, "nvbD:", process); } static char tfname[TMPNAML]; void delete(); /* process a single archive in a concatenation */ doarch (file) register FILE *file; { register FILE *tf; Sig_typ sigsav; register long size; register int c; char armag[SARMAG]; /* Make sure the file is an archive */ if (fread (armag, sizeof (*armag), SARMAG, file) != SARMAG) { fprintf (stderr, "inspkg: unexpected EOF\n"); exit (1); } if (strncmp (armag, ARMAG, SARMAG) != 0) { fprintf (stderr, "inspkg: input not a package\n"); exit (1); } /* establish a temporary file */ (void) tmpname (tfname); tf = fopen (tfname, "w"); sigsav = signal (SIGINT, SIG_IGN); if (sigsav != SIG_IGN) signal (SIGINT, delete); chmod (tfname, 0600); /* copy the installation instructions to the temp file */ size = read_header (instr, file); while (--size >= 0) { c = getc (file); if (c == EOF) { fprintf (stderr, "inspkg: premature EOF\n"); exit (1); } if (putc (c, tf) == EOF) { perror ("inspkg: Instructions"); exit (1); } } if (fclose (tf) == EOF) { perror ("inspkg: Instructions fclose"); exit (1); } next_header (file); /* create the optional backup package */ if (bflag) { pkgstart(); readtemp (BACKUP, file); pkgend(); clearlist(); } /* do the actual work */ readtemp (INSTALL, file); /* delete the temporary file */ nchk (unlink (tfname)); signal (SIGINT, sigsav); return 0; } /* * Make a pass through the temp file. */ static void readtemp (code, file) register int code; register FILE *file; { register FILE *tf; register int c; /* we're done writing the temp file, time to read it */ tf = fopen (tfname, "r"); schk ((char *) tf); /* * The main loop -- one iteration per line * We are careful in use and reuse of storage here; * if you change this code make sure you understand * the times at which getfield and transname * recycle storage or strange things will happen. */ while ((c = getc (tf)) != EOF) { char *param, *path, *path2; register FILE *outfd; int uid, gid, mode, dmajor, dminor, dev; register long size; char component[MAXCOMP+1]; switch (c) { /* special files */ case 'b': case 'c': /* read the parameters */ param = getfield (tf); mode = cvlong (param, strlen (param), 8) | (c == 'c'? S_IFCHR: S_IFBLK); param = getfield (tf); dmajor = cvlong (param, strlen (param), 10); param = getfield (tf); dminor = cvlong (param, strlen (param), 10); dev = makedev (dmajor, dminor); uid = numuid (getfield (tf)); gid = numgid (getfield (tf)); path = transname (getfield (tf)); geteol (tf); switch (code) { case BACKUP: if (!subsumed (path)) { pkgfile (path); addlist (path); } break; case INSTALL: if (vflag) { fprintf (stderr, "special file "); putpath (stderr, path); fprintf (stderr, "\n"); } if (!nflag) { rmall (path); if (mknod (path, mode, dev) >= 0) chown (path, uid, gid); else perror (path); } break; } break; /* directory */ case 'd': /* read the parameters */ param = getfield (tf); mode = cvlong (param, strlen (param), 8); uid = numuid (getfield (tf)); gid = numgid (getfield (tf)); path = transname (getfield (tf)); geteol (tf); switch (code) { case BACKUP: if (!subsumed (path)) { pkgfile (path); addlist (path); } break; case INSTALL: /* make the directory */ if (vflag) { fprintf (stderr, "directory "); putpath (stderr, path); putc ('\n', stderr); } if (!nflag) { rmall (path); mkdir (path); chmod (path, mode); chown (path, uid, gid); chmod (path, mode); } break; } break; /* file */ case 'f': /* read parameters */ param = getfield (tf); if (strlen (param) > MAXCOMP) { fprintf (stderr, "inspkg: impossibly long component name\n"); delete(); exit (1); } strcpy (component, param); uid = numuid (getfield (tf)); gid = numgid (getfield (tf)); path = transname (getfield (tf)); geteol (tf); switch (code) { case BACKUP: if (!subsumed (path)) pkgfile (path); break; case INSTALL: /* read the corresponding archive header */ size = read_header (component, file); if (vflag) { fprintf (stderr, "file "); putpath (stderr, path); putc ('\n', stderr); } /* create and open the file */ if (!nflag) { rmall (path); umask (077); outfd = fopen (path, "w"); umask (0); if (outfd == NULL) { fprintf (stderr, "inspkg: cannot create "); putpath (stderr, path); putc ('\n', stderr); } } if (nflag || outfd == NULL) { outfd = fopen ("/dev/null", "w"); schk ((char *) outfd); } /* copy the file, advance input */ while (--size >= 0) putc (getc (file), outfd); next_header (file); /* check successful completion, close output */ fflush (outfd); if (feof (file) || ferror (file) || ferror (outfd)) { fprintf (stderr, "inspkg: can't write "); putpath (stderr, path); putc ('\n', stderr); } if (fclose (outfd) == EOF) { fprintf (stderr, "inspkg: can't close "); putpath (stderr, path); fprintf (stderr, ": "); perror (""); } /* * Update output modification times * and change mode and owner. * This is done here to cater to systems * that allow people to give files away. * The chmod is done twice because * systems that let you give files away * won't let you change the mode after * you've done so, and some other systems * turn off the setuid bit as a side * effect of chown, so the second chmod * will restore that bit. */ if (!nflag) { time_t timep[2]; timep[0] = timep[1] = hdr.date; utime (path, timep); chmod (path, hdr.mode & 07777); chown (path, uid, gid); chmod (path, hdr.mode & 07777); } break; } break; /* symbolic link */ case 's': /* read parameters */ path = copy (transname (getfield (tf))); path2 = transname (getfield (tf)); geteol (tf); switch (code) { case BACKUP: if (!subsumed (path2)) pkgfile (path2); break; case INSTALL: /* log it if requested */ if (vflag) { fprintf (stderr, "symlink "); putpath (stderr, path2); fprintf (stderr, " to "); putpath (stderr, path); putc ('\n', stderr); } #ifdef S_IFLNK /* make the link */ if (!nflag) { rmall (path2); if (symlink (path, path2) < 0) perror (path2); } #else fprintf(stderr, "This system does not support symbolic links\n"); #endif break; } free (path); break; /* link */ case 'l': /* read parameters */ path = copy (transname (getfield (tf))); path2 = transname (getfield (tf)); geteol (tf); switch (code) { case BACKUP: if (!subsumed (path2)) pkgfile (path2); break; case INSTALL: /* log it if requested */ if (vflag) { fprintf (stderr, "link "); putpath (stderr, path); fprintf (stderr, " to "); putpath (stderr, path2); putc ('\n', stderr); } /* make the link */ if (!nflag) { struct stat sb, sb2; /* are we about to link x to x? */ if (stat (path, &sb) < 0 || stat (path2, &sb2) < 0 || sb.st_dev != sb2.st_dev || sb.st_ino != sb2.st_ino) { rmall (path2); if (link (path, path2) < 0) perror (path2); } } break; } free (path); break; /* remove */ case 'r': /* get parameters */ path = transname (getfield (tf)); geteol (tf); switch (code) { case BACKUP: if (!subsumed (path)) pkgfile (path); break; case INSTALL: if (vflag) { fprintf (stderr, "remove file "); putpath (stderr, path); putc ('\n', stderr); } if (!nflag) rmall (path); break; } break; case 'x': xstr = getfield (tf); geteol (tf); if (code == INSTALL) { if (vflag) { fprintf (stderr, "execute: "); putpath (stderr, xstr); fprintf (stderr, "\n"); } if (!nflag) { fflush (stderr); system (xstr); } } xstr = NULL; break; case 'X': Xstr = transname (getfield (tf)); geteol (tf); if (code == INSTALL) { if (vflag) { fprintf (stderr, "exec file: "); putpath (stderr, Xstr); fprintf (stderr, "\n"); } if (!nflag) { int status, pid, w; Sig_typ istat, qstat; fflush (stderr); if ((pid = fork()) == 0) { execl (Xstr, Xstr, (char *)0); execl ("/bin/sh", "sh", Xstr, (char *) 0); putpath (stderr, Xstr); fprintf (stderr, ": "); fflush (stderr); perror (""); _exit(127); } istat = signal (SIGINT, SIG_IGN); qstat = signal (SIGQUIT, SIG_IGN); while ((w=wait(&status)) != pid && w != -1) ; signal(SIGINT, istat); signal(SIGQUIT, qstat); } } Xstr = NULL; break; default: fprintf (stderr, "inspkg: invalid package\n"); delete(); exit (1); } } if (ferror (tf)) perror ("inspkg: internal temp file"); fclose (tf); } static void delete() { unlink (tfname); exit (3); }