From 2eb4b00cbb86ee4591b3a60e96b94e51085c3939 Mon Sep 17 00:00:00 2001 From: Florent Thoumie Date: Tue, 17 May 2011 19:11:47 +0000 Subject: Backout libinstall.a -> libpkg commit. Discussed with: erwin, brooks, bapt --- Makefile.inc1 | 5 +- lib/Makefile | 5 - lib/libpkg/Makefile | 47 --- lib/libpkg/deps.c | 241 ------------- lib/libpkg/exec.c | 106 ------ lib/libpkg/file.c | 436 ------------------------ lib/libpkg/global.c | 32 -- lib/libpkg/match.c | 603 --------------------------------- lib/libpkg/msg.c | 70 ---- lib/libpkg/pen.c | 179 ---------- lib/libpkg/pkg.h | 246 -------------- lib/libpkg/pkgwrap.c | 90 ----- lib/libpkg/plist.c | 592 -------------------------------- lib/libpkg/str.c | 129 ------- lib/libpkg/url.c | 171 ---------- lib/libpkg/version.c | 338 ------------------ share/mk/bsd.libnames.mk | 1 - usr.sbin/pkg_install/Makefile | 4 +- usr.sbin/pkg_install/Makefile.inc | 13 +- usr.sbin/pkg_install/add/Makefile | 7 +- usr.sbin/pkg_install/add/extract.c | 2 +- usr.sbin/pkg_install/add/futil.c | 2 +- usr.sbin/pkg_install/add/main.c | 4 +- usr.sbin/pkg_install/add/perform.c | 2 +- usr.sbin/pkg_install/create/Makefile | 6 +- usr.sbin/pkg_install/create/main.c | 4 +- usr.sbin/pkg_install/create/perform.c | 2 +- usr.sbin/pkg_install/create/pl.c | 2 +- usr.sbin/pkg_install/delete/Makefile | 5 + usr.sbin/pkg_install/delete/main.c | 4 +- usr.sbin/pkg_install/delete/perform.c | 2 +- usr.sbin/pkg_install/info/Makefile | 6 +- usr.sbin/pkg_install/info/info.h | 39 ++- usr.sbin/pkg_install/info/main.c | 14 +- usr.sbin/pkg_install/info/perform.c | 2 +- usr.sbin/pkg_install/info/show.c | 2 +- usr.sbin/pkg_install/lib/Makefile | 11 + usr.sbin/pkg_install/lib/deps.c | 241 +++++++++++++ usr.sbin/pkg_install/lib/exec.c | 106 ++++++ usr.sbin/pkg_install/lib/file.c | 436 ++++++++++++++++++++++++ usr.sbin/pkg_install/lib/global.c | 32 ++ usr.sbin/pkg_install/lib/lib.h | 242 +++++++++++++ usr.sbin/pkg_install/lib/match.c | 603 +++++++++++++++++++++++++++++++++ usr.sbin/pkg_install/lib/msg.c | 75 ++++ usr.sbin/pkg_install/lib/pen.c | 186 ++++++++++ usr.sbin/pkg_install/lib/pkgwrap.c | 89 +++++ usr.sbin/pkg_install/lib/plist.c | 592 ++++++++++++++++++++++++++++++++ usr.sbin/pkg_install/lib/str.c | 129 +++++++ usr.sbin/pkg_install/lib/url.c | 171 ++++++++++ usr.sbin/pkg_install/lib/version.c | 328 ++++++++++++++++++ usr.sbin/pkg_install/updating/Makefile | 5 + usr.sbin/pkg_install/updating/main.c | 4 +- usr.sbin/pkg_install/version/Makefile | 5 + usr.sbin/pkg_install/version/main.c | 4 +- usr.sbin/pkg_install/version/perform.c | 2 +- 55 files changed, 3317 insertions(+), 3357 deletions(-) delete mode 100644 lib/libpkg/Makefile delete mode 100644 lib/libpkg/deps.c delete mode 100644 lib/libpkg/exec.c delete mode 100644 lib/libpkg/file.c delete mode 100644 lib/libpkg/global.c delete mode 100644 lib/libpkg/match.c delete mode 100644 lib/libpkg/msg.c delete mode 100644 lib/libpkg/pen.c delete mode 100644 lib/libpkg/pkg.h delete mode 100644 lib/libpkg/pkgwrap.c delete mode 100644 lib/libpkg/plist.c delete mode 100644 lib/libpkg/str.c delete mode 100644 lib/libpkg/url.c delete mode 100644 lib/libpkg/version.c create mode 100644 usr.sbin/pkg_install/lib/Makefile create mode 100644 usr.sbin/pkg_install/lib/deps.c create mode 100644 usr.sbin/pkg_install/lib/exec.c create mode 100644 usr.sbin/pkg_install/lib/file.c create mode 100644 usr.sbin/pkg_install/lib/global.c create mode 100644 usr.sbin/pkg_install/lib/lib.h create mode 100644 usr.sbin/pkg_install/lib/match.c create mode 100644 usr.sbin/pkg_install/lib/msg.c create mode 100644 usr.sbin/pkg_install/lib/pen.c create mode 100644 usr.sbin/pkg_install/lib/pkgwrap.c create mode 100644 usr.sbin/pkg_install/lib/plist.c create mode 100644 usr.sbin/pkg_install/lib/str.c create mode 100644 usr.sbin/pkg_install/lib/url.c create mode 100644 usr.sbin/pkg_install/lib/version.c diff --git a/Makefile.inc1 b/Makefile.inc1 index 907cdce7d5bf..4aa53da83d2f 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1205,7 +1205,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} ${_kerberos5_lib_libheimntlm} \ ${_kerberos5_lib_libhx509} ${_kerberos5_lib_libkrb5} \ ${_kerberos5_lib_libroken} \ lib/libbz2 lib/libcom_err lib/libcrypt \ - lib/libexpat lib/libfetch \ + lib/libexpat \ ${_lib_libgssapi} ${_lib_libipx} \ lib/libkiconv lib/libkvm lib/liblzma lib/libmd \ lib/ncurses/ncurses lib/ncurses/ncursesw \ @@ -1238,7 +1238,6 @@ _cddl_lib= cddl/lib _secure_lib_libcrypto= secure/lib/libcrypto _secure_lib_libssl= secure/lib/libssl lib/libradius__L secure/lib/libssl__L: secure/lib/libcrypto__L -lib/libfetch__L: secure/lib/libcrypto__L secure/lib/libssl__L lib/libmd__L .if ${MK_OPENSSH} != "no" _secure_lib_libssh= secure/lib/libssh secure/lib/libssh__L: lib/libz__L secure/lib/libcrypto__L lib/libcrypt__L @@ -1274,7 +1273,7 @@ _lib_libypclnt= lib/libypclnt .endif .if ${MK_OPENSSL} == "no" -lib/libfetch__L lib/libradius__L: lib/libmd__L +lib/libradius__L: lib/libmd__L .endif .for _lib in ${_prereq_libs} diff --git a/lib/Makefile b/lib/Makefile index 7be186fca21c..eef204899cde 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -89,7 +89,6 @@ SUBDIR= ${SUBDIR_ORDERED} \ libopie \ libpam \ libpcap \ - ${_libpkg} \ ${_libpmc} \ ${_libproc} \ libprocstat \ @@ -215,10 +214,6 @@ _libmp= libmp _libpmc= libpmc .endif -.if ${MK_PKGTOOLS} != "no" -_libpkg= libpkg -.endif - .if ${MK_SENDMAIL} != "no" _libmilter= libmilter _libsm= libsm diff --git a/lib/libpkg/Makefile b/lib/libpkg/Makefile deleted file mode 100644 index 8f2b325f0980..000000000000 --- a/lib/libpkg/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# $FreeBSD$ - -.include - -LIB= pkg - -SHLIBDIR?= /usr/lib -SHLIB_MAJOR= 0 - -SRCS= deps.c \ - exec.c \ - file.c \ - global.c \ - match.c \ - msg.c \ - pen.c \ - pkgwrap.c \ - plist.c \ - str.c \ - url.c \ - version.c -INCS= pkg.h - -CFLAGS+= -DYES_I_KNOW_THE_API_IS_RUBBISH_AND_IS_DOOMED_TO_CHANGE - -DPADD= ${LIBFETCH} ${LIBMD} ${LIBUTIL} -LDADD= -lfetch -lmd -lutil - -.if ${MK_OPENSSL} != "no" -DPADD+= ${LIBSSL} ${LIBCRYPTO} -LDADD+= -lssl -lcrypto -.endif - -WARNS?= 3 - -DATE!= grep LIBPKG_VERSION ${.CURDIR}/pkg.h | sed 's|.*[ ]||' - -distfile: clean - @(cd ${.CURDIR}/..; \ - cp -r libpkg libpkg-${DATE}; \ - tar -czf libpkg/libpkg-${DATE}.tar.gz \ - --exclude .#* --exclude *~ --exclude CVS \ - --exclude .svn --exclude libpkg-*.tar.gz \ - libpkg-${DATE}; \ - rm -rf libpkg-${DATE}) - -.include diff --git a/lib/libpkg/deps.c b/lib/libpkg/deps.c deleted file mode 100644 index 101d04602192..000000000000 --- a/lib/libpkg/deps.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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 - * 14 March 2001 - * - * Routines used to do various operations with dependencies - * among installed packages. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" -#include -#include - -void list_deps(const char *pkgname, char **pkgs, char *listed, - char *check_loop, char **newpkgs, int *nrnewpkgs, - int *err_cnt); - -/* - * Sort given NULL-terminated list of installed packages (pkgs) in - * such a way that if package A depends on package B then after - * sorting A will be listed before B no matter how they were - * originally positioned in the list. - * - * Works by performing a recursive depth-first search on the - * required-by lists. - */ - -int -sortdeps(char **pkgs) -{ - int i, err_cnt=0; - int nrpkgs, nrnewpkgs; - char *listed, *check_loop, **newpkgs; - char *cp; - - if (pkgs[0] == NULL || pkgs[1] == NULL) - return (0); - - nrpkgs = 0; - while (pkgs[nrpkgs]) nrpkgs++; - listed = alloca(nrpkgs); - if (listed == NULL) { - warnx("%s(): alloca() failed", __func__); - return 1; - } - bzero(listed,nrpkgs); - check_loop = alloca(nrpkgs); - if (check_loop == NULL) { - warnx("%s(): alloca() failed", __func__); - return 1; - } - bzero(check_loop,nrpkgs); - newpkgs = alloca(nrpkgs*sizeof(char*)); - if (newpkgs == NULL) { - warnx("%s(): alloca() failed", __func__); - return 1; - } - nrnewpkgs = 0; - - for (i = 0; pkgs[i]; i++) if (!listed[i]) { - check_loop[i] = 1; - cp = strchr(pkgs[i], ':'); - if (cp != NULL) - *cp = '\0'; - list_deps(pkgs[i],pkgs,listed,check_loop,newpkgs,&nrnewpkgs,&err_cnt); - if (cp != NULL) - *cp = ':'; - listed[i] = 1; - newpkgs[nrnewpkgs] = pkgs[i]; - nrnewpkgs++; - } - - if (nrnewpkgs != nrpkgs) { - fprintf(stderr,"This shouldn't happen, and indicates a huge error in the code.\n"); - exit(1); - } - for (i = 0; i < nrnewpkgs; i++) pkgs[i] = newpkgs[i]; - - return err_cnt; -} - -/* - * This recursive function lists the dependencies (that is, the - * "required-by"s) for pkgname, putting them into newpkgs. - */ - -void list_deps(const char *pkgname, char **pkgs, char *listed, - char *check_loop, char **newpkgs, int *nrnewpkgs, - int *err_cnt) { - char **rb, **rbtmp; - char *cp; - int errcode, i, j; - struct reqr_by_entry *rb_entry; - struct reqr_by_head *rb_list; - - if (isinstalledpkg(pkgname) <= 0) - return; - - errcode = requiredby(pkgname, &rb_list, FALSE, TRUE); - if (errcode < 0) - return; - /* - * We put rb_list into an argv style NULL terminated list, - * because requiredby uses some static storage, and list_deps - * is a recursive function. - */ - - rbtmp = rb = alloca((errcode + 1) * sizeof(*rb)); - if (rb == NULL) { - warnx("%s(): alloca() failed", __func__); - (*err_cnt)++; - return; - } - STAILQ_FOREACH(rb_entry, rb_list, link) { - *rbtmp = alloca(strlen(rb_entry->pkgname) + 1); - if (*rbtmp == NULL) { - warnx("%s(): alloca() failed", __func__); - (*err_cnt)++; - return; - } - strcpy(*rbtmp, rb_entry->pkgname); - rbtmp++; - } - *rbtmp = NULL; - - for (i = 0; rb[i]; i++) - for (j = 0; pkgs[j]; j++) if (!listed[j]) { - cp = strchr(pkgs[j], ':'); - if (cp != NULL) - *cp = '\0'; - if (strcmp(rb[i], pkgs[j]) == 0) { /*match */ - /* - * Try to avoid deadlock if package A depends on B which in - * turn depends on C and C due to an error depends on A. - * It Should Never Happen[tm] in real life. - */ - if (check_loop[j]) { - warnx("dependency loop detected for package %s", pkgs[j]); - (*err_cnt)++; - } - else { - check_loop[j] = 1; - list_deps(pkgs[j],pkgs,listed,check_loop,newpkgs,nrnewpkgs,err_cnt); - listed[j] = 1; - newpkgs[*nrnewpkgs] = pkgs[j]; - (*nrnewpkgs)++; - } - } - if (cp != NULL) - *cp = ':'; - } -} - -/* - * Load +REQUIRED_BY file and return a list with names of - * packages that require package reffered to by `pkgname'. - * - * Optionally check that packages listed there are actually - * installed and filter out those that don't (filter == TRUE). - * - * strict argument controls whether the caller want warnings - * to be emitted when there are some non-fatal conditions, - * i.e. package doesn't have +REQUIRED_BY file or some packages - * listed in +REQUIRED_BY don't exist. - * - * Result returned in the **list, while return value is equal - * to the number of entries in the resulting list. Print error - * message and return -1 on error. - */ -int -requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter) -{ - FILE *fp; - char fbuf[FILENAME_MAX], fname[FILENAME_MAX]; - int retval; - struct reqr_by_entry *rb_entry; - static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list); - - *list = &rb_list; - /* Deallocate any previously allocated space */ - while (!STAILQ_EMPTY(&rb_list)) { - rb_entry = STAILQ_FIRST(&rb_list); - STAILQ_REMOVE_HEAD(&rb_list, link); - free(rb_entry); - } - - if (isinstalledpkg(pkgname) <= 0) { - if (strict == TRUE) - warnx("no such package '%s' installed", pkgname); - return -1; - } - - snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, pkgname, - REQUIRED_BY_FNAME); - fp = fopen(fname, "r"); - if (fp == NULL) { - /* Probably pkgname doesn't have any packages that depend on it */ - if (strict == TRUE) - warnx("couldn't open dependency file '%s'", fname); - return 0; - } - - retval = 0; - while (fgets(fbuf, sizeof(fbuf), fp) != NULL) { - if (fbuf[strlen(fbuf) - 1] == '\n') - fbuf[strlen(fbuf) - 1] = '\0'; - if (filter == TRUE && isinstalledpkg(fbuf) <= 0) { - if (strict == TRUE) - warnx("package '%s' is recorded in the '%s' but isn't " - "actually installed", fbuf, fname); - continue; - } - retval++; - rb_entry = malloc(sizeof(*rb_entry)); - if (rb_entry == NULL) { - warnx("%s(): malloc() failed", __func__); - retval = -1; - break; - } - strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname)); - STAILQ_INSERT_TAIL(&rb_list, rb_entry, link); - } - fclose(fp); - - return retval; -} diff --git a/lib/libpkg/exec.c b/lib/libpkg/exec.c deleted file mode 100644 index 04891d3cc09a..000000000000 --- a/lib/libpkg/exec.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 system routines. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" -#include - -/* - * Unusual system() substitute. Accepts format string and args, - * builds and executes command. Returns exit code. - */ - -int -vsystem(const char *fmt, ...) -{ - va_list args; - char *cmd; - int ret, maxargs; - - maxargs = sysconf(_SC_ARG_MAX); - maxargs -= 32; /* some slop for the sh -c */ - cmd = malloc(maxargs); - if (!cmd) { - warnx("vsystem can't alloc arg space"); - return 1; - } - - va_start(args, fmt); - if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) { - warnx("vsystem args are too long"); - return 1; - } -#ifdef DEBUG -printf("Executing %s\n", cmd); -#endif - ret = system(cmd); - va_end(args); - free(cmd); - return ret; -} - -char * -vpipe(const char *fmt, ...) -{ - FILE *fp; - char *cmd, *rp; - int maxargs; - va_list args; - - rp = malloc(MAXPATHLEN); - if (!rp) { - warnx("vpipe can't alloc buffer space"); - return NULL; - } - maxargs = sysconf(_SC_ARG_MAX); - maxargs -= 32; /* some slop for the sh -c */ - cmd = alloca(maxargs); - if (!cmd) { - warnx("vpipe can't alloc arg space"); - return NULL; - } - - va_start(args, fmt); - if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) { - warnx("vsystem args are too long"); - return NULL; - } -#ifdef DEBUG - fprintf(stderr, "Executing %s\n", cmd); -#endif - fflush(NULL); - fp = popen(cmd, "r"); - if (fp == NULL) { - warnx("popen() failed"); - return NULL; - } - get_string(rp, MAXPATHLEN, fp); -#ifdef DEBUG - fprintf(stderr, "Returned %s\n", rp); -#endif - va_end(args); - if (pclose(fp) || (strlen(rp) == 0)) { - free(rp); - return NULL; - } - return rp; -} diff --git a/lib/libpkg/file.c b/lib/libpkg/file.c deleted file mode 100644 index 7c95f995a2fe..000000000000 --- a/lib/libpkg/file.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * 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 "pkg.h" -#include -#include -#include -#include - -/* Quick check to see if a file exists */ -Boolean -fexists(const char *fname) -{ - int fd; - - if ((fd = open(fname, O_RDONLY)) == -1) - return FALSE; - - close(fd); - return TRUE; -} - -/* 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 %lld 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, "/bin/cp -r %s %s", fname, to); - else - 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 *tdir) -{ - char from[FILENAME_MAX]; - char to[FILENAME_MAX]; - - if (fname[0] == '/') - strncpy(from, fname, FILENAME_MAX); - else - snprintf(from, FILENAME_MAX, "%s/%s", dir, fname); - - snprintf(to, FILENAME_MAX, "%s/%s", tdir, fname); - - if (rename(from, to) == -1) { - if (vsystem("/bin/mv %s %s", from, to)) { - cleanup(0); - errx(2, "%s: could not move '%s' to '%s'", __func__, from, to); - } - } -} - -/* - * 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, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -", - dir, fname); - } - else - 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 - comp = "-j"; - 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'; -} diff --git a/lib/libpkg/global.c b/lib/libpkg/global.c deleted file mode 100644 index 8103126e6935..000000000000 --- a/lib/libpkg/global.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 - * - * Semi-convenient place to stick some needed globals. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" - -/* These are global for all utils */ -Boolean Quiet = FALSE; -Boolean Fake = FALSE; -Boolean Force = FALSE; -int AutoAnswer = FALSE; -int Verbose = 0; /* Allow multiple levels of verbose. */ diff --git a/lib/libpkg/match.c b/lib/libpkg/match.c deleted file mode 100644 index ba6544224dcf..000000000000 --- a/lib/libpkg/match.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * 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 "pkg.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 = 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 *** -matchallbyorigin(const char **origins, int *retval) -{ - char **installed, **allorigins = NULL; - char ***matches = NULL; - int i, j; - - if (retval != NULL) - *retval = 0; - - installed = matchinstalled(MATCH_ALL, NULL, retval); - if (installed == NULL) - return NULL; - - /* Gather origins for all installed packages */ - for (i = 0; installed[i] != NULL; i++) { - FILE *fp; - char *buf, *cp, tmp[PATH_MAX]; - int cmd; - - allorigins = realloc(allorigins, (i + 1) * sizeof(*allorigins)); - allorigins[i] = NULL; - - 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; - strncat(tmp, "/" CONTENTS_FNAME, PATH_MAX); - 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) { - asprintf(&buf, "%s", cp); - allorigins[i] = buf; - break; - } - } - if (cmd != PLIST_ORIGIN && 0 != strncmp("bsdpan-", installed[i], 7)) - warnx("package %s has no origin recorded", installed[i]); - fclose(fp); - } - - /* Resolve origins into package names, retaining the sequence */ - for (i = 0; origins[i] != NULL; i++) { - matches = realloc(matches, (i + 1) * sizeof(*matches)); - struct store *store = NULL; - store = storecreate(store); - - for (j = 0; installed[j] != NULL; j++) { - if (allorigins[j]) { - if (csh_match(origins[i], allorigins[j], FNM_PATHNAME) == 0) { - storeappend(store, installed[j]); - } - } - } - if (store->used == 0) - matches[i] = NULL; - else - matches[i] = store->store; - } - - if (allorigins) { - for (i = 0; installed[i] != NULL; i++) - if (allorigins[i]) - free(allorigins[i]); - free(allorigins); - } - - return matches; -} - -/* - * Synopsis is similar to matchinstalled(), but use origin - * as a key for matching packages. - */ -char ** -matchbyorigin(const char *origin, int *retval) -{ - const char *origins[2]; - char ***tmp; - - origins[0] = origin; - origins[1] = NULL; - - tmp = matchallbyorigin(origins, retval); - if (tmp && tmp[0]) { - return tmp[0]; - } else { - return NULL; - } -} - -/* - * Small linked list to memoize results of isinstalledpkg(). A hash table - * would be faster but for n ~= 1000 may be overkill. - */ -struct iip_memo { - LIST_ENTRY(iip_memo) iip_link; - char *iip_name; - int iip_result; -}; -LIST_HEAD(, iip_memo) iip_memo = LIST_HEAD_INITIALIZER(iip_memo); - -/* - * - * Return 1 if the specified package is installed, - * 0 if not, and -1 if an error occured. - */ -int -isinstalledpkg(const char *name) -{ - int result; - char *buf, *buf2; - struct iip_memo *memo; - - LIST_FOREACH(memo, &iip_memo, iip_link) { - if (strcmp(memo->iip_name, name) == 0) - return memo->iip_result; - } - - buf2 = NULL; - asprintf(&buf, "%s/%s", LOG_DIR, name); - if (buf == NULL) - goto errout; - if (!isdir(buf) || access(buf, R_OK) == FAIL) { - result = 0; - } else { - asprintf(&buf2, "%s/%s", buf, CONTENTS_FNAME); - if (buf2 == NULL) - goto errout; - - if (!isfile(buf2) || access(buf2, R_OK) == FAIL) - result = -1; - else - result = 1; - } - - free(buf); - buf = strdup(name); - if (buf == NULL) - goto errout; - free(buf2); - buf2 = NULL; - - memo = malloc(sizeof *memo); - if (memo == NULL) - goto errout; - memo->iip_name = buf; - memo->iip_result = result; - LIST_INSERT_HEAD(&iip_memo, memo, iip_link); - return result; - -errout: - if (buf != NULL) - free(buf); - if (buf2 != NULL) - free(buf2); - 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); -} diff --git a/lib/libpkg/msg.c b/lib/libpkg/msg.c deleted file mode 100644 index 0d25ad199007..000000000000 --- a/lib/libpkg/msg.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 message routines. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" -#include -#include - -/* Die a relatively simple death */ -void -upchuck(const char *message) -{ - cleanup(0); - errx(1, "fatal error during execution: %s", message); -} - -/* - * As a yes/no question, prompting from the varargs string and using - * default if user just hits return. - */ -Boolean -y_or_n(Boolean def, const char *msg, ...) -{ - va_list args; - int ch = 0; - FILE *tty; - - va_start(args, msg); - /* - * Need to open /dev/tty because file collection may have been - * collected on stdin - */ - tty = fopen(_PATH_TTY, "r"); - if (!tty) { - cleanup(0); - errx(2, "can't open %s!", _PATH_TTY); - } - while (ch != 'Y' && ch != 'N') { - vfprintf(stderr, msg, args); - if (def) - fprintf(stderr, " [yes]? "); - else - fprintf(stderr, " [no]? "); - fflush(stderr); - ch = toupper(fgetc(tty)); - if (ch == '\n') - ch = (def) ? 'Y' : 'N'; - } - fclose(tty) ; - return (ch == 'Y') ? TRUE : FALSE; -} diff --git a/lib/libpkg/pen.c b/lib/libpkg/pen.c deleted file mode 100644 index 6e30445b7594..000000000000 --- a/lib/libpkg/pen.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 "pkg.h" -#include -#include -#include -#include -#include -#include - -/* For keeping track of where we are */ -static char PenLocation[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; - char humbuf[6]; - - 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); - humanize_number(humbuf, sizeof humbuf, sz, "", HN_AUTOSCALE, - HN_NOSPACE); - 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 %s bytes\n" -"free", __func__, humbuf); - return NULL; - } - return pen; -} - -#define MAX_STACK 20 -static char *pstack[MAX_STACK]; -static int pdepth = -1; - -static const char * -pushPen(const char *pen) -{ - if (++pdepth == MAX_STACK) - errx(2, "%s: stack overflow.\n", __func__); - pstack[pdepth] = strdup(pen); - - return pstack[pdepth]; -} - -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. - */ -const char * -make_playpen(char *pen, off_t sz) -{ - char humbuf[6]; - char cwd[FILENAME_MAX]; - - if (!find_play_pen(pen, sz)) - return NULL; - - if (!mkdtemp(pen)) { - cleanup(0); - errx(2, "%s: can't mktemp '%s'", __func__, pen); - } - - humanize_number(humbuf, sizeof humbuf, sz, "", HN_AUTOSCALE, HN_NOSPACE); - - 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 at least %s and try the command again", - __func__, humbuf, pen); - } - - if (!getcwd(cwd, FILENAME_MAX)) { - upchuck("getcwd"); - return NULL; - } - - if (chdir(pen) == FAIL) { - cleanup(0); - errx(2, "%s: can't chdir to '%s'", __func__, pen); - } - - strcpy(PenLocation, pen); - return pushPen(cwd); -} - -/* Convenience routine for getting out of playpen */ -int -leave_playpen() -{ - static char left[FILENAME_MAX]; - void (*oldsig)(int); - - if (!PenLocation[0]) - return 0; - - /* Don't interrupt while we're cleaning up */ - oldsig = signal(SIGINT, SIG_IGN); - strcpy(left, PenLocation); - popPen(PenLocation); - - if (chdir(PenLocation) == FAIL) { - cleanup(0); - errx(2, "%s: can't chdir back to '%s'", __func__, PenLocation); - } - - if (left[0] == '/' && vsystem("/bin/rm -rf %s", left)) - warnx("couldn't remove temporary dir '%s'", left); - signal(SIGINT, oldsig); - - return 1; -} - -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; -} diff --git a/lib/libpkg/pkg.h b/lib/libpkg/pkg.h deleted file mode 100644 index 12e35623bc8a..000000000000 --- a/lib/libpkg/pkg.h +++ /dev/null @@ -1,246 +0,0 @@ -/* $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_ - -#ifndef YES_I_KNOW_THE_API_IS_RUBBISH_AND_IS_DOOMED_TO_CHANGE -#error "You obviously have no idea what you're doing." -#endif - -/* Includes */ -#include -#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 - -/* Some more stat macros. */ -#define S_IRALL 0000444 -#define S_IWALL 0000222 -#define S_IXALL 0000111 - -/* Usually "rm", but often "echo" during debugging! */ -#define REMOVE_CMD "/bin/rm" - -/* Usually "rm", but often "echo" during debugging! */ -#define RMDIR_CMD "/bin/rmdir" - -/* Where the ports lives by default */ -#define DEF_PORTS_DIR "/usr/ports" -/* just in case we change the environment variable name */ -#define PORTSDIR "PORTSDIR" -/* macro to get name of directory where the ports lives */ -#define PORTS_DIR (getenv(PORTSDIR) ? getenv(PORTSDIR) : DEF_PORTS_DIR) - -/* 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" - -#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 library - increase whenever you make a change - * in the code that is not cosmetic only. - */ -#define LIBPKG_VERSION 20100423 - -#define PKG_WRAPCONF_FNAME "/var/db/pkg_install.conf" - -/* 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, - PLIST_NOINST -}; -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); -const char *make_playpen(char *, off_t); -char *where_playpen(void); -int 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 *); -const char *fileGetURL(const char *, const char *, int); -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 **); -void pkg_wrap(long, char **); - -/* Query installed packages */ -char **matchinstalled(match_t, char **, int *); -char **matchbyorigin(const char *, int *); -char ***matchallbyorigin(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 libpkg_version(void); -int verscmp(Package *, int, int); -int version_cmp(const char *, const char *); - -/* Externs */ -extern Boolean Quiet; -extern Boolean Fake; -extern Boolean Force; -extern int AutoAnswer; -extern int Verbose; - -#endif /* _INST_LIB_LIB_H_ */ diff --git a/lib/libpkg/pkgwrap.c b/lib/libpkg/pkgwrap.c deleted file mode 100644 index 9c8c0c3d0a26..000000000000 --- a/lib/libpkg/pkgwrap.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * FreeBSD install - a package for the installation and maintenance - * 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 - * 8 September 2002 - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" -#include -#include -#include -#include - -extern char **environ; - -void -pkg_wrap(long curver, char **argv) -{ - FILE* f; - char ver[9]; /* Format is: 'YYYYMMDD\0' */ - char buffer[FILENAME_MAX+10]; /* Format is: 'YYYYMMDD ' */ - char cmd[FILENAME_MAX+5]; /* Format is: ' -PPq' */ - char *path, *cp; - long ptver, lpver; - - if (getenv("PKG_NOWRAP") != NULL) - goto nowrap; - - setenv("PKG_NOWRAP", "1", 1); - - /* Get alternative location for package tools. */ - if ((f = fopen(PKG_WRAPCONF_FNAME, "r")) == NULL) { - goto nowrap; - } else { - if (get_string(buffer, FILENAME_MAX+9, f) == NULL) { - goto nowrap; - } else { - if ((path = strrchr(buffer, ' ')) == NULL) { - goto nowrap; - } else { - *path++ = '\0'; - } - } - } - - if ((cp = strrchr(argv[0], '/')) == NULL) { - cp = argv[0]; - } else { - cp++; - } - - /* Get version of the other pkg_install and libpkg */ - snprintf(cmd, FILENAME_MAX+10, "%s/%s -PPq", path, cp); - if ((f = popen(cmd, "r")) == NULL) { - perror("popen()"); - goto nowrap; - } else { - if (get_string(ver, 9, f) == NULL) - goto nowrap; - else - ptver = strtol(ver, NULL, 10); - if (get_string(ver, 9, f) == NULL) - goto nowrap; - else - lpver = strtol(ver, NULL, 10); - pclose(f); - } - - if ((lpver >= LIBPKG_VERSION) && (ptver > curver)) { - snprintf(cmd, FILENAME_MAX, "%s/%s", path, cp); - execve(cmd, argv, environ); - } - -nowrap: - unsetenv("PKG_NOWRAP"); -} diff --git a/lib/libpkg/plist.c b/lib/libpkg/plist.c deleted file mode 100644 index b14ac20aafc0..000000000000 --- a/lib/libpkg/plist.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * 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 - * - * General packing list routines. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" -#include -#include - -/* Add an item to a packing list */ -void -add_plist(Package *p, plist_t type, const char *arg) -{ - PackingList tmp; - - tmp = new_plist_entry(); - tmp->name = copy_string(arg); - tmp->type = type; - - if (!p->head) - p->head = p->tail = tmp; - else { - tmp->prev = p->tail; - p->tail->next = tmp; - p->tail = tmp; - } - switch (type) { - case PLIST_NAME: - p->name = tmp->name; - break; - - case PLIST_ORIGIN: - p->origin = tmp->name; - break; - - default: - break; - } -} - -void -add_plist_top(Package *p, plist_t type, const char *arg) -{ - PackingList tmp; - - tmp = new_plist_entry(); - tmp->name = copy_string(arg); - tmp->type = type; - - if (!p->head) - p->head = p->tail = tmp; - else { - tmp->next = p->head; - p->head->prev = tmp; - p->head = tmp; - } -} - -/* Return the last (most recent) entry in a packing list */ -PackingList -last_plist(Package *p) -{ - return p->tail; -} - -/* Mark all items in a packing list to prevent iteration over them */ -void -mark_plist(Package *pkg) -{ - PackingList p = pkg->head; - - while (p) { - p->marked = TRUE; - p = p->next; - } -} - -/* Find a given item in a packing list and, if so, return it (else NULL) */ -PackingList -find_plist(Package *pkg, plist_t type) -{ - PackingList p = pkg->head; - - while (p) { - if (p->type == type) - return p; - p = p->next; - } - return NULL; -} - -/* Look for a specific boolean option argument in the list */ -char * -find_plist_option(Package *pkg, const char *name) -{ - PackingList p = pkg->head; - - while (p) { - if (p->type == PLIST_OPTION && !strcmp(p->name, name)) - return p->name; - p = p->next; - } - return NULL; -} - -/* - * Delete plist item 'type' in the list (if 'name' is non-null, match it - * too.) If 'all' is set, delete all items, not just the first occurance. - */ -void -delete_plist(Package *pkg, Boolean all, plist_t type, const char *name) -{ - PackingList p = pkg->head; - - while (p) { - PackingList pnext = p->next; - - if (p->type == type && (!name || !strcmp(name, p->name))) { - free(p->name); - if (p->prev) - p->prev->next = pnext; - else - pkg->head = pnext; - if (pnext) - pnext->prev = p->prev; - else - pkg->tail = p->prev; - free(p); - if (!all) - return; - p = pnext; - } - else - p = p->next; - } -} - -/* Allocate a new packing list entry */ -PackingList -new_plist_entry(void) -{ - PackingList ret; - - ret = (PackingList)malloc(sizeof(struct _plist)); - bzero(ret, sizeof(struct _plist)); - return ret; -} - -/* Free an entire packing list */ -void -free_plist(Package *pkg) -{ - PackingList p = pkg->head; - - while (p) { - PackingList p1 = p->next; - - free(p->name); - free(p); - p = p1; - } - pkg->head = pkg->tail = NULL; -} - -/* - * For an ascii string denoting a plist command, return its code and - * optionally its argument(s) - */ -int -plist_cmd(const char *s, char **arg) -{ - char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */ - char *cp; - const char *sp; - - strcpy(cmd, s); - str_lowercase(cmd); - cp = cmd; - sp = s; - while (*cp) { - if (isspace(*cp)) { - *cp = '\0'; - while (isspace(*sp)) /* Never sure if macro, increment later */ - ++sp; - break; - } - ++cp, ++sp; - } - if (arg) - *arg = (char *)sp; - if (!strcmp(cmd, "cwd")) - return PLIST_CWD; - else if (!strcmp(cmd, "srcdir")) - return PLIST_SRC; - else if (!strcmp(cmd, "cd")) - return PLIST_CWD; - else if (!strcmp(cmd, "exec")) - return PLIST_CMD; - else if (!strcmp(cmd, "unexec")) - return PLIST_UNEXEC; - else if (!strcmp(cmd, "mode")) - return PLIST_CHMOD; - else if (!strcmp(cmd, "owner")) - return PLIST_CHOWN; - else if (!strcmp(cmd, "group")) - return PLIST_CHGRP; - else if (!strcmp(cmd, "noinst")) - return PLIST_NOINST; - else if (!strcmp(cmd, "comment")) { - if (!strncmp(*arg, "ORIGIN:", 7)) { - *arg += 7; - return PLIST_ORIGIN; - } else if (!strncmp(*arg, "DEPORIGIN:", 10)) { - *arg += 10; - return PLIST_DEPORIGIN; - } - return PLIST_COMMENT; - } else if (!strcmp(cmd, "ignore")) - return PLIST_IGNORE; - else if (!strcmp(cmd, "ignore_inst")) - return PLIST_IGNORE_INST; - else if (!strcmp(cmd, "name")) - return PLIST_NAME; - else if (!strcmp(cmd, "display")) - return PLIST_DISPLAY; - else if (!strcmp(cmd, "pkgdep")) - return PLIST_PKGDEP; - else if (!strcmp(cmd, "conflicts")) - return PLIST_CONFLICTS; - else if (!strcmp(cmd, "mtree")) - return PLIST_MTREE; - else if (!strcmp(cmd, "dirrm")) - return PLIST_DIR_RM; - else if (!strcmp(cmd, "option")) - return PLIST_OPTION; - else - return FAIL; -} - -/* Read a packing list from a file */ -void -read_plist(Package *pkg, FILE *fp) -{ - char *cp, pline[FILENAME_MAX]; - int cmd, major, minor; - - pkg->fmtver_maj = 1; - pkg->fmtver_mnr = 0; - pkg->origin = NULL; - while (fgets(pline, FILENAME_MAX, fp)) { - int len = strlen(pline); - - while (len && isspace(pline[len - 1])) - pline[--len] = '\0'; - if (!len) - continue; - cp = pline; - if (pline[0] != CMD_CHAR) { - cmd = PLIST_FILE; - goto bottom; - } - cmd = plist_cmd(pline + 1, &cp); - if (cmd == FAIL) { - warnx("%s: unknown command '%s' (package tools out of date?)", - __func__, pline); - goto bottom; - } - if (*cp == '\0') { - cp = NULL; - if (cmd == PLIST_PKGDEP) { - warnx("corrupted record (pkgdep line without argument), ignoring"); - cmd = FAIL; - } - goto bottom; - } - if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n", - &major, &minor) == 2) { - pkg->fmtver_maj = major; - pkg->fmtver_mnr = minor; - if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0) - goto bottom; - - warnx("plist format revision (%d.%d) is higher than supported" - "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr, - PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR); - if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) { - cleanup(0); - exit(2); - } - } -bottom: - add_plist(pkg, cmd, cp); - } -} - -/* Write a packing list to a file, converting commands to ascii equivs */ -void -write_plist(Package *pkg, FILE *fp) -{ - PackingList plist = pkg->head; - - while (plist) { - switch(plist->type) { - case PLIST_FILE: - fprintf(fp, "%s\n", plist->name); - break; - - case PLIST_CWD: - fprintf(fp, "%ccwd %s\n", CMD_CHAR, (plist->name == NULL) ? "" : plist->name); - break; - - case PLIST_SRC: - fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_CMD: - fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_UNEXEC: - fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_CHMOD: - fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : ""); - break; - - case PLIST_CHOWN: - fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : ""); - break; - - case PLIST_CHGRP: - fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : ""); - break; - - case PLIST_COMMENT: - fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_NOINST: - fprintf(fp, "%cnoinst %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_IGNORE: - case PLIST_IGNORE_INST: /* a one-time non-ignored file */ - fprintf(fp, "%cignore\n", CMD_CHAR); - break; - - case PLIST_NAME: - fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_DISPLAY: - fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_PKGDEP: - fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_CONFLICTS: - fprintf(fp, "%cconflicts %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_MTREE: - fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_DIR_RM: - fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_OPTION: - fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name); - break; - - case PLIST_ORIGIN: - fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name); - break; - - case PLIST_DEPORIGIN: - fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name); - break; - - default: - cleanup(0); - errx(2, "%s: unknown command type %d (%s)", __func__, - plist->type, plist->name); - break; - } - plist = plist->next; - } -} - -/* - * Delete the results of a package installation. - * - * This is here rather than in the pkg_delete code because pkg_add needs to - * run it too in cases of failure. - */ -int -delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg) -{ - PackingList p; - const char *Where = ".", *last_file = ""; - Boolean fail = SUCCESS; - Boolean preserve; - char tmp[FILENAME_MAX], *name = NULL; - char *prefix = NULL; - - preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; - for (p = pkg->head; p; p = p->next) { - switch (p->type) { - case PLIST_NAME: - name = p->name; - break; - - case PLIST_IGNORE: - p = p->next; - break; - - case PLIST_CWD: - if (!prefix) - prefix = p->name; - Where = (p->name == NULL) ? prefix : p->name; - if (Verbose) - printf("Change working directory to %s\n", Where); - break; - - case PLIST_UNEXEC: - format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file); - if (Verbose) - printf("Execute '%s'\n", tmp); - if (!Fake && system(tmp)) { - warnx("unexec command for '%s' failed", tmp); - fail = FAIL; - } - break; - - case PLIST_FILE: - last_file = p->name; - sprintf(tmp, "%s/%s", Where, p->name); - if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) { - warnx("cannot delete specified file '%s' - it is a directory!\n" - "this packing list is incorrect - ignoring delete request", tmp); - } - else { - if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) { - char *cp = NULL, buf[33]; - - /* - * For packing lists whose version is 1.1 or greater, the md5 - * hash for a symlink is calculated on the string returned - * by readlink(). - */ - if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) { - int len; - char linkbuf[FILENAME_MAX]; - - if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0) - cp = MD5Data((unsigned char *)linkbuf, len, buf); - } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0) - cp = MD5File(tmp, buf); - - if (cp != NULL) { - /* Mismatch? */ - if (strcmp(cp, p->next->name + 4)) { - warnx("'%s' fails original MD5 checksum - %s", - tmp, Force ? "deleted anyway." : "not deleted."); - if (!Force) { - fail = FAIL; - continue; - } - } - } - } - if (Verbose) - printf("Delete file %s\n", tmp); - if (!Fake) { - if (delete_hierarchy(tmp, ign_err, nukedirs)) - fail = FAIL; - if (preserve && name) { - char tmp2[FILENAME_MAX]; - - if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) { - if (fexists(tmp2)) { - if (rename(tmp2, tmp)) - warn("preserve: unable to restore %s as %s", - tmp2, tmp); - } - } - } - } - } - break; - - case PLIST_DIR_RM: - sprintf(tmp, "%s/%s", Where, p->name); - if (!isdir(tmp) && fexists(tmp)) { - warnx("cannot delete specified directory '%s' - it is a file!\n" - "this packing list is incorrect - ignoring delete request", tmp); - } - else { - if (Verbose) - printf("Delete directory %s\n", tmp); - if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) { - warnx("unable to completely remove directory '%s'", tmp); - fail = FAIL; - } - } - last_file = p->name; - break; - - default: - break; - } - } - return fail; -} - -#ifdef DEBUG -#define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir) -#define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir) -#else -#define RMDIR rmdir -#define REMOVE(file,ie) (remove(file) && !(ie)) -#endif - -/* Selectively delete a hierarchy */ -int -delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs) -{ - char *cp1, *cp2; - - cp1 = cp2 = strdup(dir); - if (!fexists(dir) && !issymlink(dir)) { - if (!ign_err) - warnx("%s '%s' doesn't exist", - isdir(dir) ? "directory" : "file", dir); - return !ign_err; - } - else if (nukedirs) { - if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir)) - return 1; - } - else if (isdir(dir) && !issymlink(dir)) { - if (RMDIR(dir) && !ign_err) - return 1; - } - else { - if (REMOVE(dir, ign_err)) - return 1; - } - - if (!nukedirs) - return 0; - while (cp2) { - if ((cp2 = strrchr(cp1, '/')) != NULL) - *cp2 = '\0'; - if (!isemptydir(dir)) - return 0; - if (RMDIR(dir) && !ign_err) { - if (!fexists(dir)) - warnx("directory '%s' doesn't exist", dir); - else - return 1; - } - /* back up the pathname one component */ - if (cp2) { - cp1 = strdup(dir); - } - } - return 0; -} diff --git a/lib/libpkg/str.c b/lib/libpkg/str.c deleted file mode 100644 index c26e6cce6605..000000000000 --- a/lib/libpkg/str.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 string utilities. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" - -char * -strconcat(const char *s1, const char *s2) -{ - static char tmp[FILENAME_MAX]; - - tmp[0] = '\0'; - strncpy(tmp, s1 ? s1 : s2, FILENAME_MAX); /* XXX: what if both are NULL? */ - if (s1 && s2) - strncat(tmp, s2, FILENAME_MAX - strlen(tmp)); - return tmp; -} - -/* Get a string parameter as a file spec or as a "contents follow -" spec */ -char * -get_dash_string(char **str) -{ - char *s = *str; - - if (*s == '-') - *str = copy_string_adds_newline(s + 1); - else - *str = fileGetContents(s); - return *str; -} - -/* Rather Obvious */ -char * -copy_string(const char *str) -{ - return (str ? strdup(str) : NULL); -} - -/* Rather Obvious but adds a trailing \n newline */ -char * -copy_string_adds_newline(const char *str) -{ - if (str == NULL) { - return (NULL); - } else { - char *copy; - size_t line_length; - - line_length = strlen(str) + 2; - if ((copy = malloc(line_length)) == NULL) - return (NULL); - memcpy(copy, str, line_length - 2); - copy[line_length - 2] = '\n'; /* Adds trailing \n */ - copy[line_length - 1] = '\0'; - - return (copy); - } -} - -/* Return TRUE if 'str' ends in suffix 'suff' */ -Boolean -suffix(const char *str, const char *suff) -{ - char *idx; - Boolean ret = FALSE; - - idx = strrchr(str, '.'); - if (idx && !strcmp(idx + 1, suff)) - ret = TRUE; - return ret; -} - -/* Assuming str has a suffix, brutally murder it! */ -void -nuke_suffix(char *str) -{ - char *idx; - - idx = strrchr(str, '.'); - if (idx) - *idx = '\0'; /* Yow! Don't try this on a const! */ -} - -/* Lowercase a whole string */ -void -str_lowercase(char *str) -{ - while (*str) { - *str = tolower(*str); - ++str; - } -} - -char * -get_string(char *str, int max, FILE *fp) -{ - int len; - - if (!str) - return NULL; - str[0] = '\0'; - while (fgets(str, max, fp)) { - len = strlen(str); - while (len && isspace(str[len - 1])) - str[--len] = '\0'; - if (len) - return str; - } - return NULL; -} diff --git a/lib/libpkg/url.c b/lib/libpkg/url.c deleted file mode 100644 index 4c1084994283..000000000000 --- a/lib/libpkg/url.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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 "pkg.h" -#include -#include -#include -#include -#include - -/* - * Try and fetch a file by URL, returning the directory name for where - * it's unpacked, if successful. - */ -const char * -fileGetURL(const char *base, const char *spec, int keep_package) -{ - const char *rp; - char *cp, *tmp; - char fname[FILENAME_MAX]; - char pen[FILENAME_MAX]; - char pkg[FILENAME_MAX]; - char buf[8192]; - FILE *ftp; - pid_t tpid; - int pfd[2], pstat, r, w = 0; - char *hint; - int fd, pkgfd = 0; - - 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); - strcat(cp, ".tbz"); - } - 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); - strcat(fname, ".tbz"); - } - } - else - strcpy(fname, spec); - - if (keep_package) { - tmp = getenv("PKGDIR"); - strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg)); - tmp = basename(fname); - strlcat(pkg, "/", sizeof(pkg)); - strlcat(pkg, tmp, sizeof(pkg)); - if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { - printf("Error: Unable to open %s\n", pkg); - perror("open"); - return NULL; - } - } - - fetchDebug = (Verbose > 0); - if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) { - printf("Error: Unable to get %s: %s\n", - fname, fetchLastErrString); - /* If the fetch fails, yank the package. */ - if (keep_package && unlink(pkg) < 0) { - warnx("failed to remove partially fetched package: %s", pkg); - } - 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); - execl("/usr/bin/tar", "tar", - Verbose ? "-xpjvf" : "-xpjf", - "-", (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 (keep_package) { - if ((w = write(pkgfd, buf, r)) != r) - break; - } - } - if (ferror(ftp)) - warn("warning: error reading from server"); - fclose(ftp); - if (keep_package) { - close(pkgfd); - } - 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; -} diff --git a/lib/libpkg/version.c b/lib/libpkg/version.c deleted file mode 100644 index 123fd5d20e57..000000000000 --- a/lib/libpkg/version.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * FreeBSD install - a package for the installation and maintenance - * 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 - * 31 July 2001 - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "pkg.h" -#include - -/* - * This routine could easily go somewhere else. - * - */ -int -libpkg_version(void) -{ - return LIBPKG_VERSION; -} - -/* - * Routines to assist with PLIST_FMT_VER numbers in the packing - * lists. - * - * Following is the PLIST_FMT_VER history: - * 1.0 - Initial revision; - * 1.1 - When recording/checking checksum of symlink use hash of readlink() - * value instead of the hash of an object this links points to. - * - */ -int -verscmp(Package *pkg, int major, int minor) -{ - int rval = 0; - - if ((pkg->fmtver_maj < major) || (pkg->fmtver_maj == major && - pkg->fmtver_mnr < minor)) - rval = -1; - else if ((pkg->fmtver_maj > major) || (pkg->fmtver_maj == major && - pkg->fmtver_mnr > minor)) - rval = 1; - - return rval; -} - -/* - * split_version(pkgname, endname, epoch, revision) returns a pointer to - * the version portion of a package name and the two special components. - * - * Syntax is: ${PORTNAME}-${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}] - * - * Written by Oliver Eikemeier - * Based on work of Jeremy D. Lea. - */ -static const char * -split_version(const char *pkgname, const char **endname, unsigned long *epoch, unsigned long *revision) -{ - char *ch; - const char *versionstr; - const char *endversionstr; - - if (pkgname == NULL) - errx(2, "%s: Passed NULL pkgname.", __func__); - - /* Look for the last '-' the pkgname */ - ch = strrchr(pkgname, '-'); - /* Cheat if we are just passed a version, not a valid package name */ - versionstr = ch ? ch + 1 : pkgname; - - /* Look for the last '_' in the version string, advancing the end pointer */ - ch = strrchr(versionstr, '_'); - if (revision != NULL) { - *revision = ch ? strtoul(ch + 1, NULL, 10) : 0; - } - endversionstr = ch; - - /* Look for the last ',' in the remaining version string */ - ch = strrchr(endversionstr ? endversionstr + 1 : versionstr, ','); - if (epoch != NULL) { - *epoch = ch ? strtoul(ch + 1, NULL, 10) : 0; - } - if (ch && !endversionstr) - endversionstr = ch; - - /* set the pointer behind the last character of the version without revision or epoch */ - if (endname) - *endname = endversionstr ? endversionstr : strrchr(versionstr, '\0'); - - return versionstr; -} - -/* - * PORTVERSIONs are composed of components separated by dots. A component - * consists of a version number, a letter and a patchlevel number. This does - * not conform to the porter's handbook, but let us formulate rules that - * fit the current practice and are far simpler than to make decisions - * based on the order of netters and lumbers. Besides, people use versions - * like 10b2 in the ports... - */ - -typedef struct { -#ifdef __LONG_LONG_SUPPORTED - long long n; - long long pl; -#else - long n; - long pl; -#endif - int a; -} version_component; - -/* - * get_component(position, component) gets the value of the next component - * (number - letter - number triple) and returns a pointer to the next character - * after any leading separators - * - * - components are separated by dots - * - characters !~ [a-zA-Z0-9.+*] are treated as separators - * (1.0:2003.09.16 = 1.0.2003.09.16), this may not be what you expect: - * 1.0.1:2003.09.16 < 1.0:2003.09.16 - * - consecutive separators are collapsed (10..1 = 10.1) - * - missing separators are inserted, essentially - * letter number letter => letter number . letter (10a1b2 = 10a1.b2) - * - missing components are assumed to be equal to 0 (10 = 10.0 = 10.0.0) - * - the letter sort order is: [none], a, b, ..., z; numbers without letters - * sort first (10 < 10a < 10b) - * - missing version numbers (in components starting with a letter) sort as -1 - * (a < 0, 10.a < 10) - * - a separator is inserted before the special strings "pl", "alpha", "beta", - * "pre" and "rc". - * - "pl" sorts before every other letter, "alpha", "beta", "pre" and "rc" - * sort as a, b, p and r. (10alpha = 10.a < 10, but 10 < 10a; pl11 < alpha3 - * < 0.1beta2 = 0.1.b2 < 0.1) - * - other strings use only the first letter for sorting, case is ignored - * (1.d2 = 1.dev2 = 1.Development2) - * - The special component `*' is guaranteed to be the smallest possible - * component (2.* < 2pl1 < 2alpha3 < 2.9f7 < 3.*) - * - components separated by `+' are handled by version_cmp below - * - * Oliver Eikemeier - */ - -static const struct { - const char *name; - size_t namelen; - int value; -} stage[] = { - { "pl", 2, 0 }, - { "alpha", 5, 'a'-'a'+1 }, - { "beta", 4, 'b'-'a'+1 }, - { "pre", 3, 'p'-'a'+1 }, - { "rc", 2, 'r'-'a'+1 }, - { NULL, 0, -1 } -}; - -static const char * -get_component(const char *position, version_component *component) -{ - const char *pos = position; - int hasstage = 0, haspatchlevel = 0; - - if (!pos) - errx(2, "%s: Passed NULL position.", __func__); - - /* handle version number */ - if (isdigit(*pos)) { - char *endptr; -#ifdef __LONG_LONG_SUPPORTED - component->n = strtoll(pos, &endptr, 10); -#else - component->n = strtol(pos, &endptr, 10); -#endif - /* should we test for errno == ERANGE? */ - pos = endptr; - } else if (*pos == '*') { - component->n = -2; - do { - pos++; - } while(*pos && *pos != '+'); - } else { - component->n = -1; - hasstage = 1; - } - - /* handle letter */ - if (isalpha(*pos)) { - int c = tolower(*pos); - haspatchlevel = 1; - /* handle special suffixes */ - if (isalpha(pos[1])) { - int i; - for (i = 0; stage[i].name; i++) { - if (strncasecmp(pos, stage[i].name, stage[i].namelen) == 0 - && !isalpha(pos[stage[i].namelen])) { - if (hasstage) { - /* stage to value */ - component->a = stage[i].value; - pos += stage[i].namelen; - } else { - /* insert dot */ - component->a = 0; - haspatchlevel = 0; - } - c = 0; - break; - } - } - } - /* unhandled above */ - if (c) { - /* use the first letter and skip following */ - component->a = c - 'a' + 1; - do { - ++pos; - } while (isalpha(*pos)); - } - } else { - component->a = 0; - haspatchlevel = 0; - } - - if (haspatchlevel) { - /* handle patch number */ - if (isdigit(*pos)) { - char *endptr; -#ifdef __LONG_LONG_SUPPORTED - component->pl = strtoll(pos, &endptr, 10); -#else - component->pl = strtol(pos, &endptr, 10); -#endif - /* should we test for errno == ERANGE? */ - pos = endptr; - } else { - component->pl = -1; - } - } else { - component->pl = 0; - } - - /* skip trailing separators */ - while (*pos && !isdigit(*pos) && !isalpha(*pos) && *pos != '+' && *pos != '*') { - pos++; - } - - return pos; -} - -/* - * version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version - * components of pkg1 is less than, equal to or greater than pkg2. No - * comparison of the basenames is done. - * - * The port version is defined by: - * ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}] - * ${PORTEPOCH} supersedes ${PORTVERSION} supersedes ${PORTREVISION}. - * See the commit log for revision 1.349 of ports/Mk/bsd.port.mk - * for more information. - * - * The epoch and revision are defined to be a single number, while the rest - * of the version should conform to the porting guidelines. It can contain - * multiple components, separated by a period, including letters. - * - * The tests allow for significantly more latitude in the version numbers - * than is allowed in the guidelines. No point in enforcing them here. - * That's what portlint is for. - * - * Jeremy D. Lea. - * reimplemented by Oliver Eikemeier - */ -int -version_cmp(const char *pkg1, const char *pkg2) -{ - const char *v1, *v2, *ve1, *ve2; - unsigned long e1, e2, r1, r2; - int result = 0; - - v1 = split_version(pkg1, &ve1, &e1, &r1); - v2 = split_version(pkg2, &ve2, &e2, &r2); - - /* Check epoch, port version, and port revision, in that order. */ - if (e1 != e2) { - result = (e1 < e2 ? -1 : 1); - } - - /* Shortcut check for equality before invoking the parsing routines. */ - if (result == 0 && (ve1 - v1 != ve2 - v2 || strncasecmp(v1, v2, ve1 - v1) != 0)) { - /* Loop over different components (the parts separated by dots). - * If any component differs, we have the basis for an inequality. */ - while(result == 0 && (v1 < ve1 || v2 < ve2)) { - int block_v1 = 0; - int block_v2 = 0; - version_component vc1 = {0, 0, 0}; - version_component vc2 = {0, 0, 0}; - if (v1 < ve1 && *v1 != '+') { - v1 = get_component(v1, &vc1); - } else { - block_v1 = 1; - } - if (v2 < ve2 && *v2 != '+') { - v2 = get_component(v2, &vc2); - } else { - block_v2 = 1; - } - if (block_v1 && block_v2) { - if (v1 < ve1) - v1++; - if (v2 < ve2) - v2++; - } else if (vc1.n != vc2.n) { - result = (vc1.n < vc2.n ? -1 : 1); - } else if (vc1.a != vc2.a) { - result = (vc1.a < vc2.a ? -1 : 1); - } else if (vc1.pl != vc2.pl) { - result = (vc1.pl < vc2.pl ? -1 : 1); - } - } - } - - /* Compare FreeBSD revision numbers. */ - if (result == 0 && r1 != r2) { - result = (r1 < r2 ? -1 : 1); - } - return result; -} diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index 9a948ff4bbef..d3fb51a9a73f 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -129,7 +129,6 @@ MINUSLPAM+= -lypclnt LIBPANEL?= ${DESTDIR}${LIBDIR}/libpanel.a LIBPCAP?= ${DESTDIR}${LIBDIR}/libpcap.a -LIBPKG?= ${DESTDIR}${LIBDIR}/libpkg.a LIBPMC?= ${DESTDIR}${LIBDIR}/libpmc.a LIBPROC?= ${DESTDIR}${LIBDIR}/libproc.a LIBPTHREAD?= ${DESTDIR}${LIBDIR}/libpthread.a diff --git a/usr.sbin/pkg_install/Makefile b/usr.sbin/pkg_install/Makefile index 0aa19415441b..bf1a2135cc79 100644 --- a/usr.sbin/pkg_install/Makefile +++ b/usr.sbin/pkg_install/Makefile @@ -2,11 +2,11 @@ .include -SUBDIR= add create delete info updating version +SUBDIR= lib add create delete info updating version .include -DATE!= grep PKG_INSTALL_VERSION ${.CURDIR}/Makefile.inc | sed 's|.*=||' +DATE!= grep PKG_INSTALL_VERSION ${.CURDIR}/lib/lib.h | sed 's|.*[ ]||' distfile: clean @(cd ${.CURDIR}/..; \ diff --git a/usr.sbin/pkg_install/Makefile.inc b/usr.sbin/pkg_install/Makefile.inc index d929f2457009..2fa20aa1c394 100644 --- a/usr.sbin/pkg_install/Makefile.inc +++ b/usr.sbin/pkg_install/Makefile.inc @@ -2,11 +2,16 @@ .include -CFLAGS+= -DPKG_INSTALL_VERSION=20101012 -CFLAGS+= -DYES_I_KNOW_THE_API_IS_RUBBISH_AND_IS_DOOMED_TO_CHANGE +LIBINSTALL= ${.OBJDIR}/../lib/libinstall.a -DPADD+= ${LIBPKG} -LDADD+= -lpkg +DPADD+= ${LIBUTIL} +LDADD+= -lutil + +.if ${MK_OPENSSL} != "no" && \ + defined(LDADD) && ${LDADD:M-lfetch} != "" +DPADD+= ${LIBSSL} ${LIBCRYPTO} +LDADD+= -lssl -lcrypto +.endif # Inherit BINDIR from one level up. .include "../Makefile.inc" diff --git a/usr.sbin/pkg_install/add/Makefile b/usr.sbin/pkg_install/add/Makefile index 03a43f068b76..89988e78b220 100644 --- a/usr.sbin/pkg_install/add/Makefile +++ b/usr.sbin/pkg_install/add/Makefile @@ -1,11 +1,14 @@ # $FreeBSD$ -.include - PROG= pkg_add SRCS= main.c perform.c futil.c extract.c +CFLAGS+= -I${.CURDIR}/../lib + WARNS?= 3 WFORMAT?= 1 +DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} +LDADD= ${LIBINSTALL} -lfetch -lmd + .include diff --git a/usr.sbin/pkg_install/add/extract.c b/usr.sbin/pkg_install/add/extract.c index 6c2c4fc7b92b..732a13fea441 100644 --- a/usr.sbin/pkg_install/add/extract.c +++ b/usr.sbin/pkg_install/add/extract.c @@ -23,7 +23,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "add.h" diff --git a/usr.sbin/pkg_install/add/futil.c b/usr.sbin/pkg_install/add/futil.c index c5253202ca5e..ca095ea7ae2e 100644 --- a/usr.sbin/pkg_install/add/futil.c +++ b/usr.sbin/pkg_install/add/futil.c @@ -22,7 +22,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include "lib.h" #include "add.h" /* diff --git a/usr.sbin/pkg_install/add/main.c b/usr.sbin/pkg_install/add/main.c index b8b9b54bcf63..f73312a626e5 100644 --- a/usr.sbin/pkg_install/add/main.c +++ b/usr.sbin/pkg_install/add/main.c @@ -26,7 +26,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "add.h" char *Prefix = NULL; @@ -132,8 +132,6 @@ main(int argc, char **argv) static char temppackageroot[MAXPATHLEN]; static char pkgaddpath[MAXPATHLEN]; - pkg_wrap(PKG_INSTALL_VERSION, argv); - if (*argv[0] != '/' && strchr(argv[0], '/') != NULL) PkgAddCmd = realpath(argv[0], pkgaddpath); else diff --git a/usr.sbin/pkg_install/add/perform.c b/usr.sbin/pkg_install/add/perform.c index 653a1d6296fe..b23cd5232a32 100644 --- a/usr.sbin/pkg_install/add/perform.c +++ b/usr.sbin/pkg_install/add/perform.c @@ -23,7 +23,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "add.h" #include diff --git a/usr.sbin/pkg_install/create/Makefile b/usr.sbin/pkg_install/create/Makefile index 333403778fe3..42718c6f9273 100644 --- a/usr.sbin/pkg_install/create/Makefile +++ b/usr.sbin/pkg_install/create/Makefile @@ -3,10 +3,12 @@ PROG= pkg_create SRCS= main.c perform.c pl.c +CFLAGS+= -I${.CURDIR}/../lib + WARNS?= 3 WFORMAT?= 1 -DPADD= ${LIBMD} -LDADD= -lmd +DPADD= ${LIBINSTALL} ${LIBMD} +LDADD= ${LIBINSTALL} -lmd .include diff --git a/usr.sbin/pkg_install/create/main.c b/usr.sbin/pkg_install/create/main.c index 5e999dae3350..e4af62128ae0 100644 --- a/usr.sbin/pkg_install/create/main.c +++ b/usr.sbin/pkg_install/create/main.c @@ -15,7 +15,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "create.h" match_t MatchType = MATCH_GLOB; @@ -72,8 +72,6 @@ main(int argc, char **argv) int ch; char **pkgs, **start, *tmp; - pkg_wrap(PKG_INSTALL_VERSION, argv); - pkgs = start = argv; while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) switch(ch) { diff --git a/usr.sbin/pkg_install/create/perform.c b/usr.sbin/pkg_install/create/perform.c index 149bcbd08513..45786b62b87c 100644 --- a/usr.sbin/pkg_install/create/perform.c +++ b/usr.sbin/pkg_install/create/perform.c @@ -21,7 +21,7 @@ #include __FBSDID("$FreeBSD$"); -#include +#include "lib.h" #include "create.h" #include diff --git a/usr.sbin/pkg_install/create/pl.c b/usr.sbin/pkg_install/create/pl.c index fe62d421014e..18bbaf24734b 100644 --- a/usr.sbin/pkg_install/create/pl.c +++ b/usr.sbin/pkg_install/create/pl.c @@ -21,7 +21,7 @@ #include __FBSDID("$FreeBSD$"); -#include +#include "lib.h" #include "create.h" #include #include diff --git a/usr.sbin/pkg_install/delete/Makefile b/usr.sbin/pkg_install/delete/Makefile index 4f3b3906e63c..c9a0fdebea22 100644 --- a/usr.sbin/pkg_install/delete/Makefile +++ b/usr.sbin/pkg_install/delete/Makefile @@ -3,6 +3,11 @@ PROG= pkg_delete SRCS= main.c perform.c +CFLAGS+= -I${.CURDIR}/../lib + WFORMAT?= 1 +DPADD= ${LIBINSTALL} ${LIBMD} +LDADD= ${LIBINSTALL} -lmd + .include diff --git a/usr.sbin/pkg_install/delete/main.c b/usr.sbin/pkg_install/delete/main.c index 7677fe9d44bc..f09a432f2bb4 100644 --- a/usr.sbin/pkg_install/delete/main.c +++ b/usr.sbin/pkg_install/delete/main.c @@ -27,7 +27,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "delete.h" char *Prefix = NULL; @@ -67,8 +67,6 @@ main(int argc, char **argv) const char *tmp; struct stat stat_s; - pkg_wrap(PKG_INSTALL_VERSION, argv); - pkgs = start = argv; while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) switch(ch) { diff --git a/usr.sbin/pkg_install/delete/perform.c b/usr.sbin/pkg_install/delete/perform.c index 02f9717a0919..2557dbcd105d 100644 --- a/usr.sbin/pkg_install/delete/perform.c +++ b/usr.sbin/pkg_install/delete/perform.c @@ -22,7 +22,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include "lib.h" #include "delete.h" static int pkg_do(char *); diff --git a/usr.sbin/pkg_install/info/Makefile b/usr.sbin/pkg_install/info/Makefile index ba3909d17da7..485cb2263210 100644 --- a/usr.sbin/pkg_install/info/Makefile +++ b/usr.sbin/pkg_install/info/Makefile @@ -3,9 +3,11 @@ PROG= pkg_info SRCS= main.c perform.c show.c +CFLAGS+= -I${.CURDIR}/../lib + WFORMAT?= 1 -DPADD= ${LIBMD} -LDADD= -lmd +DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} +LDADD= ${LIBINSTALL} -lfetch -lmd .include diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h index 68ec7107a3c3..46e29b1202dd 100644 --- a/usr.sbin/pkg_install/info/info.h +++ b/usr.sbin/pkg_install/info/info.h @@ -33,26 +33,25 @@ #define MAXNAMESIZE 20 #endif -#define SHOW_COMMENT 0x000001 -#define SHOW_DESC 0x000002 -#define SHOW_PLIST 0x000004 -#define SHOW_INSTALL 0x000008 -#define SHOW_DEINSTALL 0x000010 -#define SHOW_REQUIRE 0x000020 -#define SHOW_PREFIX 0x000040 -#define SHOW_INDEX 0x000080 -#define SHOW_FILES 0x000100 -#define SHOW_DISPLAY 0x000200 -#define SHOW_REQBY 0x000400 -#define SHOW_MTREE 0x000800 -#define SHOW_SIZE 0x001000 -#define SHOW_ORIGIN 0x002000 -#define SHOW_CKSUM 0x004000 -#define SHOW_FMTREV 0x008000 -#define SHOW_PTREV 0x010000 -#define SHOW_DEPEND 0x020000 -#define SHOW_PKGNAME 0x040000 -#define SHOW_LPREV 0x100000 +#define SHOW_COMMENT 0x00001 +#define SHOW_DESC 0x00002 +#define SHOW_PLIST 0x00004 +#define SHOW_INSTALL 0x00008 +#define SHOW_DEINSTALL 0x00010 +#define SHOW_REQUIRE 0x00020 +#define SHOW_PREFIX 0x00040 +#define SHOW_INDEX 0x00080 +#define SHOW_FILES 0x00100 +#define SHOW_DISPLAY 0x00200 +#define SHOW_REQBY 0x00400 +#define SHOW_MTREE 0x00800 +#define SHOW_SIZE 0x01000 +#define SHOW_ORIGIN 0x02000 +#define SHOW_CKSUM 0x04000 +#define SHOW_FMTREV 0x08000 +#define SHOW_PTREV 0x10000 +#define SHOW_DEPEND 0x20000 +#define SHOW_PKGNAME 0x40000 struct which_entry { TAILQ_ENTRY(which_entry) next; diff --git a/usr.sbin/pkg_install/info/main.c b/usr.sbin/pkg_install/info/main.c index ca4e477f9995..2de638e4cad3 100644 --- a/usr.sbin/pkg_install/info/main.c +++ b/usr.sbin/pkg_install/info/main.c @@ -25,7 +25,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "info.h" int Flags = 0; @@ -68,8 +68,6 @@ main(int argc, char **argv) char **pkgs, **start; char *pkgs_split; - pkg_wrap(PKG_INSTALL_VERSION, argv); - whead = malloc(sizeof(struct which_head)); if (whead == NULL) err(2, NULL); @@ -227,10 +225,7 @@ main(int argc, char **argv) } case 'P': - if (Flags & SHOW_PTREV) - Flags |= SHOW_LPREV; - else - Flags = SHOW_PTREV; + Flags = SHOW_PTREV; break; case 'h': @@ -247,11 +242,6 @@ main(int argc, char **argv) if (!Quiet) printf("Package tools revision: "); printf("%d\n", PKG_INSTALL_VERSION); - if (Flags & SHOW_LPREV) { - if (!Quiet) - printf("Libpkg revision: "); - printf("%d\n", libpkg_version()); - } exit(0); } diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c index d2956120822a..09cad78ad3f2 100644 --- a/usr.sbin/pkg_install/info/perform.c +++ b/usr.sbin/pkg_install/info/perform.c @@ -21,7 +21,7 @@ #include __FBSDID("$FreeBSD$"); -#include +#include "lib.h" #include "info.h" #include #include diff --git a/usr.sbin/pkg_install/info/show.c b/usr.sbin/pkg_install/info/show.c index 0d3b4ad73d2e..c65c312a5062 100644 --- a/usr.sbin/pkg_install/info/show.c +++ b/usr.sbin/pkg_install/info/show.c @@ -21,7 +21,7 @@ #include __FBSDID("$FreeBSD$"); -#include +#include "lib.h" #include "info.h" #include #include diff --git a/usr.sbin/pkg_install/lib/Makefile b/usr.sbin/pkg_install/lib/Makefile new file mode 100644 index 000000000000..84a41b8d7f15 --- /dev/null +++ b/usr.sbin/pkg_install/lib/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +LIB= install +INTERNALLIB= +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 + +WARNS?= 3 +WFORMAT?= 1 + +.include diff --git a/usr.sbin/pkg_install/lib/deps.c b/usr.sbin/pkg_install/lib/deps.c new file mode 100644 index 000000000000..66f44a9c6fea --- /dev/null +++ b/usr.sbin/pkg_install/lib/deps.c @@ -0,0 +1,241 @@ +/* + * 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 + * 14 March 2001 + * + * Routines used to do various operations with dependencies + * among installed packages. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include +#include + +void list_deps(const char *pkgname, char **pkgs, char *listed, + char *check_loop, char **newpkgs, int *nrnewpkgs, + int *err_cnt); + +/* + * Sort given NULL-terminated list of installed packages (pkgs) in + * such a way that if package A depends on package B then after + * sorting A will be listed before B no matter how they were + * originally positioned in the list. + * + * Works by performing a recursive depth-first search on the + * required-by lists. + */ + +int +sortdeps(char **pkgs) +{ + int i, err_cnt=0; + int nrpkgs, nrnewpkgs; + char *listed, *check_loop, **newpkgs; + char *cp; + + if (pkgs[0] == NULL || pkgs[1] == NULL) + return (0); + + nrpkgs = 0; + while (pkgs[nrpkgs]) nrpkgs++; + listed = alloca(nrpkgs); + if (listed == NULL) { + warnx("%s(): alloca() failed", __func__); + return 1; + } + bzero(listed,nrpkgs); + check_loop = alloca(nrpkgs); + if (check_loop == NULL) { + warnx("%s(): alloca() failed", __func__); + return 1; + } + bzero(check_loop,nrpkgs); + newpkgs = alloca(nrpkgs*sizeof(char*)); + if (newpkgs == NULL) { + warnx("%s(): alloca() failed", __func__); + return 1; + } + nrnewpkgs = 0; + + for (i = 0; pkgs[i]; i++) if (!listed[i]) { + check_loop[i] = 1; + cp = strchr(pkgs[i], ':'); + if (cp != NULL) + *cp = '\0'; + list_deps(pkgs[i],pkgs,listed,check_loop,newpkgs,&nrnewpkgs,&err_cnt); + if (cp != NULL) + *cp = ':'; + listed[i] = 1; + newpkgs[nrnewpkgs] = pkgs[i]; + nrnewpkgs++; + } + + if (nrnewpkgs != nrpkgs) { + fprintf(stderr,"This shouldn't happen, and indicates a huge error in the code.\n"); + exit(1); + } + for (i = 0; i < nrnewpkgs; i++) pkgs[i] = newpkgs[i]; + + return err_cnt; +} + +/* + * This recursive function lists the dependencies (that is, the + * "required-by"s) for pkgname, putting them into newpkgs. + */ + +void list_deps(const char *pkgname, char **pkgs, char *listed, + char *check_loop, char **newpkgs, int *nrnewpkgs, + int *err_cnt) { + char **rb, **rbtmp; + char *cp; + int errcode, i, j; + struct reqr_by_entry *rb_entry; + struct reqr_by_head *rb_list; + + if (isinstalledpkg(pkgname) <= 0) + return; + + errcode = requiredby(pkgname, &rb_list, FALSE, TRUE); + if (errcode < 0) + return; + /* + * We put rb_list into an argv style NULL terminated list, + * because requiredby uses some static storage, and list_deps + * is a recursive function. + */ + + rbtmp = rb = alloca((errcode + 1) * sizeof(*rb)); + if (rb == NULL) { + warnx("%s(): alloca() failed", __func__); + (*err_cnt)++; + return; + } + STAILQ_FOREACH(rb_entry, rb_list, link) { + *rbtmp = alloca(strlen(rb_entry->pkgname) + 1); + if (*rbtmp == NULL) { + warnx("%s(): alloca() failed", __func__); + (*err_cnt)++; + return; + } + strcpy(*rbtmp, rb_entry->pkgname); + rbtmp++; + } + *rbtmp = NULL; + + for (i = 0; rb[i]; i++) + for (j = 0; pkgs[j]; j++) if (!listed[j]) { + cp = strchr(pkgs[j], ':'); + if (cp != NULL) + *cp = '\0'; + if (strcmp(rb[i], pkgs[j]) == 0) { /*match */ + /* + * Try to avoid deadlock if package A depends on B which in + * turn depends on C and C due to an error depends on A. + * It Should Never Happen[tm] in real life. + */ + if (check_loop[j]) { + warnx("dependency loop detected for package %s", pkgs[j]); + (*err_cnt)++; + } + else { + check_loop[j] = 1; + list_deps(pkgs[j],pkgs,listed,check_loop,newpkgs,nrnewpkgs,err_cnt); + listed[j] = 1; + newpkgs[*nrnewpkgs] = pkgs[j]; + (*nrnewpkgs)++; + } + } + if (cp != NULL) + *cp = ':'; + } +} + +/* + * Load +REQUIRED_BY file and return a list with names of + * packages that require package reffered to by `pkgname'. + * + * Optionally check that packages listed there are actually + * installed and filter out those that don't (filter == TRUE). + * + * strict argument controls whether the caller want warnings + * to be emitted when there are some non-fatal conditions, + * i.e. package doesn't have +REQUIRED_BY file or some packages + * listed in +REQUIRED_BY don't exist. + * + * Result returned in the **list, while return value is equal + * to the number of entries in the resulting list. Print error + * message and return -1 on error. + */ +int +requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter) +{ + FILE *fp; + char fbuf[FILENAME_MAX], fname[FILENAME_MAX]; + int retval; + struct reqr_by_entry *rb_entry; + static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list); + + *list = &rb_list; + /* Deallocate any previously allocated space */ + while (!STAILQ_EMPTY(&rb_list)) { + rb_entry = STAILQ_FIRST(&rb_list); + STAILQ_REMOVE_HEAD(&rb_list, link); + free(rb_entry); + } + + if (isinstalledpkg(pkgname) <= 0) { + if (strict == TRUE) + warnx("no such package '%s' installed", pkgname); + return -1; + } + + snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, pkgname, + REQUIRED_BY_FNAME); + fp = fopen(fname, "r"); + if (fp == NULL) { + /* Probably pkgname doesn't have any packages that depend on it */ + if (strict == TRUE) + warnx("couldn't open dependency file '%s'", fname); + return 0; + } + + retval = 0; + while (fgets(fbuf, sizeof(fbuf), fp) != NULL) { + if (fbuf[strlen(fbuf) - 1] == '\n') + fbuf[strlen(fbuf) - 1] = '\0'; + if (filter == TRUE && isinstalledpkg(fbuf) <= 0) { + if (strict == TRUE) + warnx("package '%s' is recorded in the '%s' but isn't " + "actually installed", fbuf, fname); + continue; + } + retval++; + rb_entry = malloc(sizeof(*rb_entry)); + if (rb_entry == NULL) { + warnx("%s(): malloc() failed", __func__); + retval = -1; + break; + } + strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname)); + STAILQ_INSERT_TAIL(&rb_list, rb_entry, link); + } + fclose(fp); + + return retval; +} diff --git a/usr.sbin/pkg_install/lib/exec.c b/usr.sbin/pkg_install/lib/exec.c new file mode 100644 index 000000000000..fc8220c5f399 --- /dev/null +++ b/usr.sbin/pkg_install/lib/exec.c @@ -0,0 +1,106 @@ +/* + * 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 system routines. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include + +/* + * Unusual system() substitute. Accepts format string and args, + * builds and executes command. Returns exit code. + */ + +int +vsystem(const char *fmt, ...) +{ + va_list args; + char *cmd; + int ret, maxargs; + + maxargs = sysconf(_SC_ARG_MAX); + maxargs -= 32; /* some slop for the sh -c */ + cmd = malloc(maxargs); + if (!cmd) { + warnx("vsystem can't alloc arg space"); + return 1; + } + + va_start(args, fmt); + if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) { + warnx("vsystem args are too long"); + return 1; + } +#ifdef DEBUG +printf("Executing %s\n", cmd); +#endif + ret = system(cmd); + va_end(args); + free(cmd); + return ret; +} + +char * +vpipe(const char *fmt, ...) +{ + FILE *fp; + char *cmd, *rp; + int maxargs; + va_list args; + + rp = malloc(MAXPATHLEN); + if (!rp) { + warnx("vpipe can't alloc buffer space"); + return NULL; + } + maxargs = sysconf(_SC_ARG_MAX); + maxargs -= 32; /* some slop for the sh -c */ + cmd = alloca(maxargs); + if (!cmd) { + warnx("vpipe can't alloc arg space"); + return NULL; + } + + va_start(args, fmt); + if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) { + warnx("vsystem args are too long"); + return NULL; + } +#ifdef DEBUG + fprintf(stderr, "Executing %s\n", cmd); +#endif + fflush(NULL); + fp = popen(cmd, "r"); + if (fp == NULL) { + warnx("popen() failed"); + return NULL; + } + get_string(rp, MAXPATHLEN, fp); +#ifdef DEBUG + fprintf(stderr, "Returned %s\n", rp); +#endif + va_end(args); + if (pclose(fp) || (strlen(rp) == 0)) { + free(rp); + return NULL; + } + return rp; +} diff --git a/usr.sbin/pkg_install/lib/file.c b/usr.sbin/pkg_install/lib/file.c new file mode 100644 index 000000000000..c7ab9d6b2977 --- /dev/null +++ b/usr.sbin/pkg_install/lib/file.c @@ -0,0 +1,436 @@ +/* + * 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) +{ + int fd; + + if ((fd = open(fname, O_RDONLY)) == -1) + return FALSE; + + close(fd); + return TRUE; +} + +/* 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 %lld 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, "/bin/cp -r %s %s", fname, to); + else + 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 *tdir) +{ + char from[FILENAME_MAX]; + char to[FILENAME_MAX]; + + if (fname[0] == '/') + strncpy(from, fname, FILENAME_MAX); + else + snprintf(from, FILENAME_MAX, "%s/%s", dir, fname); + + snprintf(to, FILENAME_MAX, "%s/%s", tdir, fname); + + if (rename(from, to) == -1) { + if (vsystem("/bin/mv %s %s", from, to)) { + cleanup(0); + errx(2, "%s: could not move '%s' to '%s'", __func__, from, to); + } + } +} + +/* + * 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, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -", + dir, fname); + } + else + 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 + comp = "-j"; + 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'; +} diff --git a/usr.sbin/pkg_install/lib/global.c b/usr.sbin/pkg_install/lib/global.c new file mode 100644 index 000000000000..e136ec86a6f2 --- /dev/null +++ b/usr.sbin/pkg_install/lib/global.c @@ -0,0 +1,32 @@ +/* + * 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 + * + * Semi-convenient place to stick some needed globals. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" + +/* These are global for all utils */ +Boolean Quiet = FALSE; +Boolean Fake = FALSE; +Boolean Force = FALSE; +int AutoAnswer = FALSE; +int Verbose = 0; /* Allow multiple levels of verbose. */ diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h new file mode 100644 index 000000000000..089bfa3630b9 --- /dev/null +++ b/usr.sbin/pkg_install/lib/lib.h @@ -0,0 +1,242 @@ +/* $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 +#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 + +/* Some more stat macros. */ +#define S_IRALL 0000444 +#define S_IWALL 0000222 +#define S_IXALL 0000111 + +/* Usually "rm", but often "echo" during debugging! */ +#define REMOVE_CMD "/bin/rm" + +/* Usually "rm", but often "echo" during debugging! */ +#define RMDIR_CMD "/bin/rmdir" + +/* Where the ports lives by default */ +#define DEF_PORTS_DIR "/usr/ports" +/* just in case we change the environment variable name */ +#define PORTSDIR "PORTSDIR" +/* macro to get name of directory where the ports lives */ +#define PORTS_DIR (getenv(PORTSDIR) ? getenv(PORTSDIR) : DEF_PORTS_DIR) + +/* 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" + +#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 whenever you make a change + * in the code that is not cosmetic only. + */ +#define PKG_INSTALL_VERSION 20100403 + +#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, + PLIST_NOINST +}; +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); +const char *make_playpen(char *, off_t); +char *where_playpen(void); +int 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 *); +const char *fileGetURL(const char *, const char *, int); +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 *); +char ***matchallbyorigin(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 Quiet; +extern Boolean Fake; +extern Boolean Force; +extern int AutoAnswer; +extern int Verbose; + +#endif /* _INST_LIB_LIB_H_ */ diff --git a/usr.sbin/pkg_install/lib/match.c b/usr.sbin/pkg_install/lib/match.c new file mode 100644 index 000000000000..6c1b2bfcf003 --- /dev/null +++ b/usr.sbin/pkg_install/lib/match.c @@ -0,0 +1,603 @@ +/* + * 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 = 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 *** +matchallbyorigin(const char **origins, int *retval) +{ + char **installed, **allorigins = NULL; + char ***matches = NULL; + int i, j; + + if (retval != NULL) + *retval = 0; + + installed = matchinstalled(MATCH_ALL, NULL, retval); + if (installed == NULL) + return NULL; + + /* Gather origins for all installed packages */ + for (i = 0; installed[i] != NULL; i++) { + FILE *fp; + char *buf, *cp, tmp[PATH_MAX]; + int cmd; + + allorigins = realloc(allorigins, (i + 1) * sizeof(*allorigins)); + allorigins[i] = NULL; + + 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; + strncat(tmp, "/" CONTENTS_FNAME, PATH_MAX); + 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) { + asprintf(&buf, "%s", cp); + allorigins[i] = buf; + break; + } + } + if (cmd != PLIST_ORIGIN && ( Verbose || 0 != strncmp("bsdpan-", installed[i], 7 ) ) ) + warnx("package %s has no origin recorded", installed[i]); + fclose(fp); + } + + /* Resolve origins into package names, retaining the sequence */ + for (i = 0; origins[i] != NULL; i++) { + matches = realloc(matches, (i + 1) * sizeof(*matches)); + struct store *store = NULL; + store = storecreate(store); + + for (j = 0; installed[j] != NULL; j++) { + if (allorigins[j]) { + if (csh_match(origins[i], allorigins[j], FNM_PATHNAME) == 0) { + storeappend(store, installed[j]); + } + } + } + if (store->used == 0) + matches[i] = NULL; + else + matches[i] = store->store; + } + + if (allorigins) { + for (i = 0; installed[i] != NULL; i++) + if (allorigins[i]) + free(allorigins[i]); + free(allorigins); + } + + return matches; +} + +/* + * Synopsis is similar to matchinstalled(), but use origin + * as a key for matching packages. + */ +char ** +matchbyorigin(const char *origin, int *retval) +{ + const char *origins[2]; + char ***tmp; + + origins[0] = origin; + origins[1] = NULL; + + tmp = matchallbyorigin(origins, retval); + if (tmp && tmp[0]) { + return tmp[0]; + } else { + return NULL; + } +} + +/* + * Small linked list to memoize results of isinstalledpkg(). A hash table + * would be faster but for n ~= 1000 may be overkill. + */ +struct iip_memo { + LIST_ENTRY(iip_memo) iip_link; + char *iip_name; + int iip_result; +}; +LIST_HEAD(, iip_memo) iip_memo = LIST_HEAD_INITIALIZER(iip_memo); + +/* + * + * Return 1 if the specified package is installed, + * 0 if not, and -1 if an error occured. + */ +int +isinstalledpkg(const char *name) +{ + int result; + char *buf, *buf2; + struct iip_memo *memo; + + LIST_FOREACH(memo, &iip_memo, iip_link) { + if (strcmp(memo->iip_name, name) == 0) + return memo->iip_result; + } + + buf2 = NULL; + asprintf(&buf, "%s/%s", LOG_DIR, name); + if (buf == NULL) + goto errout; + if (!isdir(buf) || access(buf, R_OK) == FAIL) { + result = 0; + } else { + asprintf(&buf2, "%s/%s", buf, CONTENTS_FNAME); + if (buf2 == NULL) + goto errout; + + if (!isfile(buf2) || access(buf2, R_OK) == FAIL) + result = -1; + else + result = 1; + } + + free(buf); + buf = strdup(name); + if (buf == NULL) + goto errout; + free(buf2); + buf2 = NULL; + + memo = malloc(sizeof *memo); + if (memo == NULL) + goto errout; + memo->iip_name = buf; + memo->iip_result = result; + LIST_INSERT_HEAD(&iip_memo, memo, iip_link); + return result; + +errout: + if (buf != NULL) + free(buf); + if (buf2 != NULL) + free(buf2); + 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); +} diff --git a/usr.sbin/pkg_install/lib/msg.c b/usr.sbin/pkg_install/lib/msg.c new file mode 100644 index 000000000000..5b17624016d0 --- /dev/null +++ b/usr.sbin/pkg_install/lib/msg.c @@ -0,0 +1,75 @@ +/* + * 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 message routines. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include +#include + +/* Die a relatively simple death */ +void +upchuck(const char *message) +{ + cleanup(0); + errx(1, "fatal error during execution: %s", message); +} + +/* + * As a yes/no question, prompting from the varargs string and using + * default if user just hits return. + */ +Boolean +y_or_n(Boolean def, const char *msg, ...) +{ + va_list args; + int ch = 0; + FILE *tty; + + va_start(args, msg); + /* + * Need to open /dev/tty because file collection may have been + * collected on stdin + */ + tty = fopen(_PATH_TTY, "r"); + if (!tty) { + cleanup(0); + errx(2, "can't open %s!", _PATH_TTY); + } + while (ch != 'Y' && ch != 'N') { + vfprintf(stderr, msg, args); + if (def) + fprintf(stderr, " [yes]? "); + else + fprintf(stderr, " [no]? "); + fflush(stderr); + if (AutoAnswer) { + ch = (AutoAnswer == YES) ? 'Y' : 'N'; + fprintf(stderr, "%c\n", ch); + } + else + ch = toupper(fgetc(tty)); + if (ch == '\n') + ch = (def) ? 'Y' : 'N'; + } + fclose(tty) ; + return (ch == 'Y') ? TRUE : FALSE; +} diff --git a/usr.sbin/pkg_install/lib/pen.c b/usr.sbin/pkg_install/lib/pen.c new file mode 100644 index 000000000000..2b405a3a43a8 --- /dev/null +++ b/usr.sbin/pkg_install/lib/pen.c @@ -0,0 +1,186 @@ +/* + * 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 +#include + +/* For keeping track of where we are */ +static char PenLocation[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; + char humbuf[6]; + + 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); + humanize_number(humbuf, sizeof humbuf, sz, "", HN_AUTOSCALE, + HN_NOSPACE); + 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 %s bytes\n" +"free", __func__, humbuf); + return NULL; + } + return pen; +} + +#define MAX_STACK 20 +static char *pstack[MAX_STACK]; +static int pdepth = -1; + +static const char * +pushPen(const char *pen) +{ + if (++pdepth == MAX_STACK) + errx(2, "%s: stack overflow.\n", __func__); + pstack[pdepth] = strdup(pen); + + return pstack[pdepth]; +} + +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. + */ +const char * +make_playpen(char *pen, off_t sz) +{ + char humbuf1[6], humbuf2[6]; + char cwd[FILENAME_MAX]; + + if (!find_play_pen(pen, sz)) + return NULL; + + if (!mkdtemp(pen)) { + cleanup(0); + errx(2, "%s: can't mktemp '%s'", __func__, pen); + } + + if (Verbose) { + if (sz) { + humanize_number(humbuf1, sizeof humbuf1, sz, "", HN_AUTOSCALE, + HN_NOSPACE); + humanize_number(humbuf2, sizeof humbuf2, min_free(pen), + "", HN_AUTOSCALE, HN_NOSPACE); + fprintf(stderr, "Requested space: %s bytes, free space: %s bytes in %s\n", humbuf1, humbuf2, 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(cwd, FILENAME_MAX)) { + upchuck("getcwd"); + return NULL; + } + + if (chdir(pen) == FAIL) { + cleanup(0); + errx(2, "%s: can't chdir to '%s'", __func__, pen); + } + + strcpy(PenLocation, pen); + return pushPen(cwd); +} + +/* Convenience routine for getting out of playpen */ +int +leave_playpen() +{ + static char left[FILENAME_MAX]; + void (*oldsig)(int); + + if (!PenLocation[0]) + return 0; + + /* Don't interrupt while we're cleaning up */ + oldsig = signal(SIGINT, SIG_IGN); + strcpy(left, PenLocation); + popPen(PenLocation); + + if (chdir(PenLocation) == FAIL) { + cleanup(0); + errx(2, "%s: can't chdir back to '%s'", __func__, PenLocation); + } + + if (left[0] == '/' && vsystem("/bin/rm -rf %s", left)) + warnx("couldn't remove temporary dir '%s'", left); + signal(SIGINT, oldsig); + + return 1; +} + +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; +} diff --git a/usr.sbin/pkg_install/lib/pkgwrap.c b/usr.sbin/pkg_install/lib/pkgwrap.c new file mode 100644 index 000000000000..cbd15cd7b445 --- /dev/null +++ b/usr.sbin/pkg_install/lib/pkgwrap.c @@ -0,0 +1,89 @@ +/* + * FreeBSD install - a package for the installation and maintenance + * 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 + * 8 September 2002 + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include +#include +#include +#include + +#undef main + +#define SEPARATORS " \t" + +extern char **environ; + +int +main(int argc, char **argv) +{ + FILE *f; + char buffer[FILENAME_MAX], *cp, *verstr; + int len; + + if (getenv("PKG_NOWRAP") != NULL) + goto nowrap; + f = fopen(PKG_WRAPCONF_FNAME, "r"); + if (f == NULL) + goto nowrap; + cp = fgets(buffer, 256, f); + fclose(f); + if (cp == NULL) + goto nowrap; + len = strlen(cp); + if (cp[len - 1] == '\n') + cp[len - 1] = '\0'; + while (strchr(SEPARATORS, *cp) != NULL) + cp++; + verstr = cp; + cp = strpbrk(cp, SEPARATORS); + if (cp == NULL) + goto nowrap; + *cp = '\0'; + for (cp = verstr; *cp != '\0'; cp++) + if (isdigit(*cp) == 0) + goto nowrap; + if (atoi(verstr) < PKG_INSTALL_VERSION) + goto nowrap; + cp++; + while (*cp != '\0' && strchr(SEPARATORS, *cp) != NULL) + cp++; + if (*cp == '\0') + goto nowrap; + bcopy(cp, buffer, strlen(cp) + 1); + cp = strpbrk(buffer, SEPARATORS); + if (cp != NULL) + *cp = '\0'; + if (!isdir(buffer)) + goto nowrap; + cp = strrchr(argv[0], '/'); + if (cp == NULL) + cp = argv[0]; + else + cp++; + strlcat(buffer, "/", sizeof(buffer)); + strlcat(buffer, cp, sizeof(buffer)); + setenv("PKG_NOWRAP", "1", 1); + execve(buffer, argv, environ); + +nowrap: + unsetenv("PKG_NOWRAP"); + return(real_main(argc, argv)); +} diff --git a/usr.sbin/pkg_install/lib/plist.c b/usr.sbin/pkg_install/lib/plist.c new file mode 100644 index 000000000000..545b541c3f18 --- /dev/null +++ b/usr.sbin/pkg_install/lib/plist.c @@ -0,0 +1,592 @@ +/* + * 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 + * + * General packing list routines. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include +#include + +/* Add an item to a packing list */ +void +add_plist(Package *p, plist_t type, const char *arg) +{ + PackingList tmp; + + tmp = new_plist_entry(); + tmp->name = copy_string(arg); + tmp->type = type; + + if (!p->head) + p->head = p->tail = tmp; + else { + tmp->prev = p->tail; + p->tail->next = tmp; + p->tail = tmp; + } + switch (type) { + case PLIST_NAME: + p->name = tmp->name; + break; + + case PLIST_ORIGIN: + p->origin = tmp->name; + break; + + default: + break; + } +} + +void +add_plist_top(Package *p, plist_t type, const char *arg) +{ + PackingList tmp; + + tmp = new_plist_entry(); + tmp->name = copy_string(arg); + tmp->type = type; + + if (!p->head) + p->head = p->tail = tmp; + else { + tmp->next = p->head; + p->head->prev = tmp; + p->head = tmp; + } +} + +/* Return the last (most recent) entry in a packing list */ +PackingList +last_plist(Package *p) +{ + return p->tail; +} + +/* Mark all items in a packing list to prevent iteration over them */ +void +mark_plist(Package *pkg) +{ + PackingList p = pkg->head; + + while (p) { + p->marked = TRUE; + p = p->next; + } +} + +/* Find a given item in a packing list and, if so, return it (else NULL) */ +PackingList +find_plist(Package *pkg, plist_t type) +{ + PackingList p = pkg->head; + + while (p) { + if (p->type == type) + return p; + p = p->next; + } + return NULL; +} + +/* Look for a specific boolean option argument in the list */ +char * +find_plist_option(Package *pkg, const char *name) +{ + PackingList p = pkg->head; + + while (p) { + if (p->type == PLIST_OPTION && !strcmp(p->name, name)) + return p->name; + p = p->next; + } + return NULL; +} + +/* + * Delete plist item 'type' in the list (if 'name' is non-null, match it + * too.) If 'all' is set, delete all items, not just the first occurance. + */ +void +delete_plist(Package *pkg, Boolean all, plist_t type, const char *name) +{ + PackingList p = pkg->head; + + while (p) { + PackingList pnext = p->next; + + if (p->type == type && (!name || !strcmp(name, p->name))) { + free(p->name); + if (p->prev) + p->prev->next = pnext; + else + pkg->head = pnext; + if (pnext) + pnext->prev = p->prev; + else + pkg->tail = p->prev; + free(p); + if (!all) + return; + p = pnext; + } + else + p = p->next; + } +} + +/* Allocate a new packing list entry */ +PackingList +new_plist_entry(void) +{ + PackingList ret; + + ret = (PackingList)malloc(sizeof(struct _plist)); + bzero(ret, sizeof(struct _plist)); + return ret; +} + +/* Free an entire packing list */ +void +free_plist(Package *pkg) +{ + PackingList p = pkg->head; + + while (p) { + PackingList p1 = p->next; + + free(p->name); + free(p); + p = p1; + } + pkg->head = pkg->tail = NULL; +} + +/* + * For an ascii string denoting a plist command, return its code and + * optionally its argument(s) + */ +int +plist_cmd(const char *s, char **arg) +{ + char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */ + char *cp; + const char *sp; + + strcpy(cmd, s); + str_lowercase(cmd); + cp = cmd; + sp = s; + while (*cp) { + if (isspace(*cp)) { + *cp = '\0'; + while (isspace(*sp)) /* Never sure if macro, increment later */ + ++sp; + break; + } + ++cp, ++sp; + } + if (arg) + *arg = (char *)sp; + if (!strcmp(cmd, "cwd")) + return PLIST_CWD; + else if (!strcmp(cmd, "srcdir")) + return PLIST_SRC; + else if (!strcmp(cmd, "cd")) + return PLIST_CWD; + else if (!strcmp(cmd, "exec")) + return PLIST_CMD; + else if (!strcmp(cmd, "unexec")) + return PLIST_UNEXEC; + else if (!strcmp(cmd, "mode")) + return PLIST_CHMOD; + else if (!strcmp(cmd, "owner")) + return PLIST_CHOWN; + else if (!strcmp(cmd, "group")) + return PLIST_CHGRP; + else if (!strcmp(cmd, "noinst")) + return PLIST_NOINST; + else if (!strcmp(cmd, "comment")) { + if (!strncmp(*arg, "ORIGIN:", 7)) { + *arg += 7; + return PLIST_ORIGIN; + } else if (!strncmp(*arg, "DEPORIGIN:", 10)) { + *arg += 10; + return PLIST_DEPORIGIN; + } + return PLIST_COMMENT; + } else if (!strcmp(cmd, "ignore")) + return PLIST_IGNORE; + else if (!strcmp(cmd, "ignore_inst")) + return PLIST_IGNORE_INST; + else if (!strcmp(cmd, "name")) + return PLIST_NAME; + else if (!strcmp(cmd, "display")) + return PLIST_DISPLAY; + else if (!strcmp(cmd, "pkgdep")) + return PLIST_PKGDEP; + else if (!strcmp(cmd, "conflicts")) + return PLIST_CONFLICTS; + else if (!strcmp(cmd, "mtree")) + return PLIST_MTREE; + else if (!strcmp(cmd, "dirrm")) + return PLIST_DIR_RM; + else if (!strcmp(cmd, "option")) + return PLIST_OPTION; + else + return FAIL; +} + +/* Read a packing list from a file */ +void +read_plist(Package *pkg, FILE *fp) +{ + char *cp, pline[FILENAME_MAX]; + int cmd, major, minor; + + pkg->fmtver_maj = 1; + pkg->fmtver_mnr = 0; + pkg->origin = NULL; + while (fgets(pline, FILENAME_MAX, fp)) { + int len = strlen(pline); + + while (len && isspace(pline[len - 1])) + pline[--len] = '\0'; + if (!len) + continue; + cp = pline; + if (pline[0] != CMD_CHAR) { + cmd = PLIST_FILE; + goto bottom; + } + cmd = plist_cmd(pline + 1, &cp); + if (cmd == FAIL) { + warnx("%s: unknown command '%s' (package tools out of date?)", + __func__, pline); + goto bottom; + } + if (*cp == '\0') { + cp = NULL; + if (cmd == PLIST_PKGDEP) { + warnx("corrupted record (pkgdep line without argument), ignoring"); + cmd = FAIL; + } + goto bottom; + } + if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n", + &major, &minor) == 2) { + pkg->fmtver_maj = major; + pkg->fmtver_mnr = minor; + if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0) + goto bottom; + + warnx("plist format revision (%d.%d) is higher than supported" + "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr, + PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR); + if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) { + cleanup(0); + exit(2); + } + } +bottom: + add_plist(pkg, cmd, cp); + } +} + +/* Write a packing list to a file, converting commands to ascii equivs */ +void +write_plist(Package *pkg, FILE *fp) +{ + PackingList plist = pkg->head; + + while (plist) { + switch(plist->type) { + case PLIST_FILE: + fprintf(fp, "%s\n", plist->name); + break; + + case PLIST_CWD: + fprintf(fp, "%ccwd %s\n", CMD_CHAR, (plist->name == NULL) ? "" : plist->name); + break; + + case PLIST_SRC: + fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_CMD: + fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_UNEXEC: + fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_CHMOD: + fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : ""); + break; + + case PLIST_CHOWN: + fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : ""); + break; + + case PLIST_CHGRP: + fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : ""); + break; + + case PLIST_COMMENT: + fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_NOINST: + fprintf(fp, "%cnoinst %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_IGNORE: + case PLIST_IGNORE_INST: /* a one-time non-ignored file */ + fprintf(fp, "%cignore\n", CMD_CHAR); + break; + + case PLIST_NAME: + fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_DISPLAY: + fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_PKGDEP: + fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_CONFLICTS: + fprintf(fp, "%cconflicts %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_MTREE: + fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_DIR_RM: + fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_OPTION: + fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name); + break; + + case PLIST_ORIGIN: + fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name); + break; + + case PLIST_DEPORIGIN: + fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name); + break; + + default: + cleanup(0); + errx(2, "%s: unknown command type %d (%s)", __func__, + plist->type, plist->name); + break; + } + plist = plist->next; + } +} + +/* + * Delete the results of a package installation. + * + * This is here rather than in the pkg_delete code because pkg_add needs to + * run it too in cases of failure. + */ +int +delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg) +{ + PackingList p; + const char *Where = ".", *last_file = ""; + Boolean fail = SUCCESS; + Boolean preserve; + char tmp[FILENAME_MAX], *name = NULL; + char *prefix = NULL; + + preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; + for (p = pkg->head; p; p = p->next) { + switch (p->type) { + case PLIST_NAME: + name = p->name; + break; + + case PLIST_IGNORE: + p = p->next; + break; + + case PLIST_CWD: + if (!prefix) + prefix = p->name; + Where = (p->name == NULL) ? prefix : p->name; + if (Verbose) + printf("Change working directory to %s\n", Where); + break; + + case PLIST_UNEXEC: + format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file); + if (Verbose) + printf("Execute '%s'\n", tmp); + if (!Fake && system(tmp)) { + warnx("unexec command for '%s' failed", tmp); + fail = FAIL; + } + break; + + case PLIST_FILE: + last_file = p->name; + sprintf(tmp, "%s/%s", Where, p->name); + if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) { + warnx("cannot delete specified file '%s' - it is a directory!\n" + "this packing list is incorrect - ignoring delete request", tmp); + } + else { + if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) { + char *cp = NULL, buf[33]; + + /* + * For packing lists whose version is 1.1 or greater, the md5 + * hash for a symlink is calculated on the string returned + * by readlink(). + */ + if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) { + int len; + char linkbuf[FILENAME_MAX]; + + if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0) + cp = MD5Data((unsigned char *)linkbuf, len, buf); + } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0) + cp = MD5File(tmp, buf); + + if (cp != NULL) { + /* Mismatch? */ + if (strcmp(cp, p->next->name + 4)) { + warnx("'%s' fails original MD5 checksum - %s", + tmp, Force ? "deleted anyway." : "not deleted."); + if (!Force) { + fail = FAIL; + continue; + } + } + } + } + if (Verbose) + printf("Delete file %s\n", tmp); + if (!Fake) { + if (delete_hierarchy(tmp, ign_err, nukedirs)) + fail = FAIL; + if (preserve && name) { + char tmp2[FILENAME_MAX]; + + if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) { + if (fexists(tmp2)) { + if (rename(tmp2, tmp)) + warn("preserve: unable to restore %s as %s", + tmp2, tmp); + } + } + } + } + } + break; + + case PLIST_DIR_RM: + sprintf(tmp, "%s/%s", Where, p->name); + if (!isdir(tmp) && fexists(tmp)) { + warnx("cannot delete specified directory '%s' - it is a file!\n" + "this packing list is incorrect - ignoring delete request", tmp); + } + else { + if (Verbose) + printf("Delete directory %s\n", tmp); + if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) { + warnx("unable to completely remove directory '%s'", tmp); + fail = FAIL; + } + } + last_file = p->name; + break; + + default: + break; + } + } + return fail; +} + +#ifdef DEBUG +#define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir) +#define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir) +#else +#define RMDIR rmdir +#define REMOVE(file,ie) (remove(file) && !(ie)) +#endif + +/* Selectively delete a hierarchy */ +int +delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs) +{ + char *cp1, *cp2; + + cp1 = cp2 = strdup(dir); + if (!fexists(dir) && !issymlink(dir)) { + if (!ign_err) + warnx("%s '%s' doesn't exist", + isdir(dir) ? "directory" : "file", dir); + return !ign_err; + } + else if (nukedirs) { + if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir)) + return 1; + } + else if (isdir(dir) && !issymlink(dir)) { + if (RMDIR(dir) && !ign_err) + return 1; + } + else { + if (REMOVE(dir, ign_err)) + return 1; + } + + if (!nukedirs) + return 0; + while (cp2) { + if ((cp2 = strrchr(cp1, '/')) != NULL) + *cp2 = '\0'; + if (!isemptydir(dir)) + return 0; + if (RMDIR(dir) && !ign_err) { + if (!fexists(dir)) + warnx("directory '%s' doesn't exist", dir); + else + return 1; + } + /* back up the pathname one component */ + if (cp2) { + cp1 = strdup(dir); + } + } + return 0; +} diff --git a/usr.sbin/pkg_install/lib/str.c b/usr.sbin/pkg_install/lib/str.c new file mode 100644 index 000000000000..0d9e288b7579 --- /dev/null +++ b/usr.sbin/pkg_install/lib/str.c @@ -0,0 +1,129 @@ +/* + * 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 string utilities. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" + +char * +strconcat(const char *s1, const char *s2) +{ + static char tmp[FILENAME_MAX]; + + tmp[0] = '\0'; + strncpy(tmp, s1 ? s1 : s2, FILENAME_MAX); /* XXX: what if both are NULL? */ + if (s1 && s2) + strncat(tmp, s2, FILENAME_MAX - strlen(tmp)); + return tmp; +} + +/* Get a string parameter as a file spec or as a "contents follow -" spec */ +char * +get_dash_string(char **str) +{ + char *s = *str; + + if (*s == '-') + *str = copy_string_adds_newline(s + 1); + else + *str = fileGetContents(s); + return *str; +} + +/* Rather Obvious */ +char * +copy_string(const char *str) +{ + return (str ? strdup(str) : NULL); +} + +/* Rather Obvious but adds a trailing \n newline */ +char * +copy_string_adds_newline(const char *str) +{ + if (str == NULL) { + return (NULL); + } else { + char *copy; + size_t line_length; + + line_length = strlen(str) + 2; + if ((copy = malloc(line_length)) == NULL) + return (NULL); + memcpy(copy, str, line_length - 2); + copy[line_length - 2] = '\n'; /* Adds trailing \n */ + copy[line_length - 1] = '\0'; + + return (copy); + } +} + +/* Return TRUE if 'str' ends in suffix 'suff' */ +Boolean +suffix(const char *str, const char *suff) +{ + char *idx; + Boolean ret = FALSE; + + idx = strrchr(str, '.'); + if (idx && !strcmp(idx + 1, suff)) + ret = TRUE; + return ret; +} + +/* Assuming str has a suffix, brutally murder it! */ +void +nuke_suffix(char *str) +{ + char *idx; + + idx = strrchr(str, '.'); + if (idx) + *idx = '\0'; /* Yow! Don't try this on a const! */ +} + +/* Lowercase a whole string */ +void +str_lowercase(char *str) +{ + while (*str) { + *str = tolower(*str); + ++str; + } +} + +char * +get_string(char *str, int max, FILE *fp) +{ + int len; + + if (!str) + return NULL; + str[0] = '\0'; + while (fgets(str, max, fp)) { + len = strlen(str); + while (len && isspace(str[len - 1])) + str[--len] = '\0'; + if (len) + return str; + } + return NULL; +} diff --git a/usr.sbin/pkg_install/lib/url.c b/usr.sbin/pkg_install/lib/url.c new file mode 100644 index 000000000000..8c5534711997 --- /dev/null +++ b/usr.sbin/pkg_install/lib/url.c @@ -0,0 +1,171 @@ +/* + * 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 +#include +#include + +/* + * Try and fetch a file by URL, returning the directory name for where + * it's unpacked, if successful. + */ +const char * +fileGetURL(const char *base, const char *spec, int keep_package) +{ + const char *rp; + char *cp, *tmp; + char fname[FILENAME_MAX]; + char pen[FILENAME_MAX]; + char pkg[FILENAME_MAX]; + char buf[8192]; + FILE *ftp; + pid_t tpid; + int pfd[2], pstat, r, w = 0; + char *hint; + int fd, pkgfd = 0; + + 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); + strcat(cp, ".tbz"); + } + 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); + strcat(fname, ".tbz"); + } + } + else + strcpy(fname, spec); + + if (keep_package) { + tmp = getenv("PKGDIR"); + strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg)); + tmp = basename(fname); + strlcat(pkg, "/", sizeof(pkg)); + strlcat(pkg, tmp, sizeof(pkg)); + if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { + printf("Error: Unable to open %s\n", pkg); + perror("open"); + return NULL; + } + } + + fetchDebug = (Verbose > 0); + if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) { + printf("Error: Unable to get %s: %s\n", + fname, fetchLastErrString); + /* If the fetch fails, yank the package. */ + if (keep_package && unlink(pkg) < 0 && Verbose) { + warnx("failed to remove partially fetched package: %s", pkg); + } + 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); + execl("/usr/bin/tar", "tar", + Verbose ? "-xpjvf" : "-xpjf", + "-", (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 (keep_package) { + if ((w = write(pkgfd, buf, r)) != r) + break; + } + } + if (ferror(ftp)) + warn("warning: error reading from server"); + fclose(ftp); + if (keep_package) { + close(pkgfd); + } + 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; +} diff --git a/usr.sbin/pkg_install/lib/version.c b/usr.sbin/pkg_install/lib/version.c new file mode 100644 index 000000000000..d9c4fe7e070c --- /dev/null +++ b/usr.sbin/pkg_install/lib/version.c @@ -0,0 +1,328 @@ +/* + * FreeBSD install - a package for the installation and maintenance + * 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 + * 31 July 2001 + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include + +/* + * Routines to assist with PLIST_FMT_VER numbers in the packing + * lists. + * + * Following is the PLIST_FMT_VER history: + * 1.0 - Initial revision; + * 1.1 - When recording/checking checksum of symlink use hash of readlink() + * value instead of the hash of an object this links points to. + * + */ +int +verscmp(Package *pkg, int major, int minor) +{ + int rval = 0; + + if ((pkg->fmtver_maj < major) || (pkg->fmtver_maj == major && + pkg->fmtver_mnr < minor)) + rval = -1; + else if ((pkg->fmtver_maj > major) || (pkg->fmtver_maj == major && + pkg->fmtver_mnr > minor)) + rval = 1; + + return rval; +} + +/* + * split_version(pkgname, endname, epoch, revision) returns a pointer to + * the version portion of a package name and the two special components. + * + * Syntax is: ${PORTNAME}-${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}] + * + * Written by Oliver Eikemeier + * Based on work of Jeremy D. Lea. + */ +static const char * +split_version(const char *pkgname, const char **endname, unsigned long *epoch, unsigned long *revision) +{ + char *ch; + const char *versionstr; + const char *endversionstr; + + if (pkgname == NULL) + errx(2, "%s: Passed NULL pkgname.", __func__); + + /* Look for the last '-' the the pkgname */ + ch = strrchr(pkgname, '-'); + /* Cheat if we are just passed a version, not a valid package name */ + versionstr = ch ? ch + 1 : pkgname; + + /* Look for the last '_' in the version string, advancing the end pointer */ + ch = strrchr(versionstr, '_'); + if (revision != NULL) { + *revision = ch ? strtoul(ch + 1, NULL, 10) : 0; + } + endversionstr = ch; + + /* Look for the last ',' in the remaining version string */ + ch = strrchr(endversionstr ? endversionstr + 1 : versionstr, ','); + if (epoch != NULL) { + *epoch = ch ? strtoul(ch + 1, NULL, 10) : 0; + } + if (ch && !endversionstr) + endversionstr = ch; + + /* set the pointer behind the last character of the version without revision or epoch */ + if (endname) + *endname = endversionstr ? endversionstr : strrchr(versionstr, '\0'); + + return versionstr; +} + +/* + * PORTVERSIONs are composed of components separated by dots. A component + * consists of a version number, a letter and a patchlevel number. This does + * not conform to the porter's handbook, but let us formulate rules that + * fit the current practice and are far simpler than to make decisions + * based on the order of netters and lumbers. Besides, people use versions + * like 10b2 in the ports... + */ + +typedef struct { +#ifdef __LONG_LONG_SUPPORTED + long long n; + long long pl; +#else + long n; + long pl; +#endif + int a; +} version_component; + +/* + * get_component(position, component) gets the value of the next component + * (number - letter - number triple) and returns a pointer to the next character + * after any leading separators + * + * - components are separated by dots + * - characters !~ [a-zA-Z0-9.+*] are treated as separators + * (1.0:2003.09.16 = 1.0.2003.09.16), this may not be what you expect: + * 1.0.1:2003.09.16 < 1.0:2003.09.16 + * - consecutive separators are collapsed (10..1 = 10.1) + * - missing separators are inserted, essentially + * letter number letter => letter number . letter (10a1b2 = 10a1.b2) + * - missing components are assumed to be equal to 0 (10 = 10.0 = 10.0.0) + * - the letter sort order is: [none], a, b, ..., z; numbers without letters + * sort first (10 < 10a < 10b) + * - missing version numbers (in components starting with a letter) sort as -1 + * (a < 0, 10.a < 10) + * - a separator is inserted before the special strings "pl", "alpha", "beta", + * "pre" and "rc". + * - "pl" sorts before every other letter, "alpha", "beta", "pre" and "rc" + * sort as a, b, p and r. (10alpha = 10.a < 10, but 10 < 10a; pl11 < alpha3 + * < 0.1beta2 = 0.1.b2 < 0.1) + * - other strings use only the first letter for sorting, case is ignored + * (1.d2 = 1.dev2 = 1.Development2) + * - The special component `*' is guaranteed to be the smallest possible + * component (2.* < 2pl1 < 2alpha3 < 2.9f7 < 3.*) + * - components separated by `+' are handled by version_cmp below + * + * Oliver Eikemeier + */ + +static const struct { + const char *name; + size_t namelen; + int value; +} stage[] = { + { "pl", 2, 0 }, + { "alpha", 5, 'a'-'a'+1 }, + { "beta", 4, 'b'-'a'+1 }, + { "pre", 3, 'p'-'a'+1 }, + { "rc", 2, 'r'-'a'+1 }, + { NULL, 0, -1 } +}; + +static const char * +get_component(const char *position, version_component *component) +{ + const char *pos = position; + int hasstage = 0, haspatchlevel = 0; + + if (!pos) + errx(2, "%s: Passed NULL position.", __func__); + + /* handle version number */ + if (isdigit(*pos)) { + char *endptr; +#ifdef __LONG_LONG_SUPPORTED + component->n = strtoll(pos, &endptr, 10); +#else + component->n = strtol(pos, &endptr, 10); +#endif + /* should we test for errno == ERANGE? */ + pos = endptr; + } else if (*pos == '*') { + component->n = -2; + do { + pos++; + } while(*pos && *pos != '+'); + } else { + component->n = -1; + hasstage = 1; + } + + /* handle letter */ + if (isalpha(*pos)) { + int c = tolower(*pos); + haspatchlevel = 1; + /* handle special suffixes */ + if (isalpha(pos[1])) { + int i; + for (i = 0; stage[i].name; i++) { + if (strncasecmp(pos, stage[i].name, stage[i].namelen) == 0 + && !isalpha(pos[stage[i].namelen])) { + if (hasstage) { + /* stage to value */ + component->a = stage[i].value; + pos += stage[i].namelen; + } else { + /* insert dot */ + component->a = 0; + haspatchlevel = 0; + } + c = 0; + break; + } + } + } + /* unhandled above */ + if (c) { + /* use the first letter and skip following */ + component->a = c - 'a' + 1; + do { + ++pos; + } while (isalpha(*pos)); + } + } else { + component->a = 0; + haspatchlevel = 0; + } + + if (haspatchlevel) { + /* handle patch number */ + if (isdigit(*pos)) { + char *endptr; +#ifdef __LONG_LONG_SUPPORTED + component->pl = strtoll(pos, &endptr, 10); +#else + component->pl = strtol(pos, &endptr, 10); +#endif + /* should we test for errno == ERANGE? */ + pos = endptr; + } else { + component->pl = -1; + } + } else { + component->pl = 0; + } + + /* skip trailing separators */ + while (*pos && !isdigit(*pos) && !isalpha(*pos) && *pos != '+' && *pos != '*') { + pos++; + } + + return pos; +} + +/* + * version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version + * components of pkg1 is less than, equal to or greater than pkg2. No + * comparison of the basenames is done. + * + * The port version is defined by: + * ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}] + * ${PORTEPOCH} supersedes ${PORTVERSION} supersedes ${PORTREVISION}. + * See the commit log for revision 1.349 of ports/Mk/bsd.port.mk + * for more information. + * + * The epoch and revision are defined to be a single number, while the rest + * of the version should conform to the porting guidelines. It can contain + * multiple components, separated by a period, including letters. + * + * The tests allow for significantly more latitude in the version numbers + * than is allowed in the guidelines. No point in enforcing them here. + * That's what portlint is for. + * + * Jeremy D. Lea. + * reimplemented by Oliver Eikemeier + */ +int +version_cmp(const char *pkg1, const char *pkg2) +{ + const char *v1, *v2, *ve1, *ve2; + unsigned long e1, e2, r1, r2; + int result = 0; + + v1 = split_version(pkg1, &ve1, &e1, &r1); + v2 = split_version(pkg2, &ve2, &e2, &r2); + + /* Check epoch, port version, and port revision, in that order. */ + if (e1 != e2) { + result = (e1 < e2 ? -1 : 1); + } + + /* Shortcut check for equality before invoking the parsing routines. */ + if (result == 0 && (ve1 - v1 != ve2 - v2 || strncasecmp(v1, v2, ve1 - v1) != 0)) { + /* Loop over different components (the parts separated by dots). + * If any component differs, we have the basis for an inequality. */ + while(result == 0 && (v1 < ve1 || v2 < ve2)) { + int block_v1 = 0; + int block_v2 = 0; + version_component vc1 = {0, 0, 0}; + version_component vc2 = {0, 0, 0}; + if (v1 < ve1 && *v1 != '+') { + v1 = get_component(v1, &vc1); + } else { + block_v1 = 1; + } + if (v2 < ve2 && *v2 != '+') { + v2 = get_component(v2, &vc2); + } else { + block_v2 = 1; + } + if (block_v1 && block_v2) { + if (v1 < ve1) + v1++; + if (v2 < ve2) + v2++; + } else if (vc1.n != vc2.n) { + result = (vc1.n < vc2.n ? -1 : 1); + } else if (vc1.a != vc2.a) { + result = (vc1.a < vc2.a ? -1 : 1); + } else if (vc1.pl != vc2.pl) { + result = (vc1.pl < vc2.pl ? -1 : 1); + } + } + } + + /* Compare FreeBSD revision numbers. */ + if (result == 0 && r1 != r2) { + result = (r1 < r2 ? -1 : 1); + } + return result; +} diff --git a/usr.sbin/pkg_install/updating/Makefile b/usr.sbin/pkg_install/updating/Makefile index f5b7525ddb51..b0d3689779e6 100644 --- a/usr.sbin/pkg_install/updating/Makefile +++ b/usr.sbin/pkg_install/updating/Makefile @@ -3,6 +3,11 @@ PROG= pkg_updating SRCS= main.c +CFLAGS+= -I${.CURDIR}/../lib + WFORMAT?= 1 +DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} +LDADD= ${LIBINSTALL} -lfetch -lmd + .include diff --git a/usr.sbin/pkg_install/updating/main.c b/usr.sbin/pkg_install/updating/main.c index 993ccd523104..0ab2ec0fe8ea 100644 --- a/usr.sbin/pkg_install/updating/main.c +++ b/usr.sbin/pkg_install/updating/main.c @@ -19,7 +19,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "pathnames.h" typedef struct installedport { @@ -87,8 +87,6 @@ main(int argc, char *argv[]) DIR *dir; FILE *fd; - pkg_wrap(PKG_INSTALL_VERSION, argv); - while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) { switch (ch) { case 'd': diff --git a/usr.sbin/pkg_install/version/Makefile b/usr.sbin/pkg_install/version/Makefile index fb079e34c7ad..3e1d7a522f27 100644 --- a/usr.sbin/pkg_install/version/Makefile +++ b/usr.sbin/pkg_install/version/Makefile @@ -3,8 +3,13 @@ PROG= pkg_version SRCS= main.c perform.c +CFLAGS+= -I${.CURDIR}/../lib + WFORMAT?= 1 +DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} +LDADD= ${LIBINSTALL} -lfetch -lmd + test: sh ${.CURDIR}/test-pkg_version.sh diff --git a/usr.sbin/pkg_install/version/main.c b/usr.sbin/pkg_install/version/main.c index 42384970603b..cad8583c23bf 100644 --- a/usr.sbin/pkg_install/version/main.c +++ b/usr.sbin/pkg_install/version/main.c @@ -25,7 +25,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "lib.h" #include "version.h" char *LimitChars = NULL; @@ -58,8 +58,6 @@ main(int argc, char **argv) { int ch, cmp = 0; - pkg_wrap(PKG_INSTALL_VERSION, argv); - if (argc == 4 && !strcmp(argv[1], "-t")) { cmp = version_cmp(argv[2], argv[3]); printf(cmp > 0 ? ">\n" : (cmp < 0 ? "<\n" : "=\n")); diff --git a/usr.sbin/pkg_install/version/perform.c b/usr.sbin/pkg_install/version/perform.c index 79575a32ba28..dc85696cfc15 100644 --- a/usr.sbin/pkg_install/version/perform.c +++ b/usr.sbin/pkg_install/version/perform.c @@ -21,7 +21,7 @@ #include __FBSDID("$FreeBSD$"); -#include +#include "lib.h" #include "version.h" #include #include -- cgit v1.3