Index: head/usr.sbin/pkg_install/add/Makefile =================================================================== --- head/usr.sbin/pkg_install/add/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/add/Makefile (revision 131285) @@ -1,13 +1,14 @@ # $FreeBSD$ PROG= pkg_add SRCS= main.c perform.c futil.c extract.c CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib -WARNS?= 2 +WARNS?= 6 +WFORMAT?= 1 DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} LDADD= ${LIBINSTALL} -lfetch -lmd .include Index: head/usr.sbin/pkg_install/add/add.h =================================================================== --- head/usr.sbin/pkg_install/add/add.h (revision 131284) +++ head/usr.sbin/pkg_install/add/add.h (revision 131285) @@ -1,44 +1,44 @@ /* $FreeBSD$ */ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Include and define various things wanted by the add command. * */ #ifndef _INST_ADD_H_INCLUDE #define _INST_ADD_H_INCLUDE typedef enum { NORMAL, MASTER, SLAVE } add_mode_t; extern char *Prefix; extern Boolean NoInstall; extern Boolean NoRecord; -extern Boolean Force; extern char *Mode; extern char *Owner; extern char *Group; extern char *Directory; extern char *PkgName; +extern char *PkgAddCmd; extern char FirstPen[]; extern add_mode_t AddMode; int make_hierarchy(char *); void extract_plist(const char *, Package *); void apply_perms(const char *, const char *); #endif /* _INST_ADD_H_INCLUDE */ Index: head/usr.sbin/pkg_install/add/extract.c =================================================================== --- head/usr.sbin/pkg_install/add/extract.c (revision 131284) +++ head/usr.sbin/pkg_install/add/extract.c (revision 131285) @@ -1,277 +1,277 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * This is the package extraction code for the add module. * */ #include __FBSDID("$FreeBSD$"); #include #include #include "lib.h" #include "add.h" -#define STARTSTRING "tar cf -" +#define STARTSTRING "/usr/bin/tar cf -" #define TOOBIG(str) \ (((int)strlen(str) + FILENAME_MAX + where_count > maxargs) ||\ ((int)strlen(str) + FILENAME_MAX + perm_count > maxargs)) #define PUSHOUT(todir) /* push out string */ \ if (where_count > (int)sizeof(STARTSTRING)-1) { \ - strcat(where_args, "|tar --unlink -xpf - -C "); \ + strcat(where_args, "|/usr/bin/tar --unlink -xpf - -C "); \ strcat(where_args, todir); \ if (system(where_args)) { \ cleanup(0); \ errx(2, "%s: can not invoke %ld byte tar pipeline: %s", \ __func__, (long)strlen(where_args), where_args); \ } \ strcpy(where_args, STARTSTRING); \ where_count = sizeof(STARTSTRING)-1; \ } \ if (perm_count) { \ apply_perms(todir, perm_args); \ perm_args[0] = 0;\ perm_count = 0; \ } static void rollback(const char *name, const char *home, PackingList start, PackingList stop) { PackingList q; char try[FILENAME_MAX], bup[FILENAME_MAX]; const char *dir; dir = home; for (q = start; q != stop; q = q->next) { if (q->type == PLIST_FILE) { snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name); if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) { (void)chflags(try, 0); (void)unlink(try); if (rename(bup, try)) warnx("rollback: unable to rename %s back to %s", bup, try); } } else if (q->type == PLIST_CWD) { if (strcmp(q->name, ".")) dir = q->name; else dir = home; } } } #define add_char(buf, len, pos, ch) do {\ if ((pos) < (len)) { \ buf[(pos)] = (ch); \ buf[(pos) + 1] = '\0'; \ } \ ++(pos); \ } while (0) static int add_arg(char *buf, int len, const char *str) { int i = 0; add_char(buf, len, i, ' '); for (; *str != '\0'; ++str) { if (!isalnum(*str) && *str != '/' && *str != '.' && *str != '-') add_char(buf, len, i, '\\'); add_char(buf, len, i, *str); } return (i); } void extract_plist(const char *home, Package *pkg) { PackingList p = pkg->head; char *last_file; char *where_args, *perm_args, *last_chdir; int maxargs, where_count = 0, perm_count = 0, add_count; Boolean preserve; maxargs = sysconf(_SC_ARG_MAX) / 2; /* Just use half the argument space */ where_args = alloca(maxargs); if (!where_args) { cleanup(0); errx(2, "%s: can't get argument list space", __func__); } perm_args = alloca(maxargs); if (!perm_args) { cleanup(0); errx(2, "%s: can't get argument list space", __func__); } strcpy(where_args, STARTSTRING); where_count = sizeof(STARTSTRING)-1; perm_args[0] = 0; last_chdir = 0; preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; /* Reset the world */ Owner = NULL; Group = NULL; Mode = NULL; last_file = NULL; (const char *)Directory = home; /* Do it */ while (p) { char cmd[FILENAME_MAX]; switch(p->type) { case PLIST_NAME: PkgName = p->name; if (Verbose) printf("extract: Package name is %s\n", p->name); break; case PLIST_FILE: last_file = p->name; if (Verbose) printf("extract: %s/%s\n", Directory, p->name); if (!Fake) { char try[FILENAME_MAX]; /* first try to rename it into place */ snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name); if (fexists(try)) { (void)chflags(try, 0); /* XXX hack - if truly immutable, rename fails */ if (preserve && PkgName) { char pf[FILENAME_MAX]; if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) { if (rename(try, pf)) { warnx( "unable to back up %s to %s, aborting pkg_add", try, pf); rollback(PkgName, home, pkg->head, p); return; } } } } if (rename(p->name, try) == 0) { /* try to add to list of perms to be changed and run in bulk. */ if (p->name[0] == '/' || TOOBIG(p->name)) { PUSHOUT(Directory); } add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name); if (add_count < 0 || add_count >= maxargs - perm_count) { cleanup(0); errx(2, "%s: oops, miscounted strings!", __func__); } perm_count += add_count; } else { /* rename failed, try copying with a big tar command */ if (last_chdir != Directory) { if (last_chdir == NULL) { PUSHOUT(Directory); } else { PUSHOUT(last_chdir); } last_chdir = Directory; } else if (p->name[0] == '/' || TOOBIG(p->name)) { PUSHOUT(Directory); } add_count = add_arg(&where_args[where_count], maxargs - where_count, p->name); if (add_count < 0 || add_count >= maxargs - where_count) { cleanup(0); errx(2, "%s: oops, miscounted strings!", __func__); } where_count += add_count; add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name); if (add_count < 0 || add_count >= maxargs - perm_count) { cleanup(0); errx(2, "%s: oops, miscounted strings!", __func__); } perm_count += add_count; } } break; case PLIST_CWD: if (Verbose) printf("extract: CWD to %s\n", p->name); PUSHOUT(Directory); if (strcmp(p->name, ".")) { if (!Fake && make_hierarchy(p->name) == FAIL) { cleanup(0); errx(2, "%s: unable to cwd to '%s'", __func__, p->name); } Directory = p->name; } else (const char *)Directory = home; break; case PLIST_CMD: if ((strstr(p->name, "%B") || strstr(p->name, "%F") || strstr(p->name, "%f")) && last_file == NULL) { cleanup(0); errx(2, "%s: no last file specified for '%s' command", __func__, p->name); } if (strstr(p->name, "%D") && Directory == NULL) { cleanup(0); errx(2, "%s: no directory specified for '%s' command", __func__, p->name); } format_cmd(cmd, FILENAME_MAX, p->name, Directory, last_file); PUSHOUT(Directory); if (Verbose) printf("extract: execute '%s'\n", cmd); if (!Fake && system(cmd)) warnx("command '%s' failed", cmd); break; case PLIST_CHMOD: PUSHOUT(Directory); Mode = p->name; break; case PLIST_CHOWN: PUSHOUT(Directory); Owner = p->name; break; case PLIST_CHGRP: PUSHOUT(Directory); Group = p->name; break; case PLIST_COMMENT: break; case PLIST_IGNORE: p = p->next; break; default: break; } p = p->next; } PUSHOUT(Directory); } Index: head/usr.sbin/pkg_install/add/futil.c =================================================================== --- head/usr.sbin/pkg_install/add/futil.c (revision 131284) +++ head/usr.sbin/pkg_install/add/futil.c (revision 131285) @@ -1,97 +1,97 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Miscellaneous file access utilities. * */ #include __FBSDID("$FreeBSD$"); #include #include "lib.h" #include "add.h" /* * Assuming dir is a desired directory name, make it and all intervening * directories necessary. */ int make_hierarchy(char *dir) { char *cp1, *cp2; if (dir[0] == '/') cp1 = cp2 = dir + 1; else cp1 = cp2 = dir; while (cp2) { if ((cp2 = strchr(cp1, '/')) !=NULL ) *cp2 = '\0'; if (fexists(dir)) { if (!isdir(dir)) { if (cp2) *cp2 = '/'; return FAIL; } } else { - if (vsystem("mkdir %s", dir)) { + if (vsystem("/bin/mkdir %s", dir)) { if (cp2) *cp2 = '/'; return FAIL; } apply_perms(NULL, dir); } /* Put it back */ if (cp2) { *cp2 = '/'; cp1 = cp2 + 1; } } return SUCCESS; } /* Using permission defaults, apply them as necessary */ void apply_perms(const char *dir, const char *arg) { const char *cd_to; if (!dir || *arg == '/') /* absolute path? */ cd_to = "/"; else cd_to = dir; if (Mode) - if (vsystem("cd %s && chmod -R %s %s", cd_to, Mode, arg)) + if (vsystem("cd %s && /bin/chmod -R %s %s", cd_to, Mode, arg)) warnx("couldn't change modes of '%s' to '%s'", arg, Mode); if (Owner && Group) { - if (vsystem("cd %s && chown -R %s:%s %s", cd_to, Owner, Group, arg)) + if (vsystem("cd %s && /usr/sbin/chown -R %s:%s %s", cd_to, Owner, Group, arg)) warnx("couldn't change owner/group of '%s' to '%s:%s'", arg, Owner, Group); return; } if (Owner) { - if (vsystem("cd %s && chown -R %s %s", cd_to, Owner, arg)) + if (vsystem("cd %s && /usr/sbin/chown -R %s %s", cd_to, Owner, arg)) warnx("couldn't change owner of '%s' to '%s'", arg, Owner); return; } else if (Group) - if (vsystem("cd %s && chgrp -R %s %s", cd_to, Group, arg)) + if (vsystem("cd %s && /usr/bin/chgrp -R %s %s", cd_to, Group, arg)) warnx("couldn't change group of '%s' to '%s'", arg, Group); } Index: head/usr.sbin/pkg_install/add/main.c =================================================================== --- head/usr.sbin/pkg_install/add/main.c (revision 131284) +++ head/usr.sbin/pkg_install/add/main.c (revision 131285) @@ -1,298 +1,311 @@ /* * * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * This is the add module. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "lib.h" #include "add.h" static char Options[] = "hvIRfnrp:SMt:C:"; char *Prefix = NULL; char *Chroot = NULL; Boolean NoInstall = FALSE; Boolean NoRecord = FALSE; Boolean Remote = FALSE; char *Mode = NULL; char *Owner = NULL; char *Group = NULL; char *PkgName = NULL; +char *PkgAddCmd = NULL; char *Directory = NULL; char FirstPen[FILENAME_MAX]; add_mode_t AddMode = NORMAL; #define MAX_PKGS 200 char pkgnames[MAX_PKGS][MAXPATHLEN]; char *pkgs[MAX_PKGS]; struct { int lowver; /* Lowest version number to match */ int hiver; /* Highest version number to match */ const char *directory; /* Directory it lives in */ } releases[] = { { 410000, 410000, "/packages-4.1-release" }, { 420000, 420000, "/packages-4.2-release" }, { 430000, 430000, "/packages-4.3-release" }, { 440000, 440000, "/packages-4.4-release" }, { 450000, 450000, "/packages-4.5-release" }, { 460000, 460001, "/packages-4.6-release" }, { 460002, 460099, "/packages-4.6.2-release" }, { 470000, 470099, "/packages-4.7-release" }, { 480000, 480099, "/packages-4.8-release" }, { 490000, 490099, "/packages-4.9-release" }, { 491000, 491099, "/packages-4.10-release" }, + { 492000, 492099, "/packages-4.11-release" }, { 500000, 500099, "/packages-5.0-release" }, { 501000, 501099, "/packages-5.1-release" }, { 502000, 502009, "/packages-5.2-release" }, { 502010, 502099, "/packages-5.2.1-release" }, + { 503000, 503099, "/packages-5.3-release" }, { 300000, 399000, "/packages-3-stable" }, { 400000, 499000, "/packages-4-stable" }, { 502100, 599000, "/packages-5-current" }, { 0, 9999999, "/packages-current" }, { 0, 0, NULL } }; static char *getpackagesite(void); int getosreldate(void); static void usage __P((void)); int main(int argc, char **argv) { int ch, error; char **start; char *cp, *packagesite = NULL, *remotepkg = NULL, *ptr; static char temppackageroot[MAXPATHLEN]; + static char pkgaddpath[MAXPATHLEN]; + if (*argv[0] != '/' && strchr(argv[0], '/') != NULL) + PkgAddCmd = realpath(argv[0], pkgaddpath); + else + PkgAddCmd = argv[0]; + start = argv; while ((ch = getopt(argc, argv, Options)) != -1) { switch(ch) { case 'v': Verbose = TRUE; break; case 'p': Prefix = optarg; break; case 'I': NoInstall = TRUE; break; case 'R': NoRecord = TRUE; break; case 'f': Force = TRUE; break; case 'n': Fake = TRUE; Verbose = TRUE; break; case 'r': Remote = TRUE; break; case 't': if (strlcpy(FirstPen, optarg, sizeof(FirstPen)) >= sizeof(FirstPen)) errx(1, "-t Argument too long."); break; case 'S': AddMode = SLAVE; break; case 'M': AddMode = MASTER; break; case 'C': Chroot = optarg; break; case 'h': case '?': default: usage(); break; } } argc -= optind; argv += optind; if (argc > MAX_PKGS) { errx(1, "too many packages (max %d)", MAX_PKGS); } if (AddMode != SLAVE) { for (ch = 0; ch < MAX_PKGS; pkgs[ch++] = NULL) ; /* Get all the remaining package names, if any */ for (ch = 0; *argv; ch++, argv++) { if (Remote) { if ((packagesite = getpackagesite()) == NULL) errx(1, "package name too long"); if (strlcpy(temppackageroot, packagesite, sizeof(temppackageroot)) >= sizeof(temppackageroot)) errx(1, "package name too long"); if (strlcat(temppackageroot, *argv, sizeof(temppackageroot)) >= sizeof(temppackageroot)) errx(1, "package name too long"); remotepkg = temppackageroot; if (!((ptr = strrchr(remotepkg, '.')) && ptr[1] == 't' && (ptr[2] == 'b' || ptr[2] == 'g') && ptr[3] == 'z' && !ptr[4])) - /* XXX: need to handle .tgz also */ - if (strlcat(remotepkg, ".tbz", sizeof(temppackageroot)) - >= sizeof(temppackageroot)) + if (strlcat(remotepkg, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 + ".tbz", +#else + ".tgz", +#endif + sizeof(temppackageroot)) >= sizeof(temppackageroot)) errx(1, "package name too long"); } if (!strcmp(*argv, "-")) /* stdin? */ (const char *)pkgs[ch] = "-"; else if (isURL(*argv)) { /* preserve URLs */ if (strlcpy(pkgnames[ch], *argv, sizeof(pkgnames[ch])) >= sizeof(pkgnames[ch])) errx(1, "package name too long"); pkgs[ch] = pkgnames[ch]; } else if ((Remote) && isURL(remotepkg)) { if (strlcpy(pkgnames[ch], remotepkg, sizeof(pkgnames[ch])) >= sizeof(pkgnames[ch])) errx(1, "package name too long"); pkgs[ch] = pkgnames[ch]; } else { /* expand all pathnames to fullnames */ if (fexists(*argv)) /* refers to a file directly */ pkgs[ch] = realpath(*argv, pkgnames[ch]); else { /* look for the file in the expected places */ if (!(cp = fileFindByPath(NULL, *argv))) { /* let pkg_do() fail later, so that error is reported */ if (strlcpy(pkgnames[ch], *argv, sizeof(pkgnames[ch])) >= sizeof(pkgnames[ch])) errx(1, "package name too long"); pkgs[ch] = pkgnames[ch]; } else { if (strlcpy(pkgnames[ch], cp, sizeof(pkgnames[ch])) >= sizeof(pkgnames[ch])) errx(1, "package name too long"); pkgs[ch] = pkgnames[ch]; } } } if (packagesite != NULL) packagesite[0] = '\0'; } } /* If no packages, yelp */ else if (!ch) { warnx("missing package name(s)"); usage(); } else if (ch > 1 && AddMode == MASTER) { warnx("only one package name may be specified with master mode"); usage(); } /* Perform chroot if requested */ if (Chroot != NULL) { if (chroot(Chroot)) errx(1, "chroot to %s failed", Chroot); } /* Make sure the sub-execs we invoke get found */ setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin", 1); /* Set a reasonable umask */ umask(022); if ((error = pkg_perform(pkgs)) != 0) { if (Verbose) warnx("%d package addition(s) failed", error); return error; } else return 0; } static char * getpackagesite(void) { int reldate, i; static char sitepath[MAXPATHLEN]; struct utsname u; if (getenv("PACKAGESITE")) { if (strlcpy(sitepath, getenv("PACKAGESITE"), sizeof(sitepath)) >= sizeof(sitepath)) return NULL; return sitepath; } if (getenv("PACKAGEROOT")) { if (strlcpy(sitepath, getenv("PACKAGEROOT"), sizeof(sitepath)) >= sizeof(sitepath)) return NULL; } else { if (strlcat(sitepath, "ftp://ftp.freebsd.org", sizeof(sitepath)) >= sizeof(sitepath)) return NULL; } if (strlcat(sitepath, "/pub/FreeBSD/ports/", sizeof(sitepath)) >= sizeof(sitepath)) return NULL; uname(&u); if (strlcat(sitepath, u.machine, sizeof(sitepath)) >= sizeof(sitepath)) return NULL; reldate = getosreldate(); for(i = 0; releases[i].directory != NULL; i++) { if (reldate >= releases[i].lowver && reldate <= releases[i].hiver) { if (strlcat(sitepath, releases[i].directory, sizeof(sitepath)) >= sizeof(sitepath)) return NULL; break; } } if (strlcat(sitepath, "/Latest/", sizeof(sitepath)) >= sizeof(sitepath)) return NULL; return sitepath; } static void usage() { fprintf(stderr, "%s\n%s\n", "usage: pkg_add [-vInrfRMS] [-t template] [-p prefix] [-C chrootdir]", " pkg-name [pkg-name ...]"); exit(1); } Index: head/usr.sbin/pkg_install/add/perform.c =================================================================== --- head/usr.sbin/pkg_install/add/perform.c (revision 131284) +++ head/usr.sbin/pkg_install/add/perform.c (revision 131285) @@ -1,598 +1,602 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * This is the main body of the add module. * */ #include __FBSDID("$FreeBSD$"); #include #include #include "lib.h" #include "add.h" #include #include #include static int pkg_do(char *); static int sanity_check(char *); static char LogDir[FILENAME_MAX]; static int zapLogDir; /* Should we delete LogDir? */ int pkg_perform(char **pkgs) { int i, err_cnt = 0; signal(SIGINT, cleanup); signal(SIGHUP, cleanup); if (AddMode == SLAVE) err_cnt = pkg_do(NULL); else { for (i = 0; pkgs[i]; i++) err_cnt += pkg_do(pkgs[i]); } return err_cnt; } static Package Plist; static char *Home; /* * This is seriously ugly code following. Written very fast! * [And subsequently made even worse.. Sigh! This code was just born * to be hacked, I guess.. :) -jkh] */ static int pkg_do(char *pkg) { char pkg_fullname[FILENAME_MAX]; char playpen[FILENAME_MAX]; char extract_contents[FILENAME_MAX]; char *where_to, *extract; FILE *cfile; int code; PackingList p; struct stat sb; int inPlace, conflictsfound, errcode; /* support for separate pre/post install scripts */ int new_m = 0; char pre_script[FILENAME_MAX] = INSTALL_FNAME; char post_script[FILENAME_MAX]; char pre_arg[FILENAME_MAX], post_arg[FILENAME_MAX]; char *conflict[2]; char **matched; conflictsfound = 0; code = 0; zapLogDir = 0; LogDir[0] = '\0'; strcpy(playpen, FirstPen); inPlace = 0; /* Are we coming in for a second pass, everything already extracted? */ if (!pkg) { fgets(playpen, FILENAME_MAX, stdin); playpen[strlen(playpen) - 1] = '\0'; /* pesky newline! */ if (chdir(playpen) == FAIL) { warnx("pkg_add in SLAVE mode can't chdir to %s", playpen); return 1; } read_plist(&Plist, stdin); where_to = playpen; } /* Nope - do it now */ else { /* Is it an ftp://foo.bar.baz/file.t[bg]z specification? */ if (isURL(pkg)) { if (!(Home = fileGetURL(NULL, pkg))) { warnx("unable to fetch '%s' by URL", pkg); return 1; } where_to = Home; strcpy(pkg_fullname, pkg); cfile = fopen(CONTENTS_FNAME, "r"); if (!cfile) { warnx( "unable to open table of contents file '%s' - not a package?", CONTENTS_FNAME); goto bomb; } read_plist(&Plist, cfile); fclose(cfile); } else { strcpy(pkg_fullname, pkg); /* * Copy for sanity's sake, * could remove pkg_fullname */ if (strcmp(pkg, "-")) { if (stat(pkg_fullname, &sb) == FAIL) { warnx("can't stat package file '%s'", pkg_fullname); goto bomb; } sprintf(extract_contents, "--fast-read %s", CONTENTS_FNAME); extract = extract_contents; } else { extract = NULL; sb.st_size = 100000; /* Make up a plausible average size */ } Home = make_playpen(playpen, sb.st_size * 4); if (!Home) errx(1, "unable to make playpen for %qd bytes", (long long)sb.st_size * 4); where_to = Home; /* Since we can call ourselves recursively, keep notes on where we came from */ if (!getenv("_TOP")) setenv("_TOP", Home, 1); if (unpack(pkg_fullname, extract)) { warnx( "unable to extract table of contents file from '%s' - not a package?", pkg_fullname); goto bomb; } cfile = fopen(CONTENTS_FNAME, "r"); if (!cfile) { warnx( "unable to open table of contents file '%s' - not a package?", CONTENTS_FNAME); goto bomb; } read_plist(&Plist, cfile); fclose(cfile); /* Extract directly rather than moving? Oh goodie! */ if (find_plist_option(&Plist, "extract-in-place")) { if (Verbose) printf("Doing in-place extraction for %s\n", pkg_fullname); p = find_plist(&Plist, PLIST_CWD); if (p) { if (!isdir(p->name) && !Fake) { if (Verbose) printf("Desired prefix of %s does not exist, creating..\n", p->name); - vsystem("mkdir -p %s", p->name); + vsystem("/bin/mkdir -p %s", p->name); if (chdir(p->name) == -1) { warn("unable to change directory to '%s'", p->name); goto bomb; } } where_to = p->name; inPlace = 1; } else { warnx( "no prefix specified in '%s' - this is a bad package!", pkg_fullname); goto bomb; } } /* * Apply a crude heuristic to see how much space the package will * take up once it's unpacked. I've noticed that most packages * compress an average of 75%, so multiply by 4 for good measure. */ if (!extract && !inPlace && min_free(playpen) < sb.st_size * 4) { warnx("projected size of %qd exceeds available free space.\n" "Please set your PKG_TMPDIR variable to point to a location with more\n" "free space and try again", (long long)sb.st_size * 4); warnx("not extracting %s\ninto %s, sorry!", pkg_fullname, where_to); goto bomb; } /* If this is a direct extract and we didn't want it, stop now */ if (inPlace && Fake) goto success; /* Finally unpack the whole mess. If extract is null we already + did so so don't bother doing it again. */ if (extract && unpack(pkg_fullname, NULL)) { warnx("unable to extract '%s'!", pkg_fullname); goto bomb; } } /* Check for sanity and dependencies */ if (sanity_check(pkg)) goto bomb; /* If we're running in MASTER mode, just output the plist and return */ if (AddMode == MASTER) { printf("%s\n", where_playpen()); write_plist(&Plist, stdout); return 0; } } /* * If we have a prefix, delete the first one we see and add this * one in place of it. */ if (Prefix) { delete_plist(&Plist, FALSE, PLIST_CWD, NULL); add_plist_top(&Plist, PLIST_CWD, Prefix); } setenv(PKG_PREFIX_VNAME, (p = find_plist(&Plist, PLIST_CWD)) ? p->name : ".", 1); /* Protect against old packages with bogus @name and origin fields */ if (Plist.name == NULL) Plist.name = "anonymous"; if (Plist.origin == NULL) Plist.origin = "anonymous/anonymous"; /* * See if we're already registered either with the same name (the same * version) or some other version with the same origin. */ if ((isinstalledpkg(Plist.name) > 0 || matchbyorigin(Plist.origin, NULL) != NULL) && !Force) { warnx("package '%s' or its older version already installed", Plist.name); code = 1; goto success; /* close enough for government work */ } /* Now check the packing list for conflicts */ for (p = Plist.head; p != NULL; p = p->next) { if (p->type == PLIST_CONFLICTS) { int i; conflict[0] = strdup(p->name); conflict[1] = NULL; matched = matchinstalled(MATCH_GLOB, conflict, &errcode); free(conflict[0]); if (errcode == 0 && matched != NULL) for (i = 0; matched[i] != NULL; i++) if (isinstalledpkg(matched[i]) > 0) { warnx("package '%s' conflicts with %s", Plist.name, matched[i]); conflictsfound = 1; } continue; } } if(conflictsfound) { if(!Force) { warnx("please use pkg_delete first to remove conflicting package(s) or -f to force installation"); code = 1; goto bomb; } else warnx("-f specified; proceeding anyway"); } /* Now check the packing list for dependencies */ for (p = Plist.head; p ; p = p->next) { char *deporigin; if (p->type != PLIST_PKGDEP) continue; deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL; if (Verbose) { printf("Package '%s' depends on '%s'", Plist.name, p->name); if (deporigin != NULL) printf(" with '%s' origin", deporigin); printf(".\n"); } if (isinstalledpkg(p->name) <= 0 && !(deporigin != NULL && matchbyorigin(deporigin, NULL) != NULL)) { char path[FILENAME_MAX], *cp = NULL; if (!Fake) { if (!isURL(pkg) && !getenv("PKG_ADD_BASE")) { const char *ext; ext = strrchr(pkg_fullname, '.'); if (ext == NULL) +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 ext = ".tbz"; +#else + ext = ".tgz"; +#endif snprintf(path, FILENAME_MAX, "%s/%s%s", getenv("_TOP"), p->name, ext); if (fexists(path)) cp = path; else cp = fileFindByPath(pkg, p->name); if (cp) { if (Verbose) printf("Loading it from %s.\n", cp); - if (vsystem("pkg_add %s'%s'", Verbose ? "-v " : "", cp)) { + if (vsystem("%s %s'%s'", PkgAddCmd, Verbose ? "-v " : "", cp)) { warnx("autoload of dependency '%s' failed%s", cp, Force ? " (proceeding anyway)" : "!"); if (!Force) ++code; } } else { warnx("could not find package %s %s", p->name, Force ? " (proceeding anyway)" : "!"); if (!Force) ++code; } } else if ((cp = fileGetURL(pkg, p->name)) != NULL) { if (Verbose) printf("Finished loading %s over FTP.\n", p->name); if (!fexists("+CONTENTS")) { warnx("autoloaded package %s has no +CONTENTS file?", p->name); if (!Force) ++code; } - else if (vsystem("(pwd; cat +CONTENTS) | pkg_add %s-S", Verbose ? "-v " : "")) { + else if (vsystem("(pwd; /bin/cat +CONTENTS) | %s %s-S", PkgAddCmd, Verbose ? "-v " : "")) { warnx("pkg_add of dependency '%s' failed%s", p->name, Force ? " (proceeding anyway)" : "!"); if (!Force) ++code; } else if (Verbose) printf("\t'%s' loaded successfully.\n", p->name); /* Nuke the temporary playpen */ leave_playpen(); } } else { if (Verbose) printf("and was not found%s.\n", Force ? " (proceeding anyway)" : ""); else printf("Package dependency %s for %s not found%s\n", p->name, pkg, Force ? " (proceeding anyway)" : "!"); if (!Force) ++code; } } else if (Verbose) printf(" - already installed.\n"); } if (code != 0) goto bomb; /* Look for the requirements file */ if (fexists(REQUIRE_FNAME)) { - vsystem("chmod +x %s", REQUIRE_FNAME); /* be sure */ + vsystem("/bin/chmod +x %s", REQUIRE_FNAME); /* be sure */ if (Verbose) printf("Running requirements file first for %s..\n", Plist.name); if (!Fake && vsystem("./%s %s INSTALL", REQUIRE_FNAME, Plist.name)) { warnx("package %s fails requirements %s", pkg_fullname, Force ? "installing anyway" : "- not installed"); if (!Force) { code = 1; goto success; /* close enough for government work */ } } } /* * Test whether to use the old method of passing tokens to installation * scripts, and set appropriate variables.. */ if (fexists(POST_INSTALL_FNAME)) { new_m = 1; sprintf(post_script, "%s", POST_INSTALL_FNAME); pre_arg[0] = '\0'; post_arg[0] = '\0'; } else { if (fexists(INSTALL_FNAME)) { sprintf(post_script, "%s", INSTALL_FNAME); sprintf(pre_arg, "PRE-INSTALL"); sprintf(post_arg, "POST-INSTALL"); } } /* If we're really installing, and have an installation file, run it */ if (!NoInstall && fexists(pre_script)) { - vsystem("chmod +x %s", pre_script); /* make sure */ + vsystem("/bin/chmod +x %s", pre_script); /* make sure */ if (Verbose) printf("Running pre-install for %s..\n", Plist.name); if (!Fake && vsystem("./%s %s %s", pre_script, Plist.name, pre_arg)) { warnx("install script returned error status"); unlink(pre_script); code = 1; goto success; /* nothing to uninstall yet */ } } /* Now finally extract the entire show if we're not going direct */ if (!inPlace && !Fake) extract_plist(".", &Plist); if (!Fake && fexists(MTREE_FNAME)) { if (Verbose) printf("Running mtree for %s..\n", Plist.name); p = find_plist(&Plist, PLIST_CWD); if (Verbose) printf("mtree -U -f %s -d -e -p %s >%s\n", MTREE_FNAME, p ? p->name : "/", _PATH_DEVNULL); if (!Fake) { if (vsystem("/usr/sbin/mtree -U -f %s -d -e -p %s >%s", MTREE_FNAME, p ? p->name : "/", _PATH_DEVNULL)) warnx("mtree returned a non-zero status - continuing"); } } /* Run the installation script one last time? */ if (!NoInstall && fexists(post_script)) { - vsystem("chmod +x %s", post_script); /* make sure */ + vsystem("/bin/chmod +x %s", post_script); /* make sure */ if (Verbose) printf("Running post-install for %s..\n", Plist.name); if (!Fake && vsystem("./%s %s %s", post_script, Plist.name, post_arg)) { warnx("install script returned error status"); unlink(post_script); code = 1; goto fail; } } /* Time to record the deed? */ if (!NoRecord && !Fake) { char contents[FILENAME_MAX]; FILE *contfile; if (getuid() != 0) warnx("not running as root - trying to record install anyway"); sprintf(LogDir, "%s/%s", LOG_DIR, Plist.name); zapLogDir = 1; if (Verbose) printf("Attempting to record package into %s..\n", LogDir); if (make_hierarchy(LogDir)) { warnx("can't record package into '%s', you're on your own!", LogDir); bzero(LogDir, FILENAME_MAX); code = 1; goto success; /* close enough for government work */ } /* Make sure pkg_info can read the entry */ - vsystem("chmod a+rx %s", LogDir); + vsystem("/bin/chmod a+rx %s", LogDir); move_file(".", DESC_FNAME, LogDir); move_file(".", COMMENT_FNAME, LogDir); if (fexists(INSTALL_FNAME)) move_file(".", INSTALL_FNAME, LogDir); if (fexists(POST_INSTALL_FNAME)) move_file(".", POST_INSTALL_FNAME, LogDir); if (fexists(DEINSTALL_FNAME)) move_file(".", DEINSTALL_FNAME, LogDir); if (fexists(POST_DEINSTALL_FNAME)) move_file(".", POST_DEINSTALL_FNAME, LogDir); if (fexists(REQUIRE_FNAME)) move_file(".", REQUIRE_FNAME, LogDir); if (fexists(DISPLAY_FNAME)) move_file(".", DISPLAY_FNAME, LogDir); if (fexists(MTREE_FNAME)) move_file(".", MTREE_FNAME, LogDir); sprintf(contents, "%s/%s", LogDir, CONTENTS_FNAME); contfile = fopen(contents, "w"); if (!contfile) { warnx("can't open new contents file '%s'! can't register pkg", contents); goto success; /* can't log, but still keep pkg */ } write_plist(&Plist, contfile); fclose(contfile); for (p = Plist.head; p ; p = p->next) { char *deporigin, **depnames; int i; if (p->type != PLIST_PKGDEP) continue; deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL; if (Verbose) { printf("Trying to record dependency on package '%s'", p->name); if (deporigin != NULL) printf(" with '%s' origin", deporigin); printf(".\n"); } depnames = (deporigin != NULL) ? matchbyorigin(deporigin, NULL) : NULL; if (depnames == NULL) { depnames = alloca(sizeof(*depnames) * 2); depnames[0] = p->name; depnames[1] = NULL; } for (i = 0; depnames[i] != NULL; i++) { sprintf(contents, "%s/%s/%s", LOG_DIR, depnames[i], REQUIRED_BY_FNAME); if (strcmp(p->name, depnames[i]) != 0) warnx("warning: package '%s' requires '%s', but '%s' " "is installed", Plist.name, p->name, depnames[i]); contfile = fopen(contents, "a"); if (!contfile) warnx("can't open dependency file '%s'!\n" "dependency registration is incomplete", contents); else { fprintf(contfile, "%s\n", Plist.name); if (fclose(contfile) == EOF) warnx("cannot properly close file %s", contents); } } } if (Verbose) printf("Package %s registered in %s\n", Plist.name, LogDir); } if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) { FILE *fp; char buf[BUFSIZ]; snprintf(buf, sizeof buf, "%s/%s", LogDir, p->name); fp = fopen(buf, "r"); if (fp) { putc('\n', stdout); while (fgets(buf, sizeof(buf), fp)) fputs(buf, stdout); putc('\n', stdout); (void) fclose(fp); } else warnx("cannot open %s as display file", buf); } goto success; bomb: code = 1; goto success; fail: /* Nuke the whole (installed) show, XXX but don't clean directories */ if (!Fake) delete_package(FALSE, FALSE, &Plist); success: /* delete the packing list contents */ free_plist(&Plist); leave_playpen(); return code; } static int sanity_check(char *pkg) { int code = 0; if (!fexists(CONTENTS_FNAME)) { warnx("package %s has no CONTENTS file!", pkg); code = 1; } else if (!fexists(COMMENT_FNAME)) { warnx("package %s has no COMMENT file!", pkg); code = 1; } else if (!fexists(DESC_FNAME)) { warnx("package %s has no DESC file!", pkg); code = 1; } return code; } void cleanup(int sig) { static int in_cleanup = 0; if (!in_cleanup) { in_cleanup = 1; if (sig) printf("Signal %d received, cleaning up..\n", sig); if (!Fake && zapLogDir && LogDir[0]) vsystem("%s -rf %s", REMOVE_CMD, LogDir); leave_playpen(); } if (sig) exit(1); } Index: head/usr.sbin/pkg_install/create/Makefile =================================================================== --- head/usr.sbin/pkg_install/create/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/create/Makefile (revision 131285) @@ -1,13 +1,14 @@ # $FreeBSD$ PROG= pkg_create SRCS= main.c perform.c pl.c CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib -WARNS?= 2 +WARNS?= 6 +WFORMAT?= 1 DPADD= ${LIBINSTALL} ${LIBMD} LDADD= ${LIBINSTALL} -lmd .include Index: head/usr.sbin/pkg_install/create/create.h =================================================================== --- head/usr.sbin/pkg_install/create/create.h (revision 131284) +++ head/usr.sbin/pkg_install/create/create.h (revision 131285) @@ -1,56 +1,55 @@ /* $FreeBSD$ */ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Include and define various things wanted by the create command. * */ #ifndef _INST_CREATE_H_INCLUDE #define _INST_CREATE_H_INCLUDE extern char *Prefix; extern char *Comment; extern char *Desc; extern char *Display; extern char *Install; extern char *PostInstall; extern char *DeInstall; extern char *PostDeInstall; extern char *Contents; extern char *Require; extern char *SrcDir; extern char *BaseDir; extern char *ExcludeFrom; extern char *Mtree; extern char *Pkgdeps; extern char *Conflicts; extern char *Origin; extern char *InstalledPkg; extern char PlayPen[]; extern int Dereference; extern int PlistOnly; enum zipper {NONE, GZIP, BZIP, BZIP2 }; extern enum zipper Zipper; void add_cksum(Package *, PackingList, const char *); void check_list(const char *, Package *); -int pkg_perform(char **); void copy_plist(const char *, Package *); #endif /* _INST_CREATE_H_INCLUDE */ Index: head/usr.sbin/pkg_install/create/pl.c =================================================================== --- head/usr.sbin/pkg_install/create/pl.c (revision 131284) +++ head/usr.sbin/pkg_install/create/pl.c (revision 131285) @@ -1,273 +1,273 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Routines for dealing with the packing list. * */ #include __FBSDID("$FreeBSD$"); #include "lib.h" #include "create.h" #include #include #include /* Add an MD5 checksum entry for a file or link */ void add_cksum(Package *pkg, PackingList p, const char *fname) { char *cp = NULL, buf[33]; if (issymlink(fname)) { int len; char lnk[FILENAME_MAX]; if ((len = readlink(fname, lnk, FILENAME_MAX)) > 0) cp = MD5Data((unsigned char *)lnk, len, buf); } else if (isfile(fname)) { /* Don't record MD5 checksum for device nodes and such */ cp = MD5File(fname, buf); } if (cp != NULL) { PackingList tmp = new_plist_entry(); tmp->name = copy_string(strconcat("MD5:", cp)); tmp->type = PLIST_COMMENT; tmp->next = p->next; tmp->prev = p; p->next = tmp; if (pkg->tail == p) pkg->tail = tmp; } } /* Check a list for files that require preconversion */ void check_list(const char *home, Package *pkg) { const char *where = home; const char *there = NULL; char name[FILENAME_MAX]; PackingList p; for (p = pkg->head; p != NULL; p = p->next) switch (p->type) { case PLIST_CWD: where = p->name; break; case PLIST_IGNORE: p = p->next; break; case PLIST_SRC: there = p->name; break; case PLIST_FILE: if (there) snprintf(name, sizeof(name), "%s/%s", there, p->name); else snprintf(name, sizeof(name), "%s%s/%s", BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name); add_cksum(pkg, p, name); break; default: break; } } static int trylink(const char *from, const char *to) { if (link(from, to) == 0) return 0; if (errno == ENOENT) { /* try making the container directory */ char *cp = strrchr(to, '/'); if (cp) - vsystem("mkdir -p %.*s", cp - to, + vsystem("/bin/mkdir -p %.*s", cp - to, to); return link(from, to); } return -1; } -#define STARTSTRING "tar cf -" +#define STARTSTRING "/usr/bin/tar cf -" #define TOOBIG(str) (int)strlen(str) + 6 + (int)strlen(home) + where_count > maxargs #define PUSHOUT() /* push out string */ \ if (where_count > (int)sizeof(STARTSTRING)-1) { \ - strcat(where_args, "|tar xpf -"); \ + strcat(where_args, "|/usr/bin/tar xpf -"); \ if (system(where_args)) { \ cleanup(0); \ errx(2, "%s: can't invoke tar pipeline", __func__); \ } \ memset(where_args, 0, maxargs); \ last_chdir = NULL; \ strcpy(where_args, STARTSTRING); \ where_count = sizeof(STARTSTRING)-1; \ } /* * Copy unmarked files in packing list to playpen - marked files * have already been copied in an earlier pass through the list. */ void copy_plist(const char *home, Package *plist) { PackingList p = plist->head; const char *where = home; const char *there = NULL, *mythere; char *where_args; const char *last_chdir, *root = "/"; int maxargs, where_count = 0, add_count; struct stat stb; dev_t curdir; maxargs = sysconf(_SC_ARG_MAX); maxargs -= 64; /* * Some slop for the tar cmd text, * and sh -c */ where_args = malloc(maxargs); if (!where_args) { cleanup(0); errx(2, "%s: can't get argument list space", __func__); } memset(where_args, 0, maxargs); strcpy(where_args, STARTSTRING); where_count = sizeof(STARTSTRING)-1; last_chdir = 0; if (stat(".", &stb) == 0) curdir = stb.st_dev; else curdir = (dev_t) -1; /* * It's ok if this is a valid dev_t; * this is just a hint for an * optimization. */ while (p) { if (p->type == PLIST_CWD) where = p->name; else if (p->type == PLIST_SRC) there = p->name; else if (p->type == PLIST_IGNORE) p = p->next; else if (p->type == PLIST_FILE && !p->marked) { char fn[FILENAME_MAX]; /* First, look for it in the "home" dir */ sprintf(fn, "%s/%s", home, p->name); if (fexists(fn)) { if (lstat(fn, &stb) == 0 && stb.st_dev == curdir && S_ISREG(stb.st_mode)) { /* * If we can link it to the playpen, that avoids a copy * and saves time. */ if (p->name[0] != '/') { /* * Don't link abspn stuff--it doesn't come from * local dir! */ if (trylink(fn, p->name) == 0) { p = p->next; continue; } } } if (TOOBIG(fn)) { PUSHOUT(); } if (p->name[0] == '/') { add_count = snprintf(&where_args[where_count], maxargs - where_count, " %s %s", last_chdir == root ? "" : "-C /", p->name); last_chdir = root; } else { add_count = snprintf(&where_args[where_count], maxargs - where_count, " %s%s %s", last_chdir == home ? "" : "-C ", last_chdir == home ? "" : home, p->name); last_chdir = home; } if (add_count < 0 || add_count >= maxargs - where_count) { cleanup(0); errx(2, "%s: oops, miscounted strings!", __func__); } where_count += add_count; } /* * Otherwise, try along the actual extraction path.. */ else { if (p->name[0] == '/') mythere = root; else mythere = there; if (mythere) snprintf(fn, sizeof(fn), "%s/%s", mythere, p->name); else snprintf(fn, sizeof(fn), "%s%s/%s", BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name); if (lstat(fn, &stb) == 0 && stb.st_dev == curdir && S_ISREG(stb.st_mode)) { /* * If we can link it to the playpen, that avoids a copy * and saves time. */ if (trylink(fn, p->name) == 0) { p = p->next; continue; } } if (TOOBIG(p->name)) { PUSHOUT(); } if (last_chdir == (mythere ? mythere : where)) add_count = snprintf(&where_args[where_count], maxargs - where_count, " %s", p->name); else add_count = snprintf(&where_args[where_count], maxargs - where_count, " -C %s %s", mythere ? mythere : where, p->name); if (add_count < 0 || add_count >= maxargs - where_count) { cleanup(0); errx(2, "%s: oops, miscounted strings!", __func__); } where_count += add_count; last_chdir = (mythere ? mythere : where); } } p = p->next; } PUSHOUT(); free(where_args); } Index: head/usr.sbin/pkg_install/delete/Makefile =================================================================== --- head/usr.sbin/pkg_install/delete/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/delete/Makefile (revision 131285) @@ -1,13 +1,14 @@ # $FreeBSD$ PROG= pkg_delete SRCS= main.c perform.c CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib -WARNS?= 4 +WARNS?= 6 +WFORMAT?= 1 DPADD= ${LIBINSTALL} ${LIBMD} LDADD= ${LIBINSTALL} -lmd .include Index: head/usr.sbin/pkg_install/delete/delete.h =================================================================== --- head/usr.sbin/pkg_install/delete/delete.h (revision 131284) +++ head/usr.sbin/pkg_install/delete/delete.h (revision 131285) @@ -1,36 +1,35 @@ /* $FreeBSD$ */ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Include and define various things wanted by the delete command. * */ #ifndef _INST_DELETE_H_INCLUDE #define _INST_DELETE_H_INCLUDE extern char *Prefix; extern Boolean CleanDirs; extern Boolean Interactive; extern Boolean NoDeInstall; -extern Boolean Force; extern Boolean Recursive; extern char *Directory; extern char *PkgName; extern match_t MatchType; #endif /* _INST_DELETE_H_INCLUDE */ Index: head/usr.sbin/pkg_install/delete/perform.c =================================================================== --- head/usr.sbin/pkg_install/delete/perform.c (revision 131284) +++ head/usr.sbin/pkg_install/delete/perform.c (revision 131285) @@ -1,398 +1,398 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * This is the main body of the delete module. * */ #include __FBSDID("$FreeBSD$"); #include #include "lib.h" #include "delete.h" static int pkg_do(char *); static void sanity_check(char *); static void undepend(char *, char *); static char LogDir[FILENAME_MAX]; int pkg_perform(char **pkgs) { char **matched, **rb, **rbtmp; int errcode, i, j; int err_cnt = 0; struct reqr_by_entry *rb_entry; struct reqr_by_head *rb_list; if (MatchType != MATCH_EXACT) { matched = matchinstalled(MatchType, pkgs, &errcode); if (errcode != 0) return 1; /* Not reached */ /* * Copy matched[] into pkgs[], because we'll need to use * matchinstalled() later on. */ if (matched != NULL) { pkgs = NULL; for (i = 0; matched[i] != NULL; i++) { pkgs = realloc(pkgs, sizeof(*pkgs) * (i + 2)); pkgs[i] = strdup(matched[i]); } pkgs[i] = NULL; } else switch (MatchType) { case MATCH_GLOB: break; case MATCH_ALL: warnx("no packages installed"); return 0; case MATCH_EREGEX: case MATCH_REGEX: warnx("no packages match pattern(s)"); return 1; default: break; } } err_cnt += sortdeps(pkgs); for (i = 0; pkgs[i]; i++) { if (Recursive == TRUE) { errcode = requiredby(pkgs[i], &rb_list, FALSE, TRUE); if (errcode < 0) { err_cnt++; } else if (errcode > 0) { /* * Copy values from the rb_list queue into argv-like NULL * terminated list because requiredby() uses some static * storage, while pkg_do() below will call this function, * thus blowing our rb_list away. */ rbtmp = rb = alloca((errcode + 1) * sizeof(*rb)); if (rb == NULL) { warnx("%s(): alloca() failed", __func__); err_cnt++; continue; } STAILQ_FOREACH(rb_entry, rb_list, link) { *rbtmp = alloca(strlen(rb_entry->pkgname) + 1); if (*rbtmp == NULL) { warnx("%s(): alloca() failed", __func__); err_cnt++; continue; } strcpy(*rbtmp, rb_entry->pkgname); rbtmp++; } *rbtmp = NULL; err_cnt += sortdeps(rb); for (j = 0; rb[j]; j++) err_cnt += pkg_do(rb[j]); } } err_cnt += pkg_do(pkgs[i]); } return err_cnt; } static Package Plist; /* This is seriously ugly code following. Written very fast! */ static int pkg_do(char *pkg) { FILE *cfile; char *deporigin, **depnames, home[FILENAME_MAX]; PackingList p; int i, len; int isinstalled; /* support for separate pre/post install scripts */ int new_m = 0; const char *pre_script = DEINSTALL_FNAME; const char *post_script, *pre_arg, *post_arg; struct reqr_by_entry *rb_entry; struct reqr_by_head *rb_list; if (!pkg || !(len = strlen(pkg))) return 1; if (pkg[len - 1] == '/') pkg[len - 1] = '\0'; /* Reset some state */ if (Plist.head) free_plist(&Plist); sprintf(LogDir, "%s/%s", LOG_DIR, pkg); isinstalled = isinstalledpkg(pkg); if (isinstalled == 0) { warnx("no such package '%s' installed", pkg); return 1; } else if (isinstalled < 0) { warnx("the package info for package '%s' is corrupt%s", pkg, Force ? " (but I'll delete it anyway)" : " (use -f to force removal)"); if (!Force) return 1; if (!Fake) { if (vsystem("%s -rf %s", REMOVE_CMD, LogDir)) { warnx("couldn't remove log entry in %s, deinstall failed", LogDir); } else { warnx("couldn't completely deinstall package '%s',\n" "only the log entry in %s was removed", pkg, LogDir); } } return 0; } if (!getcwd(home, FILENAME_MAX)) { cleanup(0); errx(2, "%s: unable to get current working directory!", __func__); } if (chdir(LogDir) == FAIL) { warnx("unable to change directory to %s! deinstall failed", LogDir); return 1; } if (Interactive == TRUE) { int first, ch; (void)fprintf(stderr, "delete %s? ", pkg); (void)fflush(stderr); first = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); if (first != 'y' && first != 'Y') return 0; /* Not reached */ } if (requiredby(pkg, &rb_list, FALSE, TRUE) < 0) return 1; if (!STAILQ_EMPTY(rb_list)) { warnx("package '%s' is required by these other packages\n" "and may not be deinstalled%s:", pkg, Force ? " (but I'll delete it anyway)" : ""); STAILQ_FOREACH(rb_entry, rb_list, link) fprintf(stderr, "%s\n", rb_entry->pkgname); if (!Force) return 1; } sanity_check(LogDir); cfile = fopen(CONTENTS_FNAME, "r"); if (!cfile) { warnx("unable to open '%s' file", CONTENTS_FNAME); return 1; } /* If we have a prefix, add it now */ if (Prefix) add_plist(&Plist, PLIST_CWD, Prefix); read_plist(&Plist, cfile); fclose(cfile); p = find_plist(&Plist, PLIST_CWD); if (!p) { warnx("package '%s' doesn't have a prefix", pkg); return 1; } setenv(PKG_PREFIX_VNAME, p->name, 1); if (fexists(REQUIRE_FNAME)) { if (Verbose) printf("Executing 'require' script.\n"); - vsystem("chmod +x %s", REQUIRE_FNAME); /* be sure */ + vsystem("/bin/chmod +x %s", REQUIRE_FNAME); /* be sure */ if (vsystem("./%s %s DEINSTALL", REQUIRE_FNAME, pkg)) { warnx("package %s fails requirements %s", pkg, Force ? "" : "- not deleted"); if (!Force) return 1; } } /* * Test whether to use the old method of passing tokens to deinstallation * scripts, and set appropriate variables.. */ if (fexists(POST_DEINSTALL_FNAME)) { new_m = 1; post_script = POST_DEINSTALL_FNAME; pre_arg = post_arg = ""; } else if (fexists(DEINSTALL_FNAME)) { post_script = DEINSTALL_FNAME; pre_arg = "DEINSTALL"; post_arg = "POST-DEINSTALL"; } else { post_script = pre_arg = post_arg = NULL; } if (!NoDeInstall && pre_script != NULL && fexists(pre_script)) { if (Fake) printf("Would execute de-install script at this point.\n"); else { - vsystem("chmod +x %s", pre_script); /* make sure */ + vsystem("/bin/chmod +x %s", pre_script); /* make sure */ if (vsystem("./%s %s %s", pre_script, pkg, pre_arg)) { warnx("deinstall script returned error status"); if (!Force) return 1; } } } for (p = Plist.head; p ; p = p->next) { if (p->type != PLIST_PKGDEP) continue; deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL; if (Verbose) { printf("Trying to remove dependency on package '%s'", p->name); if (deporigin != NULL) printf(" with '%s' origin", deporigin); printf(".\n"); } if (!Fake) { depnames = (deporigin != NULL) ? matchbyorigin(deporigin, NULL) : NULL; if (depnames == NULL) { depnames = alloca(sizeof(*depnames) * 2); depnames[0] = p->name; depnames[1] = NULL; } for (i = 0; depnames[i] != NULL; i++) undepend(depnames[i], pkg); } } if (chdir(home) == FAIL) { cleanup(0); errx(2, "%s: unable to return to working directory %s!", __func__, home); } /* * Some packages aren't packed right, so we need to just ignore * delete_package()'s status. Ugh! :-( */ if (delete_package(FALSE, CleanDirs, &Plist) == FAIL) warnx( "couldn't entirely delete package (perhaps the packing list is\n" "incorrectly specified?)"); if (chdir(LogDir) == FAIL) { warnx("unable to change directory to %s! deinstall failed", LogDir); return 1; } if (!NoDeInstall && post_script != NULL && fexists(post_script)) { if (Fake) printf("Would execute post-deinstall script at this point.\n"); else { - vsystem("chmod +x %s", post_script); /* make sure */ + vsystem("/bin/chmod +x %s", post_script); /* make sure */ if (vsystem("./%s %s %s", post_script, pkg, post_arg)) { warnx("post-deinstall script returned error status"); if (!Force) return 1; } } } if (chdir(home) == FAIL) { cleanup(0); errx(2, "%s: unable to return to working directory %s!", __func__, home); } if (!Fake) { if (vsystem("%s -r%c %s", REMOVE_CMD, Force ? 'f' : ' ', LogDir)) { warnx("couldn't remove log entry in %s, deinstall failed", LogDir); if (!Force) return 1; } } return 0; } static void sanity_check(char *pkg) { if (!fexists(CONTENTS_FNAME)) { cleanup(0); errx(2, "%s: installed package %s has no %s file!", __func__, pkg, CONTENTS_FNAME); } } void cleanup(int sig) { if (sig) exit(1); } static void undepend(char *p, char *pkgname) { char fname[FILENAME_MAX], ftmp[FILENAME_MAX]; FILE *fpwr; int s; struct reqr_by_entry *rb_entry; struct reqr_by_head *rb_list; if (requiredby(p, &rb_list, Verbose, FALSE) <= 0) return; snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, p, REQUIRED_BY_FNAME); snprintf(ftmp, sizeof(ftmp), "%s.XXXXXX", fname); s = mkstemp(ftmp); if (s == -1) { warnx("couldn't open temp file '%s'", ftmp); return; } fpwr = fdopen(s, "w"); if (fpwr == NULL) { close(s); warnx("couldn't fdopen temp file '%s'", ftmp); goto cleanexit; } STAILQ_FOREACH(rb_entry, rb_list, link) if (strcmp(rb_entry->pkgname, pkgname)) /* no match */ fputs(rb_entry->pkgname, fpwr), putc('\n', fpwr); if (fchmod(s, 0644) == FAIL) { warnx("error changing permission of temp file '%s'", ftmp); fclose(fpwr); goto cleanexit; } if (fclose(fpwr) == EOF) { warnx("error closing temp file '%s'", ftmp); goto cleanexit; } if (rename(ftmp, fname) == -1) warnx("error renaming '%s' to '%s'", ftmp, fname); cleanexit: remove(ftmp); return; } Index: head/usr.sbin/pkg_install/info/Makefile =================================================================== --- head/usr.sbin/pkg_install/info/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/info/Makefile (revision 131285) @@ -1,13 +1,14 @@ # $FreeBSD$ PROG= pkg_info SRCS= main.c perform.c show.c CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib -WARNS?= 2 +WARNS?= 6 +WFORMAT?= 1 DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} LDADD= ${LIBINSTALL} -lfetch -lmd .include Index: head/usr.sbin/pkg_install/lib/Makefile =================================================================== --- head/usr.sbin/pkg_install/lib/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/lib/Makefile (revision 131285) @@ -1,12 +1,13 @@ # $FreeBSD$ LIB= install INTERNALLIB= YES SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c match.c \ deps.c version.c pkgwrap.c url.c CFLAGS+= ${DEBUG} -WARNS?= 2 +WARNS?= 6 +WFORMAT?= 1 .include Index: head/usr.sbin/pkg_install/lib/file.c =================================================================== --- head/usr.sbin/pkg_install/lib/file.c (revision 131284) +++ head/usr.sbin/pkg_install/lib/file.c (revision 131285) @@ -1,428 +1,431 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Miscellaneous file access utilities. * */ #include __FBSDID("$FreeBSD$"); #include "lib.h" #include #include #include #include /* Quick check to see if a file exists */ Boolean fexists(const char *fname) { struct stat dummy; if (!lstat(fname, &dummy)) return TRUE; return FALSE; } /* Quick check to see if something is a directory or symlink to a directory */ Boolean isdir(const char *fname) { struct stat sb; if (lstat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode)) return TRUE; else if (lstat(strconcat(fname, "/."), &sb) != FAIL && S_ISDIR(sb.st_mode)) return TRUE; else return FALSE; } /* Check to see if file is a dir or symlink to a dir, and is empty */ Boolean isemptydir(const char *fname) { if (isdir(fname)) { DIR *dirp; struct dirent *dp; dirp = opendir(fname); if (!dirp) return FALSE; /* no perms, leave it alone */ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) { closedir(dirp); return FALSE; } } (void)closedir(dirp); return TRUE; } return FALSE; } /* * Returns TRUE if file is a regular file or symlink pointing to a regular * file */ Boolean isfile(const char *fname) { struct stat sb; if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode)) return TRUE; return FALSE; } /* * Check to see if file is a file or symlink pointing to a file and is empty. * If nonexistent or not a file, say "it's empty", otherwise return TRUE if * zero sized. */ Boolean isemptyfile(const char *fname) { struct stat sb; if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode)) { if (sb.st_size != 0) return FALSE; } return TRUE; } /* Returns TRUE if file is a symbolic link. */ Boolean issymlink(const char *fname) { struct stat sb; if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode)) return TRUE; return FALSE; } /* Returns TRUE if file is a URL specification */ Boolean isURL(const char *fname) { /* * I'm sure there are other types of URL specifications that I could * also be looking for here, but for now I'll just be happy to get ftp * and http working. */ if (!fname) return FALSE; while (isspace(*fname)) ++fname; if (!strncmp(fname, "ftp://", 6) || !strncmp(fname, "http://", 7) || !strncmp(fname, "https://", 8) || !strncmp(fname, "file://", 7)) return TRUE; return FALSE; } char * fileFindByPath(const char *base, const char *fname) { static char tmp[FILENAME_MAX]; char *cp; const char *suffixes[] = {".tbz", ".tgz", ".tar", NULL}; int i; if (fexists(fname) && isfile(fname)) { strcpy(tmp, fname); return tmp; } if (base) { strcpy(tmp, base); cp = strrchr(tmp, '/'); if (cp) { *cp = '\0'; /* chop name */ cp = strrchr(tmp, '/'); } if (cp) for (i = 0; suffixes[i] != NULL; i++) { *(cp + 1) = '\0'; strcat(cp, "All/"); strcat(cp, fname); strcat(cp, suffixes[i]); if (fexists(tmp)) return tmp; } } cp = getenv("PKG_PATH"); while (cp) { char *cp2 = strsep(&cp, ":"); for (i = 0; suffixes[i] != NULL; i++) { snprintf(tmp, FILENAME_MAX, "%s/%s%s", cp2 ? cp2 : cp, fname, suffixes[i]); if (fexists(tmp) && isfile(tmp)) return tmp; } } return NULL; } char * fileGetContents(const char *fname) { char *contents; struct stat sb; int fd; if (stat(fname, &sb) == FAIL) { cleanup(0); errx(2, "%s: can't stat '%s'", __func__, fname); } contents = (char *)malloc(sb.st_size + 1); fd = open(fname, O_RDONLY, 0); if (fd == FAIL) { cleanup(0); errx(2, "%s: unable to open '%s' for reading", __func__, fname); } if (read(fd, contents, sb.st_size) != sb.st_size) { cleanup(0); errx(2, "%s: short read on '%s' - did not get %qd bytes", __func__, fname, (long long)sb.st_size); } close(fd); contents[sb.st_size] = '\0'; return contents; } /* * Takes a filename and package name, returning (in "try") the * canonical "preserve" name for it. */ Boolean make_preserve_name(char *try, int max, const char *name, const char *file) { int len, i; if ((len = strlen(file)) == 0) return FALSE; else i = len - 1; strncpy(try, file, max); if (try[i] == '/') /* Catch trailing slash early and save checking in the loop */ --i; for (; i; i--) { if (try[i] == '/') { try[i + 1]= '.'; strncpy(&try[i + 2], &file[i + 1], max - i - 2); break; } } if (!i) { try[0] = '.'; strncpy(try + 1, file, max - 1); } /* I should probably be called rude names for these inline assignments */ strncat(try, ".", max -= strlen(try)); strncat(try, name, max -= strlen(name)); strncat(try, ".", max--); strncat(try, "backup", max -= 6); return TRUE; } /* Write the contents of "str" to a file */ void write_file(const char *name, const char *str) { FILE *fp; size_t len; fp = fopen(name, "w"); if (!fp) { cleanup(0); errx(2, "%s: cannot fopen '%s' for writing", __func__, name); } len = strlen(str); if (fwrite(str, 1, len, fp) != len) { cleanup(0); errx(2, "%s: short fwrite on '%s', tried to write %ld bytes", __func__, name, (long)len); } if (fclose(fp)) { cleanup(0); errx(2, "%s: failure to fclose '%s'", __func__, name); } } void copy_file(const char *dir, const char *fname, const char *to) { char cmd[FILENAME_MAX]; if (fname[0] == '/') - snprintf(cmd, FILENAME_MAX, "cp -r %s %s", fname, to); + snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s %s", fname, to); else - snprintf(cmd, FILENAME_MAX, "cp -r %s/%s %s", dir, fname, to); + snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s/%s %s", dir, fname, to); if (vsystem(cmd)) { cleanup(0); errx(2, "%s: could not perform '%s'", __func__, cmd); } } void move_file(const char *dir, const char *fname, const char *to) { char cmd[FILENAME_MAX]; if (fname[0] == '/') - snprintf(cmd, FILENAME_MAX, "mv %s %s", fname, to); + snprintf(cmd, FILENAME_MAX, "/bin/mv %s %s", fname, to); else - snprintf(cmd, FILENAME_MAX, "mv %s/%s %s", dir, fname, to); + snprintf(cmd, FILENAME_MAX, "/bin/mv %s/%s %s", dir, fname, to); if (vsystem(cmd)) { cleanup(0); errx(2, "%s: could not perform '%s'", __func__, cmd); } } /* * Copy a hierarchy (possibly from dir) to the current directory, or * if "to" is TRUE, from the current directory to a location someplace * else. * * Though slower, using tar to copy preserves symlinks and everything * without me having to write some big hairy routine to do it. */ void copy_hierarchy(const char *dir, const char *fname, Boolean to) { char cmd[FILENAME_MAX * 3]; if (!to) { /* If absolute path, use it */ if (*fname == '/') dir = "/"; - snprintf(cmd, FILENAME_MAX * 3, "tar cf - -C %s %s | tar xpf -", + snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -", dir, fname); } else - snprintf(cmd, FILENAME_MAX * 3, "tar cf - %s | tar xpf - -C %s", + snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - %s | /usr/bin/tar xpf - -C %s", fname, dir); #ifdef DEBUG printf("Using '%s' to copy trees.\n", cmd); #endif if (system(cmd)) { cleanup(0); errx(2, "%s: could not perform '%s'", __func__, cmd); } } /* Unpack a tar file */ int unpack(const char *pkg, const char *flist) { const char *comp, *cp; char suff[80]; comp = ""; /* * Figure out by a crude heuristic whether this or not this is probably * compressed and whichever compression utility was used (gzip or bzip2). */ if (strcmp(pkg, "-")) { cp = strrchr(pkg, '.'); if (cp) { strcpy(suff, cp + 1); if (strchr(suff, 'z') || strchr(suff, 'Z')) { if (strchr(suff, 'b')) comp = "-j"; else comp = "-z"; } } } else - /* XXX: need to handle .tgz also */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 comp = "-j"; - if (vsystem("tar -xp %s -f '%s' %s", comp, pkg, flist ? flist : "")) { +#else + comp = "-z"; +#endif + if (vsystem("/usr/bin/tar -xp %s -f '%s' %s", comp, pkg, flist ? flist : "")) { warnx("tar extract of %s failed!", pkg); return 1; } return 0; } /* * Using fmt, replace all instances of: * * %F With the parameter "name" * %D With the parameter "dir" * %B Return the directory part ("base") of %D/%F * %f Return the filename part of %D/%F * * Does not check for overflow - caution! * */ void format_cmd(char *buf, int max, const char *fmt, const char *dir, const char *name) { char *cp, scratch[FILENAME_MAX * 2]; int l; while (*fmt && max > 0) { if (*fmt == '%') { switch (*++fmt) { case 'F': strncpy(buf, name, max); l = strlen(name); buf += l, max -= l; break; case 'D': strncpy(buf, dir, max); l = strlen(dir); buf += l, max -= l; break; case 'B': snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name); cp = &scratch[strlen(scratch) - 1]; while (cp != scratch && *cp != '/') --cp; *cp = '\0'; strncpy(buf, scratch, max); l = strlen(scratch); buf += l, max -= l; break; case 'f': snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name); cp = &scratch[strlen(scratch) - 1]; while (cp != scratch && *(cp - 1) != '/') --cp; strncpy(buf, cp, max); l = strlen(cp); buf += l, max -= l; break; default: *buf++ = *fmt; --max; break; } ++fmt; } else { *buf++ = *fmt++; --max; } } *buf = '\0'; } Index: head/usr.sbin/pkg_install/lib/lib.h =================================================================== --- head/usr.sbin/pkg_install/lib/lib.h (revision 131284) +++ head/usr.sbin/pkg_install/lib/lib.h (revision 131285) @@ -1,226 +1,232 @@ /* $FreeBSD$ */ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Include and define various things wanted by the library routines. * */ #ifndef _INST_LIB_LIB_H_ #define _INST_LIB_LIB_H_ /* Includes */ #include #include #include #include #include #include #include #include #include #include #include /* Macros */ #define SUCCESS (0) #define FAIL (-1) #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #define YES 2 #define NO 1 /* Usually "rm", but often "echo" during debugging! */ -#define REMOVE_CMD "rm" +#define REMOVE_CMD "/bin/rm" /* Usually "rm", but often "echo" during debugging! */ -#define RMDIR_CMD "rmdir" +#define RMDIR_CMD "/bin/rmdir" /* Where we put logging information by default, else ${PKG_DBDIR} if set */ #define DEF_LOG_DIR "/var/db/pkg" /* just in case we change the environment variable name */ #define PKG_DBDIR "PKG_DBDIR" /* macro to get name of directory where we put logging information */ #define LOG_DIR (getenv(PKG_DBDIR) ? getenv(PKG_DBDIR) : DEF_LOG_DIR) /* The names of our "special" files */ #define CONTENTS_FNAME "+CONTENTS" #define COMMENT_FNAME "+COMMENT" #define DESC_FNAME "+DESC" #define INSTALL_FNAME "+INSTALL" #define POST_INSTALL_FNAME "+POST-INSTALL" #define DEINSTALL_FNAME "+DEINSTALL" #define POST_DEINSTALL_FNAME "+POST-DEINSTALL" #define REQUIRE_FNAME "+REQUIRE" #define REQUIRED_BY_FNAME "+REQUIRED_BY" #define DISPLAY_FNAME "+DISPLAY" #define MTREE_FNAME "+MTREE_DIRS" +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500036 +#define INDEX_FNAME "INDEX-5" +#else +#define INDEX_FNAME "INDEX" +#endif + #define CMD_CHAR '@' /* prefix for extended PLIST cmd */ /* The name of the "prefix" environment variable given to scripts */ #define PKG_PREFIX_VNAME "PKG_PREFIX" /* * Version of the package tools - increase only when some * functionality used by bsd.port.mk is changed, added or removed */ -#define PKG_INSTALL_VERSION 20030417 +#define PKG_INSTALL_VERSION 20040629 #define PKG_WRAPCONF_FNAME "/var/db/pkg_install.conf" #define main(argc, argv) real_main(argc, argv) /* Version numbers to assist with changes in package file format */ #define PLIST_FMT_VER_MAJOR 1 #define PLIST_FMT_VER_MINOR 1 enum _plist_t { PLIST_FILE, PLIST_CWD, PLIST_CMD, PLIST_CHMOD, PLIST_CHOWN, PLIST_CHGRP, PLIST_COMMENT, PLIST_IGNORE, PLIST_NAME, PLIST_UNEXEC, PLIST_SRC, PLIST_DISPLAY, PLIST_PKGDEP, PLIST_CONFLICTS, PLIST_MTREE, PLIST_DIR_RM, PLIST_IGNORE_INST, PLIST_OPTION, PLIST_ORIGIN, PLIST_DEPORIGIN }; typedef enum _plist_t plist_t; enum _match_t { MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_NGLOB, MATCH_EREGEX, MATCH_REGEX }; typedef enum _match_t match_t; /* Types */ typedef unsigned int Boolean; struct _plist { struct _plist *prev, *next; char *name; Boolean marked; plist_t type; }; typedef struct _plist *PackingList; struct _pack { struct _plist *head, *tail; const char *name; const char *origin; int fmtver_maj, fmtver_mnr; }; typedef struct _pack Package; struct reqr_by_entry { STAILQ_ENTRY(reqr_by_entry) link; char pkgname[PATH_MAX]; }; STAILQ_HEAD(reqr_by_head, reqr_by_entry); /* Prototypes */ /* Misc */ int vsystem(const char *, ...); char *vpipe(const char *, ...); void cleanup(int); char *make_playpen(char *, off_t); char *where_playpen(void); void leave_playpen(void); off_t min_free(const char *); /* String */ char *get_dash_string(char **); char *copy_string(const char *); char *copy_string_adds_newline(const char *); Boolean suffix(const char *, const char *); void nuke_suffix(char *); void str_lowercase(char *); char *strconcat(const char *, const char *); char *get_string(char *, int, FILE *); /* File */ Boolean fexists(const char *); Boolean isdir(const char *); Boolean isemptydir(const char *fname); Boolean isemptyfile(const char *fname); Boolean isfile(const char *); Boolean isempty(const char *); Boolean issymlink(const char *); Boolean isURL(const char *); char *fileGetURL(const char *, const char *); char *fileFindByPath(const char *, const char *); char *fileGetContents(const char *); void write_file(const char *, const char *); void copy_file(const char *, const char *, const char *); void move_file(const char *, const char *, const char *); void copy_hierarchy(const char *, const char *, Boolean); int delete_hierarchy(const char *, Boolean, Boolean); int unpack(const char *, const char *); void format_cmd(char *, int, const char *, const char *, const char *); /* Msg */ void upchuck(const char *); void barf(const char *, ...); void whinge(const char *, ...); Boolean y_or_n(Boolean, const char *, ...); /* Packing list */ PackingList new_plist_entry(void); PackingList last_plist(Package *); PackingList find_plist(Package *, plist_t); char *find_plist_option(Package *, const char *name); void plist_delete(Package *, Boolean, plist_t, const char *); void free_plist(Package *); void mark_plist(Package *); void csum_plist_entry(char *, PackingList); void add_plist(Package *, plist_t, const char *); void add_plist_top(Package *, plist_t, const char *); void delete_plist(Package *pkg, Boolean all, plist_t type, const char *name); void write_plist(Package *, FILE *); void read_plist(Package *, FILE *); int plist_cmd(const char *, char **); int delete_package(Boolean, Boolean, Package *); Boolean make_preserve_name(char *, int, const char *, const char *); /* For all */ int pkg_perform(char **); int real_main(int, char **); /* Query installed packages */ char **matchinstalled(match_t, char **, int *); char **matchbyorigin(const char *, int *); int isinstalledpkg(const char *name); int pattern_match(match_t MatchType, char *pattern, const char *pkgname); /* Dependencies */ int sortdeps(char **); int chkifdepends(const char *, const char *); int requiredby(const char *, struct reqr_by_head **, Boolean, Boolean); /* Version */ int verscmp(Package *, int, int); int version_cmp(const char *, const char *); /* Externs */ extern Boolean Verbose; extern Boolean Fake; extern Boolean Force; extern int AutoAnswer; #endif /* _INST_LIB_LIB_H_ */ Index: head/usr.sbin/pkg_install/lib/match.c =================================================================== --- head/usr.sbin/pkg_install/lib/match.c (revision 131284) +++ head/usr.sbin/pkg_install/lib/match.c (revision 131285) @@ -1,516 +1,516 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Maxim Sobolev * 24 February 2001 * * Routines used to query installed packages. * */ #include __FBSDID("$FreeBSD$"); #include "lib.h" #include #include #include #include /* * Simple structure representing argv-like * NULL-terminated list. */ struct store { int currlen; int used; char **store; }; static int rex_match(const char *, const char *, int); static int csh_match(const char *, const char *, int); struct store *storecreate(struct store *); static int storeappend(struct store *, const char *); static int fname_cmp(const FTSENT * const *, const FTSENT * const *); /* * Function to query names of installed packages. * MatchType - one of MATCH_ALL, MATCH_EREGEX, MATCH_REGEX, MATCH_GLOB, MATCH_NGLOB; * patterns - NULL-terminated list of glob or regex patterns * (could be NULL for MATCH_ALL); * retval - return value (could be NULL if you don't want/need * return value). * Returns NULL-terminated list with matching names. * Names in list returned are dynamically allocated and should * not be altered by the caller. */ char ** matchinstalled(match_t MatchType, char **patterns, int *retval) { int i, errcode, len; char *matched; const char *paths[2] = {LOG_DIR, NULL}; static struct store *store = NULL; FTS *ftsp; FTSENT *f; - Boolean *lmatched; + Boolean *lmatched = NULL; store = storecreate(store); if (store == NULL) { if (retval != NULL) *retval = 1; return NULL; } if (retval != NULL) *retval = 0; if (!isdir(paths[0])) { if (retval != NULL) *retval = 1; return NULL; /* Not reached */ } /* Count number of patterns */ if (patterns != NULL) { for (len = 0; patterns[len]; len++) {} lmatched = alloca(sizeof(*lmatched) * len); if (lmatched == NULL) { warnx("%s(): alloca() failed", __func__); if (retval != NULL) *retval = 1; return NULL; } } else len = 0; for (i = 0; i < len; i++) lmatched[i] = FALSE; ftsp = fts_open((char * const *)(uintptr_t)paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp); if (ftsp != NULL) { while ((f = fts_read(ftsp)) != NULL) { if (f->fts_info == FTS_D && f->fts_level == 1) { fts_set(ftsp, f, FTS_SKIP); matched = NULL; errcode = 0; if (MatchType == MATCH_ALL) matched = f->fts_name; else for (i = 0; patterns[i]; i++) { errcode = pattern_match(MatchType, patterns[i], f->fts_name); if (errcode == 1) { matched = f->fts_name; lmatched[i] = TRUE; errcode = 0; } if (matched != NULL || errcode != 0) break; } if (errcode == 0 && matched != NULL) errcode = storeappend(store, matched); if (errcode != 0) { if (retval != NULL) *retval = 1; return NULL; /* Not reached */ } } } fts_close(ftsp); } if (MatchType == MATCH_GLOB) { for (i = 0; i < len; i++) if (lmatched[i] == FALSE) storeappend(store, patterns[i]); } if (store->used == 0) return NULL; else return store->store; } int pattern_match(match_t MatchType, char *pattern, const char *pkgname) { int errcode = 0; const char *fname = pkgname; char basefname[PATH_MAX]; char condchar = '\0'; char *condition; /* do we have an appended condition? */ condition = strpbrk(pattern, "<>="); if (condition) { const char *ch; /* yes, isolate the pattern from the condition ... */ if (condition > pattern && condition[-1] == '!') condition--; condchar = *condition; *condition = '\0'; /* ... and compare the name without version */ ch = strrchr(fname, '-'); if (ch && ch - fname < PATH_MAX) { strlcpy(basefname, fname, ch - fname + 1); fname = basefname; } } switch (MatchType) { case MATCH_EREGEX: case MATCH_REGEX: errcode = rex_match(pattern, fname, MatchType == MATCH_EREGEX ? 1 : 0); break; case MATCH_NGLOB: case MATCH_GLOB: errcode = (csh_match(pattern, fname, 0) == 0) ? 1 : 0; break; case MATCH_EXACT: errcode = (strcmp(pattern, fname) == 0) ? 1 : 0; break; case MATCH_ALL: errcode = 1; break; default: break; } /* loop over all appended conditions */ while (condition) { /* restore the pattern */ *condition = condchar; /* parse the condition (fun with bits) */ if (errcode == 1) { char *nextcondition; /* compare version numbers */ int match = 0; if (*++condition == '=') { match = 2; condition++; } switch(condchar) { case '<': match |= 1; break; case '>': match |= 4; break; case '=': match |= 2; break; case '!': match = 5; break; } /* isolate the version number from the next condition ... */ nextcondition = strpbrk(condition, "<>=!"); if (nextcondition) { condchar = *nextcondition; *nextcondition = '\0'; } /* and compare the versions (version_cmp removes the filename for us) */ if ((match & (1 << (version_cmp(pkgname, condition) + 1))) == 0) errcode = 0; condition = nextcondition; } else { break; } } return errcode; } /* * Synopsis is similar to matchinstalled(), but use origin * as a key for matching packages. */ char ** matchbyorigin(const char *origin, int *retval) { char **installed; int i; static struct store *store = NULL; store = storecreate(store); if (store == NULL) { if (retval != NULL) *retval = 1; return NULL; } if (retval != NULL) *retval = 0; installed = matchinstalled(MATCH_ALL, NULL, retval); if (installed == NULL) return NULL; for (i = 0; installed[i] != NULL; i++) { FILE *fp; char *cp, tmp[PATH_MAX]; int cmd; snprintf(tmp, PATH_MAX, "%s/%s", LOG_DIR, installed[i]); /* * SPECIAL CASE: ignore empty dirs, since we can can see them * during port installation. */ if (isemptydir(tmp)) continue; snprintf(tmp, PATH_MAX, "%s/%s", tmp, CONTENTS_FNAME); fp = fopen(tmp, "r"); if (fp == NULL) { warnx("the package info for package '%s' is corrupt", installed[i]); continue; } cmd = -1; while (fgets(tmp, sizeof(tmp), fp)) { int len = strlen(tmp); while (len && isspace(tmp[len - 1])) tmp[--len] = '\0'; if (!len) continue; cp = tmp; if (tmp[0] != CMD_CHAR) continue; cmd = plist_cmd(tmp + 1, &cp); if (cmd == PLIST_ORIGIN) { if (csh_match(origin, cp, FNM_PATHNAME) == 0) storeappend(store, installed[i]); break; } } if (cmd != PLIST_ORIGIN) warnx("package %s has no origin recorded", installed[i]); fclose(fp); } if (store->used == 0) return NULL; else return store->store; } /* * * Return 1 if the specified package is installed, * 0 if not, and -1 if an error occured. */ int isinstalledpkg(const char *name) { char buf[FILENAME_MAX]; char buf2[FILENAME_MAX]; snprintf(buf, sizeof(buf), "%s/%s", LOG_DIR, name); if (!isdir(buf) || access(buf, R_OK) == FAIL) return 0; snprintf(buf2, sizeof(buf2), "%s/%s", buf, CONTENTS_FNAME); if (!isfile(buf2) || access(buf2, R_OK) == FAIL) return -1; return 1; } /* * Returns 1 if specified pkgname matches RE pattern. * Otherwise returns 0 if doesn't match or -1 if RE * engine reported an error (usually invalid syntax). */ static int rex_match(const char *pattern, const char *pkgname, int extended) { char errbuf[128]; int errcode; int retval; regex_t rex; retval = 0; errcode = regcomp(&rex, pattern, (extended ? REG_EXTENDED : REG_BASIC) | REG_NOSUB); if (errcode == 0) errcode = regexec(&rex, pkgname, 0, NULL, 0); if (errcode == 0) { retval = 1; } else if (errcode != REG_NOMATCH) { regerror(errcode, &rex, errbuf, sizeof(errbuf)); warnx("%s: %s", pattern, errbuf); retval = -1; } regfree(&rex); return retval; } /* * Match string by a csh-style glob pattern. Returns 0 on * match and FNM_NOMATCH otherwise, to be compatible with * fnmatch(3). */ static int csh_match(const char *pattern, const char *string, int flags) { int ret = FNM_NOMATCH; const char *nextchoice = pattern; const char *current = NULL; int prefixlen = -1; int currentlen = 0; int level = 0; do { const char *pos = nextchoice; const char *postfix = NULL; Boolean quoted = FALSE; nextchoice = NULL; do { const char *eb; if (!*pos) { postfix = pos; } else if (quoted) { quoted = FALSE; } else { switch (*pos) { case '{': ++level; if (level == 1) { current = pos+1; prefixlen = pos-pattern; } break; case ',': if (level == 1 && !nextchoice) { nextchoice = pos+1; currentlen = pos-current; } break; case '}': if (level == 1) { postfix = pos+1; if (!nextchoice) currentlen = pos-current; } level--; break; case '[': eb = pos+1; if (*eb == '!' || *eb == '^') eb++; if (*eb == ']') eb++; while(*eb && *eb != ']') eb++; if (*eb) pos=eb; break; case '\\': quoted = TRUE; break; default: ; } } pos++; } while (!postfix); if (current) { char buf[FILENAME_MAX]; snprintf(buf, sizeof(buf), "%.*s%.*s%s", prefixlen, pattern, currentlen, current, postfix); ret = csh_match(buf, string, flags); if (ret) { current = nextchoice; level = 1; } else current = NULL; } else ret = fnmatch(pattern, string, flags); } while (current); return ret; } /* * Create an empty store, optionally deallocating * any previously allocated space if store != NULL. */ struct store * storecreate(struct store *store) { int i; if (store == NULL) { store = malloc(sizeof *store); if (store == NULL) { warnx("%s(): malloc() failed", __func__); return NULL; } store->currlen = 0; store->store = NULL; } else if (store->store != NULL) { /* Free previously allocated memory */ for (i = 0; store->store[i] != NULL; i++) free(store->store[i]); store->store[0] = NULL; } store->used = 0; return store; } /* * Append specified element to the provided store. */ static int storeappend(struct store *store, const char *item) { if (store->used + 2 > store->currlen) { store->currlen += 16; store->store = reallocf(store->store, store->currlen * sizeof(*(store->store))); if (store->store == NULL) { store->currlen = 0; warnx("%s(): reallocf() failed", __func__); return 1; } } asprintf(&(store->store[store->used]), "%s", item); if (store->store[store->used] == NULL) { warnx("%s(): malloc() failed", __func__); return 1; } store->used++; store->store[store->used] = NULL; return 0; } static int fname_cmp(const FTSENT * const *a, const FTSENT * const *b) { return strcmp((*a)->fts_name, (*b)->fts_name); } Index: head/usr.sbin/pkg_install/lib/pen.c =================================================================== --- head/usr.sbin/pkg_install/lib/pen.c (revision 131284) +++ head/usr.sbin/pkg_install/lib/pen.c (revision 131285) @@ -1,176 +1,176 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * Routines for managing the "play pen". * */ #include __FBSDID("$FreeBSD$"); #include "lib.h" #include #include #include #include #include /* For keeping track of where we are */ static char PenLocation[FILENAME_MAX]; static char Previous[FILENAME_MAX]; char * where_playpen(void) { return PenLocation; } /* Find a good place to play. */ static char * find_play_pen(char *pen, off_t sz) { char *cp; struct stat sb; if (pen[0] && isdir(dirname(pen)) == TRUE && (min_free(dirname(pen)) >= sz)) return pen; else if ((cp = getenv("PKG_TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz)) sprintf(pen, "%s/instmp.XXXXXX", cp); else if ((cp = getenv("TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz)) sprintf(pen, "%s/instmp.XXXXXX", cp); else if (stat("/var/tmp", &sb) != FAIL && min_free("/var/tmp") >= sz) strcpy(pen, "/var/tmp/instmp.XXXXXX"); else if (stat("/tmp", &sb) != FAIL && min_free("/tmp") >= sz) strcpy(pen, "/tmp/instmp.XXXXXX"); else if ((stat("/usr/tmp", &sb) == SUCCESS || mkdir("/usr/tmp", 01777) == SUCCESS) && min_free("/usr/tmp") >= sz) strcpy(pen, "/usr/tmp/instmp.XXXXXX"); else { cleanup(0); errx(2, "%s: can't find enough temporary space to extract the files, please set your\n" "PKG_TMPDIR environment variable to a location with at least %ld bytes\n" "free", __func__, (long)sz); return NULL; } return pen; } #define MAX_STACK 20 static char *pstack[MAX_STACK]; static int pdepth = -1; static void pushPen(const char *pen) { if (++pdepth == MAX_STACK) errx(2, "%s: stack overflow.\n", __func__); pstack[pdepth] = strdup(pen); } static void popPen(char *pen) { if (pdepth == -1) { pen[0] = '\0'; return; } strcpy(pen, pstack[pdepth]); free(pstack[pdepth--]); } /* * Make a temporary directory to play in and chdir() to it, returning * pathname of previous working directory. */ char * make_playpen(char *pen, off_t sz) { if (!find_play_pen(pen, sz)) return NULL; if (!mkdtemp(pen)) { cleanup(0); errx(2, "%s: can't mktemp '%s'", __func__, pen); } if (chmod(pen, 0700) == FAIL) { cleanup(0); errx(2, "%s: can't mkdir '%s'", __func__, pen); } if (Verbose) { if (sz) fprintf(stderr, "Requested space: %d bytes, free space: %qd bytes in %s\n", (int)sz, (long long)min_free(pen), pen); } if (min_free(pen) < sz) { rmdir(pen); cleanup(0); errx(2, "%s: not enough free space to create '%s'.\n" "Please set your PKG_TMPDIR environment variable to a location\n" "with more space and\ntry the command again", __func__, pen); } if (!getcwd(Previous, FILENAME_MAX)) { upchuck("getcwd"); return NULL; } if (chdir(pen) == FAIL) { cleanup(0); errx(2, "%s: can't chdir to '%s'", __func__, pen); } if (PenLocation[0]) pushPen(PenLocation); strcpy(PenLocation, pen); return Previous; } /* Convenience routine for getting out of playpen */ void leave_playpen() { void (*oldsig)(int); /* Don't interrupt while we're cleaning up */ oldsig = signal(SIGINT, SIG_IGN); if (Previous[0]) { if (chdir(Previous) == FAIL) { cleanup(0); errx(2, "%s: can't chdir back to '%s'", __func__, Previous); } Previous[0] = '\0'; } if (PenLocation[0]) { - if (PenLocation[0] == '/' && vsystem("rm -rf %s", PenLocation)) + if (PenLocation[0] == '/' && vsystem("/bin/rm -rf %s", PenLocation)) warnx("couldn't remove temporary dir '%s'", PenLocation); popPen(PenLocation); } signal(SIGINT, oldsig); } off_t min_free(const char *tmpdir) { struct statfs buf; if (statfs(tmpdir, &buf) != 0) { warn("statfs"); return -1; } return (off_t)buf.f_bavail * (off_t)buf.f_bsize; } Index: head/usr.sbin/pkg_install/lib/url.c =================================================================== --- head/usr.sbin/pkg_install/lib/url.c (revision 131284) +++ head/usr.sbin/pkg_install/lib/url.c (revision 131285) @@ -1,144 +1,154 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 18 July 1993 * * URL file access utilities. * */ #include __FBSDID("$FreeBSD$"); #include "lib.h" #include #include #include /* * Try and fetch a file by URL, returning the directory name for where * it's unpacked, if successful. */ char * fileGetURL(const char *base, const char *spec) { char *cp, *rp; char fname[FILENAME_MAX]; char pen[FILENAME_MAX]; char buf[8192]; FILE *ftp; pid_t tpid; - int pfd[2], pstat, r, w; + int pfd[2], pstat, r, w = 0; char *hint; int fd; rp = NULL; /* Special tip that sysinstall left for us */ hint = getenv("PKG_ADD_BASE"); if (!isURL(spec)) { if (!base && !hint) return NULL; /* * We've been given an existing URL (that's known-good) and now we need * to construct a composite one out of that and the basename we were * handed as a dependency. */ if (base) { strcpy(fname, base); /* * Advance back two slashes to get to the root of the package * hierarchy */ cp = strrchr(fname, '/'); if (cp) { *cp = '\0'; /* chop name */ cp = strrchr(fname, '/'); } if (cp) { *(cp + 1) = '\0'; strcat(cp, "All/"); strcat(cp, spec); - /* XXX: need to handle .tgz also */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 strcat(cp, ".tbz"); +#else + strcat(cp, ".tgz"); +#endif } else return NULL; } else { /* * Otherwise, we've been given an environment variable hinting * at the right location from sysinstall */ strcpy(fname, hint); strcat(fname, spec); - /* XXX: need to handle .tgz also */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 strcat(fname, ".tbz"); +#else + strcat(fname, ".tgz"); +#endif } } else strcpy(fname, spec); if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) { printf("Error: FTP Unable to get %s: %s\n", fname, fetchLastErrString); return NULL; } if (isatty(0) || Verbose) printf("Fetching %s...", fname), fflush(stdout); pen[0] = '\0'; if ((rp = make_playpen(pen, 0)) == NULL) { printf("Error: Unable to construct a new playpen for FTP!\n"); fclose(ftp); return NULL; } if (pipe(pfd) == -1) { warn("pipe()"); cleanup(0); exit(2); } if ((tpid = fork()) == -1) { warn("pipe()"); cleanup(0); exit(2); } if (!tpid) { dup2(pfd[0], 0); for (fd = getdtablesize() - 1; fd >= 3; --fd) close(fd); - /* XXX: need to handle .tgz also */ - execl("/usr/bin/tar", "tar", Verbose ? "-xjvf" : "-xjf", "-", - (char *)0); + execl("/usr/bin/tar", "tar", +#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 + Verbose ? "-xjvf" : "-xjf", +#else + Verbose ? "-xzvf" : "-xzf", +#endif + "-", (char *)0); _exit(2); } close(pfd[0]); for (;;) { if ((r = fread(buf, 1, sizeof buf, ftp)) < 1) break; if ((w = write(pfd[1], buf, r)) != r) break; } if (ferror(ftp)) warn("warning: error reading from server"); fclose(ftp); close(pfd[1]); if (w == -1) warn("warning: error writing to tar"); tpid = waitpid(tpid, &pstat, 0); if (Verbose) printf("tar command returns %d status\n", WEXITSTATUS(pstat)); if (rp && (isatty(0) || Verbose)) printf(" Done.\n"); return rp; } Index: head/usr.sbin/pkg_install/sign/Makefile =================================================================== --- head/usr.sbin/pkg_install/sign/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/sign/Makefile (revision 131285) @@ -1,19 +1,17 @@ # $FreeBSD$ # $OpenBSD: Makefile.bsd-wrapper,v 1.2 1999/10/07 16:30:32 espie Exp $ PROG= pkg_sign LINKS= ${BINDIR}/pkg_sign ${BINDIR}/pkg_check MLINKS= pkg_sign.1 pkg_check.1 SRCS= main.c check.c common.c gzip.c pgp_check.c pgp_sign.c \ sha1.c sign.c stand.c x509.c CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib -WARNS?= 0 - DISTRIBUTION= crypto DPADD= ${LIBINSTALL} ${LIBMD} ${LIBCRYPTO} LDADD= ${LIBINSTALL} -lmd -lcrypto .include Index: head/usr.sbin/pkg_install/sign/pgp_sign.c =================================================================== --- head/usr.sbin/pkg_install/sign/pgp_sign.c (revision 131284) +++ head/usr.sbin/pkg_install/sign/pgp_sign.c (revision 131285) @@ -1,280 +1,281 @@ /* $OpenBSD: pgp_sign.c,v 1.1 1999/10/04 21:46:29 espie Exp $ */ /*- * Copyright (c) 1999 Marc Espie. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Espie for the OpenBSD * Project. * * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include #include "stand.h" #include "pgp.h" #include "gzip.h" #include "extern.h" static void pgpsign(fdin, fdout, userid, envp) int fdin, fdout; const char *userid; char *envp[]; { pchar argv[10]; int argc = 0; argv[argc++] = PGP; argv[argc++] = "+batchmode"; argv[argc++] = "+compress=off"; argv[argc++] = "-f"; argv[argc++] = "-s"; argv[argc++] = "-zAthlon"; if (userid) { argv[argc++] = "-u"; argv[argc++] = (char *)userid; } argv[argc++] = NULL; assert(argc <= sizeof argv / sizeof(pchar)); if (dup2(fdin, fileno(stdin)) == -1 || dup2(fdout, fileno(stdout)) == -1 || execve(PGP, argv, envp) == -1) exit(errno); } static struct signature * new_pgpsignature(old) struct signature *old; { struct signature *n; n = malloc(sizeof(*n)); if (n != NULL) { n->data = malloc(MAXPGPSIGNSIZE); if (n->data == NULL) { free(n); return NULL; } n->length = 0; n->next = old; n->type = TAG_PGP; memcpy(n->tag, pgptag, sizeof pgptag); } return n; } int retrieve_pgp_signature(filename, sign, userid, envp) const char *filename; struct signature **sign; const char *userid; char *envp[]; { int topgp[2], frompgp[2]; pid_t pgpid; struct mygzip_header h; int success; FILE *orig, *dest, *signin; struct signature *old; orig = fopen(filename, "r"); if (orig == NULL) return 0; if (gzip_read_header(orig, &h, &old) == GZIP_NOT_GZIP) { warnx("File %s is not a gzip file\n", filename); fclose(orig); return 0; } if (pipe(topgp) == -1) { fclose(orig); return 0; } if (pipe(frompgp) == -1) { fclose(orig); (void)close(topgp[0]); (void)close(topgp[1]); return 0; } switch(pgpid = fork()) { case 0: (void)close(topgp[1]); (void)close(frompgp[0]); pgpsign(topgp[0], frompgp[1], userid, envp); /*NOT REACHED */ case -1: (void)close(topgp[0]); (void)close(topgp[1]); (void)close(frompgp[0]); (void)close(frompgp[1]); fclose(orig); return 0; default: (void)close(topgp[0]); (void)close(frompgp[1]); } dest = fdopen(topgp[1], "w"); if (dest == NULL) { (void)close(topgp[1]); (void)close(frompgp[0]); (void)reap(pgpid); return 0; } success = 1; if (gzip_write_header(dest, &h, old) == 0) success = 0; else { int c; while ((c = fgetc(orig)) != EOF && fputc(c, dest) != EOF) ; if (ferror(dest)) success = 0; } if (fclose(dest) != 0) success = 0; if (fclose(orig) != 0) success = 0; signin = fdopen(frompgp[0], "r"); if (signin == NULL) { (void)close(frompgp[0]); } else { enum { NONE, FIRST, DONE, COPY} magic = NONE; int c; #ifdef DEBUG_DUMP FILE *out = fopen("dump", "w"); #endif if ((*sign = new_pgpsignature(old)) == NULL) success = 0; else { while ((c = fgetc(signin)) != EOF && magic != DONE && (*sign)->length < MAXPGPSIGNSIZE) { switch(magic) { case NONE: (*sign)->data[(*sign)->length++] = c; if ((unsigned char)c == (unsigned char)GZIP_MAGIC0) magic = FIRST; break; case FIRST: (*sign)->data[(*sign)->length++] = c; if ((unsigned char)c == (unsigned char)GZIP_MAGIC1) #ifdef DEBUG_DUMP magic = COPY; #else magic = DONE; #endif else if ((unsigned char)c != (unsigned char)GZIP_MAGIC0) magic = NONE; break; case DONE: case COPY: break; } #ifdef DEBUG_DUMP fputc(c, out); #endif } if ((*sign)->length == MAXPGPSIGNSIZE) success = 0; (*sign)->length -= 2; sign_fill_tag(*sign); } fclose(signin); #ifdef DEBUG_DUMP fclose(out); #endif reap(pgpid); } return success; } void handle_pgp_passphrase() { pid_t pid; int fd[2]; char *p; printf("Short-circuiting %s\n", __func__); return; /* Retrieve the pgp passphrase */ p = getpass("Enter passphrase:"); /* * Somewhat kludgy code to get the passphrase to pgp, see * pgp documentation for the gore */ if (pipe(fd) != 0) { perror("pkg_sign"); exit(EXIT_FAILURE); } switch(pid = fork()) { case -1: perror("pkg_sign"); exit(EXIT_FAILURE); case 0: { (void)close(fd[0]); /* * The child fills the pipe with copies of the passphrase. * Expect violent death when father exits. */ printf("Child process %d stuffing passphrase in pipe:\n", getpid()); for(;;) { char c = '\n'; (void)write(fd[1], p, strlen(p)); (void)write(fd[1], &c, 1); putchar('.'); fflush(stdout); } } default: { char buf[10]; sleep(1); (void)close(fd[1]); (void)sprintf(buf, "%d", fd[0]); (void)setenv("PGPPASSFD", buf, 1); printf("Parent process PGPPASSFD=%d.\n", fd[0]); } } } Index: head/usr.sbin/pkg_install/sign/sha1.c =================================================================== --- head/usr.sbin/pkg_install/sign/sha1.c (revision 131284) +++ head/usr.sbin/pkg_install/sign/sha1.c (revision 131285) @@ -1,231 +1,230 @@ /* $OpenBSD: sha1.c,v 1.1 1999/10/04 21:46:29 espie Exp $ */ /*- * Copyright (c) 1999 Marc Espie. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Espie for the OpenBSD * Project. * * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "stand.h" #include "gzip.h" #include "extern.h" /* private context for sha1 signature checker */ struct sha1_checker { SHA_CTX context; const char *id; const char *filename; }; #define SHA1_TEMPLATE "SHA1 (%s) = " #define BUFSIZE (MAXID+sizeof(SHA1_TEMPLATE)+2*SHA_DIGEST_LENGTH+1) /* * Finalize SHA1 checksum for our sha1_context into result * (size at least BUFSIZE). Returns the length of the checksum * marker, e.g., SHA1 (id) = xxxxxxxxx * ^here * Return 0 for errors. */ size_t sha1_build_checksum(result, n) char *result; struct sha1_checker *n; { size_t length; snprintf(result, BUFSIZE-2*SHA_DIGEST_LENGTH-1, SHA1_TEMPLATE, n->id); length = strlen(result); SHA1_End(&n->context, result + length); strcat(result, "\n"); free(n); return length; } void * new_sha1_checker(h, sign, userid, envp, filename) struct mygzip_header *h; struct signature *sign; const char *userid; char *envp[]; /*@observer@*/const char *filename; { struct sha1_checker *n; assert(sign->type == TAG_SHA1); /* make sure data conforms to what we can handle */ if (sign->length > MAXID || sign->data[sign->length-1] != '\0') { warnx("Corrupted SHA1 header in %s", filename); return 0; } n = malloc(sizeof *n); if (n == NULL) { warnx("Can't allocate sha1_checker"); return NULL; } SHA1_Init(&n->context); n->id = sign->data; n->filename = filename; /* copy header, as this is a checksum, we don't strip our own marker */ if (gzip_copy_header(h, sign, sha1_add, n) == 0) { warnx("Unexpected header in %s", filename); free(n); return 0; } return n; } void sha1_add(arg, buffer, length) void *arg; const char *buffer; size_t length; { struct sha1_checker *n = arg; SHA1_Update(&n->context, buffer, length); } int sha1_sign_ok(arg) void *arg; { struct sha1_checker *n = arg; char buffer[BUFSIZE]; char scan[BUFSIZE]; size_t length; FILE *f; int tag_found; length = sha1_build_checksum(buffer, n); f= fopen(SHA1_DB_NAME, "r"); tag_found = 0; if (f == NULL) { warn("Can't access checksum file %s", SHA1_DB_NAME); return PKG_BADSIG; } while (fgets(scan, sizeof(scan), f) != NULL) { if (strcmp(scan, buffer) == 0) { fprintf(stderr, "Checksum ok\n"); return PKG_GOODSIG; } if (strncmp(scan, buffer, length) == 0) tag_found = 1; } if (tag_found) { warnx("Checksum incorrect for %s (%s)", n->filename, n->id); return PKG_BADSIG; } else { warnx("No checksum found for %s (%s)", n->filename, n->id); return PKG_SIGUNKNOWN; } } int retrieve_sha1_marker(filename, sign, userid) const char *filename; struct signature **sign; const char *userid; { struct signature *n; struct mygzip_header h; FILE *f; char buffer[1024]; char result[BUFSIZE]; ssize_t length = -1; struct sha1_checker *checker; - struct signature *old; *sign = NULL; if (userid == NULL) return 0; /* * Create a blank signature and fill it with the userid. */ n = malloc(sizeof *n); if (n == NULL) return 0; n->length = strlen(userid)+1; n->data = malloc(n->length); if (n->data == NULL) { free(n); return 0; } memcpy(n->data, userid, n->length); n->type = TAG_SHA1; memcpy(n->tag, sha1tag, sizeof sha1tag); sign_fill_tag(n); /* * Read the gzip header and add our "userid" signature to it. */ f = fopen(filename, "r"); if (f == NULL) { free(n); return 0; } if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) { warnx("File %s is not a gzip file\n", filename); fclose(f); free(n); return 0; } n->next = *sign; *sign = n; /* * Calculate the SHA1 of the remaining data and write it to stderr. */ checker = new_sha1_checker(&h, *sign, NULL, NULL, filename); if (checker) while ((length = fread(buffer, 1, sizeof buffer, f)) > 0) sha1_add(checker, buffer, length); if (fclose(f) != 0 || length == -1) { warn("Problem checksumming %s", filename); *sign = n->next; free(n); return 0; } (void)sha1_build_checksum(result, checker); fputs(result, stderr); return 1; } Index: head/usr.sbin/pkg_install/sign/sign.c =================================================================== --- head/usr.sbin/pkg_install/sign/sign.c (revision 131284) +++ head/usr.sbin/pkg_install/sign/sign.c (revision 131285) @@ -1,146 +1,147 @@ /* $OpenBSD: sign.c,v 1.3 1999/10/04 21:46:29 espie Exp $ */ /*- * Copyright (c) 1999 Marc Espie. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Espie for the OpenBSD * Project. * * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include #include "stand.h" #include "pgp.h" #include "gzip.h" #include "extern.h" #define COPY_TEMPLATE "%s.sign" static int embed_signature_FILE(orig, dest, sign, filename) /*@temp@*/FILE *orig; /*@temp@*/FILE *dest; struct signature *sign; const char *filename; { struct mygzip_header h; int c; if (gzip_read_header(orig, &h, NULL) == GZIP_NOT_GZIP) return 0; if (gzip_write_header(dest, &h, sign) == 0) return 0; while ((c = fgetc(orig)) != EOF && fputc(c, dest) != EOF) ; if (ferror(dest) != 0) return 0; return 1; } static int embed_signature(filename, copy, sign) const char *filename; const char *copy; struct signature *sign; { FILE *orig, *dest; int success; success = 0; orig= fopen(filename, "r"); if (orig) { dest = fopen(copy, "w"); if (dest) { success = embed_signature_FILE(orig, dest, sign, filename); if (fclose(dest) != 0) success = 0; } if (fclose(orig) != 0) success = 0; } return success; } int sign(filename, type, userid, envp) const char *filename; const char *userid; int type; char *envp[]; { char *copy; int result; struct signature *sign; int success; sign = NULL; switch(type) { case TAG_PGP: success = retrieve_pgp_signature(filename, &sign, userid, envp); break; case TAG_SHA1: success = retrieve_sha1_marker(filename, &sign, userid); break; case TAG_X509: success = retrieve_x509_marker(filename, &sign, userid); break; } if (!success) { fprintf(stderr, "Problem signing %s\n", filename); free_signature(sign); return 0; } copy = malloc(strlen(filename)+sizeof(COPY_TEMPLATE)); if (copy == NULL) { fprintf(stderr, "Can't allocate memory\n"); free_signature(sign); return 0; } sprintf(copy, COPY_TEMPLATE, filename); result = embed_signature(filename, copy, sign); if (result == 0) { fprintf(stderr, "Can't embed signature in %s\n", filename); } else if (unlink(filename) != 0) { fprintf(stderr, "Can't unlink original %s\n", filename); result = 0; } else if (rename(copy, filename) != 0) { fprintf(stderr, "Can't rename new file %s\n", copy); result = 0; } free(copy); free_signature(sign); return result; } Index: head/usr.sbin/pkg_install/sign/stand.h =================================================================== --- head/usr.sbin/pkg_install/sign/stand.h (revision 131284) +++ head/usr.sbin/pkg_install/sign/stand.h (revision 131285) @@ -1,28 +1,28 @@ /* $FreeBSD$ */ /* $OpenBSD: stand.h,v 1.2 1999/10/04 21:46:30 espie Exp $ */ /* provided to cater for BSD idiosyncrasies */ #if (defined(__unix__) || defined(unix)) && !defined(USG) #include #endif #ifndef __P #ifdef __STDC__ #define __P(x) x #else #define __P(x) () #endif #endif #if defined(BSD4_4) #include #else -extern void set_program_name __P((const char * name)); extern void warn __P((const char *fmt, ...)); extern void warnx __P((const char *fmt, ...)); #endif +extern void set_program_name __P((const char * name)); #ifndef __GNUC__ #define __attribute__(x) #endif Index: head/usr.sbin/pkg_install/sign/x509.c =================================================================== --- head/usr.sbin/pkg_install/sign/x509.c (revision 131284) +++ head/usr.sbin/pkg_install/sign/x509.c (revision 131285) @@ -1,427 +1,425 @@ /*- * Copyright (c) 2000 Softweyr LLC, South Jordan, Utah, USA. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY Softweyr LLC ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL Softweyr LLC BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stand.h" #include "gzip.h" #include "extern.h" /* * Default names for the signing key and certificate(s) for verification. */ #define CERTFILE "/etc/ssl/pkg.crt" #define KEYFILE "/etc/ssl/pkg.key" /* * Private context for X.509 signature checker */ struct x509_checker { const char * id; const char * filename; struct signature * signature; STACK_OF(X509) * certs; EVP_MD_CTX rsa_ctx, dsa_ctx; int has_rsa, has_dsa; }; static void key_from_name(char *, const char *); /* * Initialize an X.509 "checker" context. */ void * new_x509_checker(h, sign, userid, envp, filename) struct mygzip_header *h; struct signature *sign; const char *userid; char *envp[]; /*@observer@*/const char *filename; { FILE * fp; struct x509_checker * me; char certfile[PATH_MAX + 1] = CERTFILE; - char * cp; X509 * x509; assert(sign->type == TAG_X509); /* * Make sure data conforms to what we can handle. We do not write a * trailing null onto the signature like some other types, because * the X.509 signature is binary data. */ if (sign->length > MAXID) { warnx("Corrupted X.509 header in %s", filename); return 0; } me = malloc(sizeof *me); if (me == NULL) { warn("Cannot allocate x509_checker"); return 0; } me->id = sign->data; me->filename = filename; me->signature = sign; me->has_rsa = 0; me->has_dsa = 0; key_from_name(certfile, userkey); /* * Load just the crypto library error strings. */ ERR_load_crypto_strings(); /* * Load the stack of X.509 certs we will compare against. * * KLUDGE: this needs to be fleshed out a bit. We can do better * than hard-coding the location of the cert key file. */ me->certs = sk_X509_new_null(); fp = fopen(certfile, "r"); if (fp == NULL) { warnx("Cannot open public key %s", certfile); return 0; } if (verbose) printf("Loading certificates from %s:\n", certfile); - while (x509 = PEM_read_X509(fp, NULL, NULL, 0)) { + while ((x509 = PEM_read_X509(fp, NULL, NULL, 0))) { sk_X509_push(me->certs, x509); switch (EVP_PKEY_type(X509_get_pubkey(x509)->type)) { case EVP_PKEY_RSA: me->has_rsa = 1; break; case EVP_PKEY_DSA: me->has_dsa = 1; break; default: warnx("Uknown certificate type"); return 0; } /* * By default, print the contents of the cert we matched so the * user can decide if she is willing to accept a package from * whoever signed this. */ if (!quiet) X509_print_fp(stdout, x509); } fclose(fp); /* * Initialize the verification contexts for both RSA and DSA. */ if (me->has_rsa) EVP_VerifyInit(&me->rsa_ctx, EVP_sha1()); if (me->has_dsa) EVP_VerifyInit(&me->dsa_ctx, EVP_dss1()); return me; } /* * "Add" another data block to an existing checker. */ void x509_add(arg, buffer, length) void *arg; const char *buffer; size_t length; { struct x509_checker * me = arg; if (me->has_rsa) EVP_VerifyUpdate(&me->rsa_ctx, buffer, length); if (me->has_dsa) EVP_VerifyUpdate(&me->dsa_ctx, buffer, length); } /* * Finalize an existing checker and verify the signature matches one of the * certs in our stack. */ int x509_sign_ok(arg) void *arg; { struct x509_checker * n = arg; X509 * x509; EVP_PKEY * pkey; EVP_MD_CTX * md_ctx; int status; if (verbose) printf("\n\n-------\n\nChecking package signature:\n"); while ((x509 = sk_X509_pop(n->certs)) != NULL) { /* * Get public key from cert. */ pkey = X509_get_pubkey(x509); if (pkey == NULL) { warnx("Getting public key:"); ERR_print_errors_fp(stderr); continue; } if (verbose) X509_print_fp(stdout, x509); switch (EVP_PKEY_type(pkey->type)) { case EVP_PKEY_RSA: md_ctx = &n->rsa_ctx; break; case EVP_PKEY_DSA: md_ctx = &n->dsa_ctx; break; default: break; } status = EVP_VerifyFinal(md_ctx, n->signature->data, n->signature->length, pkey); EVP_PKEY_free(pkey); X509_free(x509); if (status == 1) { fprintf(stderr, "X.509 signature matched\n"); /* * KLUDGE: Does this free the rest of the certs, or just the * stack itself? Enquiring minds want to know. */ sk_X509_free(n->certs); return PKG_GOODSIG; } } warnx("Verifying signature:"); ERR_print_errors_fp(stderr); sk_X509_free(n->certs); return PKG_BADSIG; } /* * Sign the specified filename into sign. */ int retrieve_x509_marker(filename, sign, userid) const char * filename; struct signature ** sign; const char * userid; { struct signature * n; struct mygzip_header h; FILE * f, * keyf; char buffer[1024]; ssize_t length; int err; int sig_len = 4096; unsigned char * sig_buf; EVP_MD_CTX md_ctx; const EVP_MD * md_type; EVP_PKEY * pkey; char keyfile[PATH_MAX + 1] = KEYFILE; - char * kp; key_from_name(keyfile, userkey); f = fopen(filename, "r"); if (f == NULL) { free(n); return 0; } if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) { warnx("File %s is not a gzip file\n", filename); fclose(f); free(n); return 0; } /* * Sign the remaining data: * Load just the crypto library error strings. */ ERR_load_crypto_strings(); /* * Read private key. */ keyf = fopen(keyfile, "r"); if (keyf == NULL) { warnx("Cannot open private key %s.", keyfile); return 0; } pkey = PEM_read_PrivateKey(keyf, NULL, NULL, 0); fclose(keyf); if (pkey == NULL) { warnx("Reading private key %s:", keyfile); ERR_print_errors_fp(stderr); return 0; } /* * Do the signature. The remaining bytes of the GZIP file are the * compressed tar image, which is what we are signing. */ switch (EVP_PKEY_type(pkey->type)) { case EVP_PKEY_RSA: md_type = EVP_sha1(); printf("*** It's an RSA key.\n"); break; case EVP_PKEY_DSA: md_type = EVP_dss1(); printf("@@@ It's a DSA key, yippee!\n"); break; default: warnx("Uknown key type"); return 0; } EVP_SignInit(&md_ctx, md_type); while ((length = fread(buffer, 1, sizeof buffer, f)) > 0) EVP_SignUpdate(&md_ctx, buffer, length); sig_buf = malloc(sig_len); if (sig_buf == NULL) { warnx("Cannot allocated %u bytes for signature buffer", sig_len); return 0; } err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey); if (err != 1) { warnx("Creating signature:"); ERR_print_errors_fp(stderr); return 0; } EVP_PKEY_free(pkey); /* * Stuff the signature onto the head of the chain of signatures in * the package. */ n = malloc(sizeof *n); if (n == NULL) { warnx("Cannot allocate %u bytes for new signature", sizeof *n); return 0; } n->data = sig_buf; n->length = sig_len; n->type = TAG_X509; memcpy(n->tag, x509tag, sizeof x509tag); sign_fill_tag(n); n->next = *sign; *sign = n; /* * Report our success. */ return 1; } static void key_from_name(char * filename, const char * ident) { char * cp; /* * If an alternate keyfile was specified, treat it as the name of an * alternate private key with which to sign or verify the package. */ if (ident) { printf("Using alternate key/cert \"%s\".\n", ident); if (strchr(ident, '/')) { /* * The user specified a path, take it verbatim. */ strncpy(filename, ident, PATH_MAX); } else { cp = dirname(filename); if (cp == NULL) { warnx("Key directory not correctly specified."); return; } snprintf(filename, PATH_MAX, "%s/%s", cp, ident); } } if (verbose) printf("Key is \"%s\".\n", filename); } Index: head/usr.sbin/pkg_install/version/Makefile =================================================================== --- head/usr.sbin/pkg_install/version/Makefile (revision 131284) +++ head/usr.sbin/pkg_install/version/Makefile (revision 131285) @@ -1,16 +1,17 @@ # $FreeBSD$ PROG= pkg_version SRCS= main.c perform.c CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib -WARNS?= 2 +WARNS?= 6 +WFORMAT?= 1 DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} LDADD= ${LIBINSTALL} -lfetch -lmd test: ./test-pkg_version.sh .include Index: head/usr.sbin/pkg_install/version/perform.c =================================================================== --- head/usr.sbin/pkg_install/version/perform.c (revision 131284) +++ head/usr.sbin/pkg_install/version/perform.c (revision 131285) @@ -1,391 +1,390 @@ /* * FreeBSD install - a package for the installation and maintainance * of non-core utilities. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jeremy D. Lea. * 11 May 2002 * * This is the version module. Based on pkg_version.pl by Bruce A. Mah. * */ #include __FBSDID("$FreeBSD$"); #include "lib.h" #include "version.h" #include #include #include FILE *IndexFile; struct index_head Index = SLIST_HEAD_INITIALIZER(Index); static int pkg_do(char *); static void show_version(const char *, const char *, const char *); /* * This is the traditional pkg_perform, except that the argument is _not_ * a list of packages. It is the index file from the command line. * * We loop over the installed packages, matching them with the -s flag * if needed and calling pkg_do(). Before hand we set up a few things, * and after we tear them down... */ int pkg_perform(char **indexarg) { char tmp[PATH_MAX], **pkgs, *pat[2], **patterns; struct index_entry *ie; int i, err_cnt = 0; int MatchType; /* * Try to find and open the INDEX. We only check IndexFile != NULL * later, if we actually need the INDEX. - * XXX This should not be hard-coded to INDEX-5. */ if (*indexarg == NULL) - snprintf(tmp, PATH_MAX, "%s/INDEX-5", PORTS_DIR); + snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, INDEX_FNAME); else strlcpy(tmp, *indexarg, PATH_MAX); if (isURL(tmp)) IndexFile = fetchGetURL(tmp, ""); else IndexFile = fopen(tmp, "r"); /* Get either a list of matching or all packages */ if (MatchName != NULL) { pat[0] = MatchName; pat[1] = NULL; MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX; patterns = pat; } else { MatchType = MATCH_ALL; patterns = NULL; } pkgs = matchinstalled(MatchType, patterns, &err_cnt); if (err_cnt != 0) errx(2, "Unable to find package database directory!"); if (pkgs == NULL) { switch (MatchType) { case MATCH_ALL: warnx("no packages installed"); return (0); case MATCH_EREGEX: case MATCH_REGEX: warnx("no packages match pattern"); return (1); default: break; } } for (i = 0; pkgs[i] != NULL; i++) err_cnt += pkg_do(pkgs[i]); /* If we opened the INDEX in pkg_do(), clean up. */ while (!SLIST_EMPTY(&Index)) { ie = SLIST_FIRST(&Index); SLIST_REMOVE_HEAD(&Index, next); if (ie->name != NULL) free(ie->name); if (ie->origin != NULL) free(ie->origin); free(ie); } if (IndexFile != NULL) fclose(IndexFile); return err_cnt; } /* * Traditional pkg_do(). We take the package name we are passed and * first slurp in the CONTENTS file, getting name and origin, then * we look for it's corresponding Makefile. If that fails we pull in * the INDEX, and check there. */ static int pkg_do(char *pkg) { char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL; Package plist; struct index_entry *ie; FILE *fp; size_t len; /* Suck in the contents list. */ plist.head = plist.tail = NULL; plist.name = plist.origin = NULL; snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME); fp = fopen(tmp, "r"); if (!fp) { warnx("the package info for package '%s' is corrupt", pkg); return 1; } read_plist(&plist, fp); fclose(fp); if (plist.name == NULL) { warnx("%s does not appear to be a valid package!", pkg); return 1; } /* * First we check if the installed package has an origin, and try * looking for it's Makefile. If we find the Makefile we get the * latest version from there. If we fail, we start looking in the * INDEX, first matching the origin and then the package name. */ if (plist.origin != NULL) { snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin); if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) { - if ((latest = vpipe("make -V PKGNAME", tmp)) == NULL) + if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL) warnx("Failed to get PKGNAME from %s/Makefile!", tmp); else show_version(plist.name, latest, "port"); } } if (latest == NULL) { /* We only pull in the INDEX once, if needed. */ if (SLIST_EMPTY(&Index)) { if (!IndexFile) errx(2, "Unable to open INDEX in %s.", __func__); while ((ch = fgetln(IndexFile, &len)) != NULL) { /* * Don't use strlcpy() because fgetln() doesn't * return a valid C string. */ strncpy(tmp, ch, MIN(len, PATH_MAX)); tmp[PATH_MAX-1] = '\0'; /* The INDEX has pkgname|portdir|... */ if ((ch = strchr(tmp, '|')) != NULL) ch[0] = '\0'; if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL) ch[0] = '\0'; /* Look backwards for the last two dirs = origin */ while (ch != NULL && *--ch != '/') if (ch[0] == '\0') ch = NULL; while (ch != NULL && *--ch != '/') if (ch[0] == '\0') ch = NULL; if (ch == NULL) errx(2, "The INDEX does not appear to be valid!"); if ((ie = malloc(sizeof(struct index_entry))) == NULL) errx(2, "Unable to allocate memory in %s.", __func__); bzero(ie, sizeof(struct index_entry)); ie->name = strdup(tmp); ie->origin = strdup(&ch[1]); /* Who really cares if we reverse the index... */ SLIST_INSERT_HEAD(&Index, ie, next); } } /* Now that we've slurped in the INDEX... */ SLIST_FOREACH(ie, &Index, next) { if (plist.origin != NULL) { if (strcmp(plist.origin, ie->origin) == 0) latest = strdup(ie->name); } else { strlcpy(tmp, ie->name, PATH_MAX); strlcpy(tmp2, plist.name, PATH_MAX); /* Chop off the versions and compare. */ if ((ch = strrchr(tmp, '-')) == NULL) errx(2, "The INDEX does not appear to be valid!"); ch[0] = '\0'; if ((ch = strrchr(tmp2, '-')) == NULL) warnx("%s is not a valid package!", plist.name); else ch[0] = '\0'; if (strcmp(tmp2, tmp) == 0) { if (latest != NULL) { /* Multiple matches */ snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name); free(latest); latest = strdup(tmp); } else latest = strdup(ie->name); } } } if (latest == NULL) show_version(plist.name, NULL, plist.origin); else show_version(plist.name, latest, "index"); } if (latest != NULL) free(latest); free_plist(&plist); return 0; } #define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \ (LimitChars != NULL && strchr(LimitChars, (c))) || \ (PreventChars == NULL && LimitChars == NULL)) /* * Do the work of comparing and outputing. Ugly, but well that's what * You get when you try to match perl output in C ;-). */ void show_version(const char *installed, const char *latest, const char *source) { char *ch, tmp[PATH_MAX]; const char *ver; int cmp = 0; if (!installed || strlen(installed) == 0) return; strlcpy(tmp, installed, PATH_MAX); if (!Verbose) { if ((ch = strrchr(tmp, '-')) != NULL) ch[0] = '\0'; } if (latest == NULL) { if (source == NULL && OUTPUT('!')) { printf("%-34s !", tmp); if (Verbose) printf(" Comparison failed"); printf("\n"); } else if (source != NULL && OUTPUT('?')) { printf("%-34s ?", tmp); if (Verbose) printf(" orphaned: %s", source); printf("\n"); } } else if (strchr(latest,'|') != NULL) { if (OUTPUT('*')) { printf("%-34s *", tmp); if (Verbose) { strlcpy(tmp, latest, PATH_MAX); ch = strchr(tmp, '|'); ch[0] = '\0'; ver = strrchr(tmp, '-'); ver = ver ? &ver[1] : tmp; printf(" multiple versions (index has %s", ver); do { ver = strrchr(&ch[1], '-'); ver = ver ? &ver[1] : &ch[1]; if ((ch = strchr(&ch[1], '|')) != NULL) ch[0] = '\0'; printf(", %s", ver); } while (ch != NULL); printf(")"); } printf("\n"); } } else { cmp = version_cmp(installed, latest); ver = strrchr(latest, '-'); ver = ver ? &ver[1] : latest; if (cmp < 0 && OUTPUT('<')) { printf("%-34s <", tmp); if (Verbose) printf(" needs updating (%s has %s)", source, ver); printf("\n"); } else if (cmp == 0 && OUTPUT('=')) { printf("%-34s =", tmp); if (Verbose) printf(" up-to-date with %s", source); printf("\n"); } else if (cmp > 0 && OUTPUT('>')) { printf("%-34s >", tmp); if (Verbose) printf(" succeeds %s (%s has %s)", source, source, ver); printf("\n"); } } } int version_match(char *pattern, const char *pkgname) { int ret = 0; int matchstream = 0; FILE *fp = NULL; Boolean isTMP = FALSE; if (isURL(pkgname)) { fp = fetchGetURL(pkgname, ""); isTMP = TRUE; matchstream = 1; if (fp == NULL) errx(2, "Unable to open %s.", pkgname); } else if (pkgname[0] == '/') { fp = fopen(pkgname, "r"); isTMP = TRUE; matchstream = 1; if (fp == NULL) errx(2, "Unable to open %s.", pkgname); } else if (strcmp(pkgname, "-") == 0) { fp = stdin; matchstream = 1; } else if (isURL(pattern)) { fp = fetchGetURL(pattern, ""); isTMP = TRUE; matchstream = -1; if (fp == NULL) errx(2, "Unable to open %s.", pattern); } else if (pattern[0] == '/') { fp = fopen(pattern, "r"); isTMP = TRUE; matchstream = -1; if (fp == NULL) errx(2, "Unable to open %s.", pattern); } else if (strcmp(pattern, "-") == 0) { fp = stdin; matchstream = -1; } else { ret = pattern_match(MATCH_GLOB, pattern, pkgname); } if (fp != NULL) { size_t len; char *line; while ((line = fgetln(fp, &len)) != NULL) { int match; char *ch, ln[2048]; size_t lnlen; if (len > 0 && line[len-1] == '\n') len --; lnlen = len; if (lnlen > sizeof(ln)-1) lnlen = sizeof(ln)-1; memcpy(ln, line, lnlen); ln[lnlen] = '\0'; if ((ch = strchr(ln, '|')) != NULL) ch[0] = '\0'; if (matchstream > 0) match = pattern_match(MATCH_GLOB, pattern, ln); else match = pattern_match(MATCH_GLOB, ln, pkgname); if (match == 1) { ret = 1; printf("%.*s\n", (int)len, line); } } if (isTMP) fclose(fp); } return ret; } void cleanup(int sig) { if (sig) exit(1); }