diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c index 1af00ec4ff95..32443b225cea 100644 --- a/usr.sbin/pkg_install/info/perform.c +++ b/usr.sbin/pkg_install/info/perform.c @@ -1,11 +1,11 @@ -/* $NetBSD: perform.c,v 1.8 1998/08/25 00:54:09 hubertf Exp $ */ +/* $NetBSD: perform.c,v 1.9 1998/08/27 12:54:03 agc Exp $ */ #include #ifndef lint #if 0 static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp"; #else -__RCSID("$NetBSD: perform.c,v 1.8 1998/08/25 00:54:09 hubertf Exp $"); +__RCSID("$NetBSD: perform.c,v 1.9 1998/08/27 12:54:03 agc Exp $"); #endif #endif @@ -32,232 +32,355 @@ __RCSID("$NetBSD: perform.c,v 1.8 1998/08/25 00:54:09 hubertf Exp $"); #include "lib.h" #include "info.h" +#include +#include + #include #include -#include #include #include +#include -static int pkg_do(char *); - -int -pkg_perform(char **pkgs) -{ - int i, err_cnt = 0; - char *tmp; - - signal(SIGINT, cleanup); - - tmp = getenv(PKG_DBDIR); - if (!tmp) - tmp = DEF_LOG_DIR; - /* Overriding action? */ - if (CheckPkg) { - if (!strpbrk(CheckPkg,"*?[]")) { - /* No shell meta character given - simple check */ - char buf[FILENAME_MAX]; - int error; - - snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); - error=abs(access(buf, R_OK)); - if (!error && !Quiet) - printf("%s\n",CheckPkg); - return error; - } else { - /* Using glob-match */ - int found; - DIR *d; - struct dirent *dp; - - found=0; - d=opendir(tmp); - if (d == NULL) { - warnx("can't opendir package dir '%s'", tmp); - return !0; - } - - while ((dp=readdir(d))){ - if (fnmatch(CheckPkg, dp->d_name, FNM_PERIOD)==0) { - if (!Quiet) - printf("%s\n",dp->d_name); - found=1; - } - } - closedir(d); - - return !found; /* negate logic for shell return code */ - } - } - else if (AllInstalled) { - DIR *dirp; - struct dirent *dp; - - if (!isdir(tmp)) - return 1; - dirp = opendir(tmp); - if (dirp) { - for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) - if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) - err_cnt += pkg_do(dp->d_name); - (void)closedir(dirp); - } - } - else - for (i = 0; pkgs[i]; i++) - err_cnt += pkg_do(pkgs[i]); - return err_cnt; -} - -static char *Home; +static char *Home; static int pkg_do(char *pkg) { - Boolean installed = FALSE, isTMP = FALSE; - char log_dir[FILENAME_MAX]; - char fname[FILENAME_MAX]; - Package plist; - FILE *fp; - struct stat sb; - char *cp = NULL; - int code = 0; + Boolean installed = FALSE, isTMP = FALSE; + char log_dir[FILENAME_MAX]; + char fname[FILENAME_MAX]; + Package plist; + FILE *fp; + struct stat sb; + char *cp = NULL; + int code = 0; - if (isURL(pkg)) { - if ((cp = fileGetURL(NULL, pkg)) != NULL) { - strcpy(fname, cp); - isTMP = TRUE; - } - } - else if (fexists(pkg) && isfile(pkg)) { - int len; + if (isURL(pkg)) { + if ((cp = fileGetURL(NULL, pkg)) != NULL) { + strcpy(fname, cp); + isTMP = TRUE; + } + } else if (fexists(pkg) && isfile(pkg)) { + int len; - if (*pkg != '/') { - if (!getcwd(fname, FILENAME_MAX)) - upchuck("getcwd"); - len = strlen(fname); - snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); + if (*pkg != '/') { + if (!getcwd(fname, FILENAME_MAX)) + upchuck("getcwd"); + len = strlen(fname); + snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); + } else + strcpy(fname, pkg); + cp = fname; + } else { + if ((cp = fileFindByPath(NULL, pkg)) != NULL) + strncpy(fname, cp, FILENAME_MAX); + } + if (cp) { + if (isURL(pkg)) { + /* file is already unpacked by fileGetURL() */ + strcpy(PlayPen, cp); + } else { + /* + * 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%, but we're only unpacking the + files so + * be very optimistic. + */ + if (stat(fname, &sb) == FAIL) { + warnx("can't stat package file '%s'", fname); + code = 1; + goto bail; + } + Home = make_playpen(PlayPen, sb.st_size / 2); + if (unpack(fname, "+*")) { + warnx("error during unpacking, no info for '%s' available", pkg); + code = 1; + goto bail; + } + } } - else - strcpy(fname, pkg); - cp = fname; - } - else { - if ((cp = fileFindByPath(NULL, pkg)) != NULL) - strncpy(fname, cp, FILENAME_MAX); - } - if (cp) { - if (isURL(pkg)) { - /* file is already unpacked by fileGetURL() */ - strcpy(PlayPen,cp); - } - else { /* - * 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%, but we're only unpacking the + files so - * be very optimistic. + * It's not an ininstalled package, try and find it among the + * installed */ - if (stat(fname, &sb) == FAIL) { - warnx("can't stat package file '%s'", fname); - code = 1; - goto bail; - } - Home = make_playpen(PlayPen, sb.st_size / 2); - if (unpack(fname, "+*")) { - warnx("error during unpacking, no info for '%s' available", pkg); - code = 1; - goto bail; - } - } - } - /* It's not an ininstalled package, try and find it among the installed */ - else { - char *tmp; + else { + char *tmp; - sprintf(log_dir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, - pkg); - if (!fexists(log_dir)) { - warnx("can't find package `%s' installed or in a file!", pkg); - return 1; + sprintf(log_dir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, + pkg); + if (!fexists(log_dir)) { + warnx("can't find package `%s' installed or in a file!", pkg); + return 1; + } + if (chdir(log_dir) == FAIL) { + warnx("can't change directory to '%s'!", log_dir); + return 1; + } + installed = TRUE; } - if (chdir(log_dir) == FAIL) { - warnx("can't change directory to '%s'!", log_dir); - return 1; + + /* Suck in the contents list */ + plist.head = plist.tail = NULL; + fp = fopen(CONTENTS_FNAME, "r"); + if (!fp) { + warnx("unable to open %s file", CONTENTS_FNAME); + code = 1; + goto bail; } - installed = TRUE; - } + /* If we have a prefix, add it now */ + read_plist(&plist, fp); + fclose(fp); - /* Suck in the contents list */ - plist.head = plist.tail = NULL; - fp = fopen(CONTENTS_FNAME, "r"); - if (!fp) { - warnx("unable to open %s file", CONTENTS_FNAME); - code = 1; - goto bail; - } - /* If we have a prefix, add it now */ - read_plist(&plist, fp); - fclose(fp); + /* + * Index is special info type that has to override all others to make + * any sense. + */ + if (Flags & SHOW_INDEX) { + char tmp[FILENAME_MAX]; - /* - * Index is special info type that has to override all others to make - * any sense. - */ - if (Flags & SHOW_INDEX) { - char tmp[FILENAME_MAX]; + snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); + show_index(tmp, COMMENT_FNAME); + } else { + /* Start showing the package contents */ + if (!Quiet) + printf("%sInformation for %s:\n\n", InfoPrefix, pkg); + if (Flags & SHOW_COMMENT) + show_file("Comment:\n", COMMENT_FNAME); + if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) + show_file("Required by:\n", REQUIRED_BY_FNAME); + if (Flags & SHOW_DESC) + show_file("Description:\n", DESC_FNAME); + if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) + show_file("Install notice:\n", DISPLAY_FNAME); + if (Flags & SHOW_PLIST) + show_plist("Packing list:\n", &plist, (plist_t) - 1); + if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) + show_file("Install script:\n", INSTALL_FNAME); + if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) + show_file("De-Install script:\n", DEINSTALL_FNAME); + if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) + show_file("mtree file:\n", MTREE_FNAME); + if (Flags & SHOW_PREFIX) + show_plist("Prefix(s):\n", &plist, PLIST_CWD); + if (Flags & SHOW_FILES) + show_files("Files:\n", &plist); + if (!Quiet) + puts(InfoPrefix); + } + free_plist(&plist); +bail: + leave_playpen(Home); + if (isTMP) + unlink(fname); + return code; +} - snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); - show_index(tmp, COMMENT_FNAME); - } - else { - /* Start showing the package contents */ - if (!Quiet) - printf("%sInformation for %s:\n\n", InfoPrefix, pkg); - if (Flags & SHOW_COMMENT) - show_file("Comment:\n", COMMENT_FNAME); - if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) - show_file("Required by:\n", REQUIRED_BY_FNAME); - if (Flags & SHOW_DESC) - show_file("Description:\n", DESC_FNAME); - if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) - show_file("Install notice:\n", DISPLAY_FNAME); - if (Flags & SHOW_PLIST) - show_plist("Packing list:\n", &plist, (plist_t)-1); - if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) - show_file("Install script:\n", INSTALL_FNAME); - if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) - show_file("De-Install script:\n", DEINSTALL_FNAME); - if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) - show_file("mtree file:\n", MTREE_FNAME); - if (Flags & SHOW_PREFIX) - show_plist("Prefix(s):\n", &plist, PLIST_CWD); - if (Flags & SHOW_FILES) - show_files("Files:\n", &plist); - if (!Quiet) - puts(InfoPrefix); - } - free_plist(&plist); - bail: - leave_playpen(Home); - if (isTMP) - unlink(fname); - return code; +/* use fnmatch to do a glob-style match */ +/* returns 0 if found, 1 if not (1) */ +static int +globmatch(char *pkgspec, char *dbdir, int quiet) +{ + /* Using glob-match */ + struct dirent *dp; + int found; + DIR *dirp; + + found = 0; + if ((dirp = opendir(dbdir)) == (DIR *) NULL) { + warnx("can't opendir package dir '%s'", dbdir); + return !0; + } + while ((dp = readdir(dirp)) != (struct dirent *) NULL) { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) { + continue; + } + if (fnmatch(pkgspec, dp->d_name, FNM_PERIOD) == 0) { + if (!quiet) + printf("%s\n", dp->d_name); + found = 1; + } + } + closedir(dirp); + return !found; +} + +enum { + GT, + GE, + LT, + LE +}; + +/* compare two dewey decimal numbers */ +static int +deweycmp(char *a, int op, char *b) +{ + int ad; + int bd; + int cmp; + + for (;;) { + if (*a == 0 && *b == 0) { + cmp = 0; + break; + } + ad = bd = 0; + for ( ; *a && *a != '.' ; a++) { + ad = (ad * 10) + (*a - '0'); + } + for ( ; *b && *b != '.' ; b++) { + bd = (bd * 10) + (*b - '0'); + } + if ((cmp = ad - bd) != 0) { + break; + } + if (*a == '.') { + a++; + } + if (*b == '.') { + b++; + } + } + return (op == GE) ? cmp >= 0 : (op == GT) ? cmp > 0 : (op == LE) ? cmp <= 0 : cmp < 0; +} + +/* match on a relation against dewey decimal numbers */ +/* returns 0 if found, 1 if not (!) */ +static int +deweymatch(char *name, int op, char *ver, char *dbdir, int quiet) +{ + struct dirent *dp; + char *cp; + DIR *dirp; + int ret; + int n; + + n = strlen(name); + ret = 1; + if ((dirp = opendir(dbdir)) == (DIR *) NULL) { + warnx("can't opendir package dir '%s'", dbdir); + return 1; + } + while ((dp = readdir(dirp)) != (struct dirent *) NULL) { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) { + continue; + } + if ((cp = strrchr(dp->d_name, '-')) != (char *) NULL) { + if (strncmp(dp->d_name, name, cp - dp->d_name) == 0 && n == cp - dp->d_name) { + if (deweycmp(cp + 1, op, ver)) { + if (!quiet) + printf("%s\n", dp->d_name); + ret = 0; + } + } + } + } + closedir(dirp); + return ret; +} + +/* do a match on a package pattern in dbdir */ +/* returns 0 if found, 1 if not (!) */ +static int +matchname(char *pkgspec, char *dbdir, int quiet) +{ + struct stat st; + char buf[FILENAME_MAX]; + char *sep; + char *last; + char *alt; + char *cp; + int error; + int cnt; + int ret; + + if ((sep = strchr(pkgspec, '{')) != (char *) NULL) { + /* emulate csh-type alternates */ + (void) strncpy(buf, pkgspec, sep - pkgspec); + alt = &buf[sep - pkgspec]; + for (last = NULL, cnt = 0, cp = sep ; *cp && !last ; cp++) { + if (*cp == '{') { + cnt++; + } else if (*cp == '}' && --cnt == 0 && last == NULL) { + last = cp + 1; + } + } + if (cnt != 0) { + warnx("Malformed alternate `%s'", pkgspec); + return 1; + } + for (ret = 1, cp = sep + 1 ; *sep != '}' ; cp = sep + 1) { + for (cnt = 0, sep = cp ; cnt > 0 || (cnt == 0 && *sep != '}' && *sep != ',') ; sep++) { + if (*sep == '{') { + cnt++; + } else if (*sep == '}') { + cnt--; + } + } + (void) snprintf(alt, sizeof(buf) - (alt - buf), "%.*s%s", sep - cp, cp, last); + if (matchname(buf, dbdir, quiet) == 0) { + ret = 0; + } + } + return ret; + } + if ((sep = strpbrk(pkgspec, "<>")) != (char *) NULL) { + /* perform relational dewey match on version number */ + (void) snprintf(buf, sizeof(buf), "%.*s", sep - pkgspec, pkgspec); + cnt = (*sep == '>') ? (*(sep + 1) == '=') ? GE : GT : (*(sep + 1) == '=') ? LE : LT; + cp = (cnt == GE || cnt == LE) ? sep + 2 : sep + 1; + return deweymatch(buf, cnt, cp, dbdir, quiet); + } + if (strpbrk(pkgspec, "*?[]") != (char *) NULL) { + return globmatch(pkgspec, dbdir, quiet); + } + /* No shell meta character given - simple check */ + (void) snprintf(buf, sizeof(buf), "%s/%s", dbdir, pkgspec); + error = (lstat(buf, &st) < 0); + if (!error && !quiet) + printf("%s\n", pkgspec); + return error; } void cleanup(int sig) { - static int alreadyCleaning; - void (*oldint)(int); - oldint = signal(SIGINT, SIG_IGN); - - if (!alreadyCleaning) { - alreadyCleaning = 1; - if (sig) - printf("Signal %d received, cleaning up.\n", sig); leave_playpen(Home); - if (sig) - exit(1); - } - signal(SIGINT, oldint); + exit(1); +} + +int +pkg_perform(char **pkgs) +{ + int i, err_cnt = 0; + char *tmp; + + signal(SIGINT, cleanup); + + tmp = getenv(PKG_DBDIR); + if (!tmp) + tmp = DEF_LOG_DIR; + /* Overriding action? */ + if (CheckPkg) { + return matchname(CheckPkg, tmp, Quiet); + } else if (AllInstalled) { + struct dirent *dp; + DIR *dirp; + + if (!isdir(tmp)) + return 1; + if ((dirp = opendir(tmp)) != (DIR *) NULL) { + while ((dp = readdir(dirp)) != (struct dirent *) NULL) { + if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) { + err_cnt += pkg_do(dp->d_name); + } + } + (void) closedir(dirp); + } + } else { + for (i = 0; pkgs[i]; i++) { + err_cnt += pkg_do(pkgs[i]); + } + } + return err_cnt; } diff --git a/usr.sbin/pkg_install/info/pkg_info.1 b/usr.sbin/pkg_install/info/pkg_info.1 index 796172fc36bc..876a39f3853e 100644 --- a/usr.sbin/pkg_install/info/pkg_info.1 +++ b/usr.sbin/pkg_install/info/pkg_info.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: pkg_info.1,v 1.8 1998/08/23 10:16:19 tron Exp $ +.\" $NetBSD: pkg_info.1,v 1.9 1998/08/27 12:54:03 agc Exp $ .\" .\" FreeBSD install - a package for the installation and maintainance .\" of non-core utilities. @@ -63,11 +63,25 @@ shell metacharacter, it will be matched against all installed packages using .Xr fnmatch 3 , and any packages found installed are printed to stdout, one name per -line. This printing can be turned off using the +line. +.Xr csh 1 +style {,} alternates have also been implemented. +Dewey decimal numbers can also be matched in a relational manner, +using the +.Pa >=, <=, > +and +.Pa < +operators. +For example, +.Pa pkg_info -e 'name>=1.3' +will match versions 1.3 and later of the +.Pa name +package. +This printing can be turned off using the .Fl q option. This option -allows you to easily test for the presence of another (perhaps +allows you to test for the presence of another (perhaps prerequisite) package from a script. .It Fl f Show the packing list instructions for each package.