diff options
Diffstat (limited to 'usr.sbin/pkg_install/lib')
-rw-r--r-- | usr.sbin/pkg_install/lib/Makefile | 10 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/exec.c | 60 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/file.c | 534 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/global.c | 34 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/lib.h | 177 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/msg.c | 101 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/pen.c | 141 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/plist.c | 503 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/str.c | 110 |
9 files changed, 1670 insertions, 0 deletions
diff --git a/usr.sbin/pkg_install/lib/Makefile b/usr.sbin/pkg_install/lib/Makefile new file mode 100644 index 0000000..3876b10 --- /dev/null +++ b/usr.sbin/pkg_install/lib/Makefile @@ -0,0 +1,10 @@ +LIB= install +SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c +CFLAGS+= ${DEBUG} +NOPROFILE= yes +NOPIC= yes + +install: + @echo -n + +.include <bsd.lib.mk> diff --git a/usr.sbin/pkg_install/lib/exec.c b/usr.sbin/pkg_install/lib/exec.c new file mode 100644 index 0000000..87bcc10 --- /dev/null +++ b/usr.sbin/pkg_install/lib/exec.c @@ -0,0 +1,60 @@ +#ifndef lint +static const char *rcsid = "$Id$"; +#endif + +/* + * 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 "lib.h" + +/* + * 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) { + whinge("vsystem can't alloc arg space"); + return 1; + } + + va_start(args, fmt); + if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) { + whinge("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; +} + diff --git a/usr.sbin/pkg_install/lib/file.c b/usr.sbin/pkg_install/lib/file.c new file mode 100644 index 0000000..2748235 --- /dev/null +++ b/usr.sbin/pkg_install/lib/file.c @@ -0,0 +1,534 @@ +#ifndef lint +static const char *rcsid = "$Id: file.c,v 1.27 1997/02/22 16:09:47 peter Exp $"; +#endif + +/* + * 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 "lib.h" +#include <ftpio.h> +#include <netdb.h> +#include <pwd.h> +#include <time.h> +#include <sys/wait.h> + +/* Quick check to see if a file exists */ +Boolean +fexists(char *fname) +{ + struct stat dummy; + if (!lstat(fname, &dummy)) + return TRUE; + return FALSE; +} + +/* Quick check to see if something is a directory */ +Boolean +isdir(char *fname) +{ + struct stat sb; + + if (stat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode)) + return TRUE; + else + return FALSE; +} + +/* Check to see if file is a dir, and is empty */ +Boolean +isemptydir(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; +} + +Boolean +isfile(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 and is empty. If nonexistent or not + a file, say "it's empty", otherwise return TRUE if zero sized. */ +Boolean +isemptyfile(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 URL specification */ +Boolean +isURL(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 + * working. + */ + if (!fname) + return FALSE; + while (isspace(*fname)) + ++fname; + if (!strncmp(fname, "ftp://", 6)) + return TRUE; + return FALSE; +} + +/* Returns the host part of a URL */ +char * +fileURLHost(char *fname, char *where, int max) +{ + char *ret; + + while (isspace(*fname)) + ++fname; + /* Don't ever call this on a bad URL! */ + fname += strlen("ftp://"); + /* Do we have a place to stick our work? */ + if ((ret = where) != NULL) { + while (*fname && *fname != '/' && max--) + *where++ = *fname++; + *where = '\0'; + return ret; + } + /* If not, they must really want us to stomp the original string */ + ret = fname; + while (*fname && *fname != '/') + ++fname; + *fname = '\0'; + return ret; +} + +/* Returns the filename part of a URL */ +char * +fileURLFilename(char *fname, char *where, int max) +{ + char *ret; + + while (isspace(*fname)) + ++fname; + /* Don't ever call this on a bad URL! */ + fname += strlen("ftp://"); + /* Do we have a place to stick our work? */ + if ((ret = where) != NULL) { + while (*fname && *fname != '/') + ++fname; + if (*fname == '/') { + while (*fname && max--) + *where++ = *fname++; + } + *where = '\0'; + return ret; + } + /* If not, they must really want us to stomp the original string */ + while (*fname && *fname != '/') + ++fname; + return fname; +} + +#define HOSTNAME_MAX 64 +/* + * Try and fetch a file by URL, returning the directory name for where + * it's unpacked, if successful. + */ +char * +fileGetURL(char *base, char *spec) +{ + char host[HOSTNAME_MAX], file[FILENAME_MAX]; + char pword[HOSTNAME_MAX + 40], *uname, *cp, *rp; + char fname[FILENAME_MAX]; + char pen[FILENAME_MAX]; + struct passwd *pw; + FILE *ftp; + pid_t tpid; + int i, status; + char *hint; + + 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, ".tgz"); + } + 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); + } + } + else + strcpy(fname, spec); + cp = fileURLHost(fname, host, HOSTNAME_MAX); + if (!*cp) { + whinge("URL `%s' has bad host part!", fname); + return NULL; + } + + cp = fileURLFilename(fname, file, FILENAME_MAX); + if (!*cp) { + whinge("URL `%s' has bad filename part!", fname); + return NULL; + } + + /* Maybe change to ftp if this doesn't work */ + uname = "anonymous"; + + /* Make up a convincing "password" */ + pw = getpwuid(getuid()); + if (!pw) { + whinge("Can't get user name for ID %d\n.", getuid()); + strcpy(pword, "joe@"); + } + else { + char me[HOSTNAME_MAX]; + + gethostname(me, HOSTNAME_MAX); + snprintf(pword, HOSTNAME_MAX + 40, "%s@%s", pw->pw_name, me); + } + if (Verbose) + printf("Trying to fetch %s.\n", fname); + ftp = ftpGetURL(fname, uname, pword, &status); + if (ftp) { + pen[0] = '\0'; + if ((rp = make_playpen(pen, 0)) != NULL) { + if (Verbose) + printf("Extracting from FTP connection into %s\n", pen); + tpid = fork(); + if (!tpid) { + dup2(fileno(ftp), 0); + i = execl("/usr/bin/tar", "tar", Verbose ? "-xzvf" : "-xzf", "-", 0); + exit(i); + } + else { + int pstat; + + fclose(ftp); + tpid = waitpid(tpid, &pstat, 0); + if (Verbose) + printf("tar command returns %d status\n", WEXITSTATUS(pstat)); + } + } + else + printf("Error: Unable to construct a new playpen for FTP!\n"); + fclose(ftp); + } + else + printf("Error: FTP Unable to get %s: %s\n", + fname, + status ? ftpErrString(status) : hstrerror(h_errno)); + return rp; +} + +char * +fileFindByPath(char *base, char *fname) +{ + static char tmp[FILENAME_MAX]; + char *cp; + + if (fexists(fname) && isfile(fname)) { + strcpy(tmp, fname); + return tmp; + } + if (base) { + strcpy(tmp, base); + + cp = strrchr(fname, '/'); + if (cp) { + *cp = '\0'; /* chop name */ + cp = strrchr(fname, '/'); + } + if (cp) { + *(cp + 1) = '\0'; + strcat(cp, "All/"); + strcat(cp, fname); + if (fexists(tmp)) + return tmp; + } + } + + cp = getenv("PKG_PATH"); + while (cp) { + char *cp2 = strsep(&cp, ":"); + + snprintf(tmp, FILENAME_MAX, "%s/%s.tgz", cp2 ? cp2 : cp, fname); + if (fexists(tmp) && isfile(tmp)) + return tmp; + } + return NULL; +} + +char * +fileGetContents(char *fname) +{ + char *contents; + struct stat sb; + int fd; + + if (stat(fname, &sb) == FAIL) + barf("Can't stat '%s'.", fname); + + contents = (char *)malloc(sb.st_size + 1); + fd = open(fname, O_RDONLY, 0); + if (fd == FAIL) + barf("Unable to open '%s' for reading.", fname); + if (read(fd, contents, sb.st_size) != sb.st_size) + barf("Short read on '%s' - did not get %qd bytes.", fname, 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, char *name, 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(char *name, char *str) +{ + FILE *fp; + int len; + + fp = fopen(name, "w"); + if (!fp) + barf("Cannot fopen '%s' for writing.", name); + len = strlen(str); + if (fwrite(str, 1, len, fp) != len) + barf("Short fwrite on '%s', tried to write %d bytes.", name, len); + if (fclose(fp)) + barf("failure to fclose '%s'.", name); +} + +void +copy_file(char *dir, char *fname, char *to) +{ + char cmd[FILENAME_MAX]; + + if (fname[0] == '/') + snprintf(cmd, FILENAME_MAX, "cp -p -r %s %s", fname, to); + else + snprintf(cmd, FILENAME_MAX, "cp -p -r %s/%s %s", dir, fname, to); + if (vsystem(cmd)) + barf("Could not perform '%s'", cmd); +} + +void +move_file(char *dir, char *fname, char *to) +{ + char cmd[FILENAME_MAX]; + + if (fname[0] == '/') + snprintf(cmd, FILENAME_MAX, "mv %s %s", fname, to); + else + snprintf(cmd, FILENAME_MAX, "mv %s/%s %s", dir, fname, to); + if (vsystem(cmd)) + barf("Could not perform '%s'", cmd); +} + +/* + * Copy a hierarchy (possibly from dir) to the current directory, or + * if "to" is TRUE, from the current directory to a location someplace + * else. + * + * Though slower, using tar to copy preserves symlinks and everything + * without me having to write some big hairy routine to do it. + */ +void +copy_hierarchy(char *dir, char *fname, Boolean to) +{ + char cmd[FILENAME_MAX * 3]; + + if (!to) { + /* If absolute path, use it */ + if (*fname == '/') + dir = "/"; + snprintf(cmd, FILENAME_MAX * 3, "tar cf - -C %s %s | tar xpf -", + dir, fname); + } + else + snprintf(cmd, FILENAME_MAX * 3, "tar cf - %s | tar xpf - -C %s", + fname, dir); +#ifdef DEBUG + printf("Using '%s' to copy trees.\n", cmd); +#endif + if (system(cmd)) + barf("copy_file: Could not perform '%s'", cmd); +} + +/* Unpack a tar file */ +int +unpack(char *pkg, char *flist) +{ + char args[10], suffix[80], *cp; + + args[0] = '\0'; + /* + * Figure out by a crude heuristic whether this or not this is probably + * compressed. + */ + if (strcmp(pkg, "-")) { + cp = rindex(pkg, '.'); + if (cp) { + strcpy(suffix, cp + 1); + if (index(suffix, 'z') || index(suffix, 'Z')) + strcpy(args, "-z"); + } + } + else + strcpy(args, "z"); + strcat(args, "xpf"); + if (vsystem("tar %s %s %s", args, pkg, flist ? flist : "")) { + whinge("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, char *fmt, char *dir, char *name) +{ + char *cp, scratch[FILENAME_MAX * 2]; + + while (*fmt) { + if (*fmt == '%') { + switch (*++fmt) { + case 'F': + strcpy(buf, name); + buf += strlen(name); + break; + + case 'D': + strcpy(buf, dir); + buf += strlen(dir); + break; + + case 'B': + sprintf(scratch, "%s/%s", dir, name); + cp = &scratch[strlen(scratch) - 1]; + while (cp != scratch && *cp != '/') + --cp; + *cp = '\0'; + strcpy(buf, scratch); + buf += strlen(scratch); + break; + + case 'f': + sprintf(scratch, "%s/%s", dir, name); + cp = &scratch[strlen(scratch) - 1]; + while (cp != scratch && *(cp - 1) != '/') + --cp; + strcpy(buf, cp); + buf += strlen(cp); + break; + + default: + *buf++ = *fmt; + break; + } + ++fmt; + } + else + *buf++ = *fmt++; + } + *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 0000000..3b00c81 --- /dev/null +++ b/usr.sbin/pkg_install/lib/global.c @@ -0,0 +1,34 @@ +#ifndef lint +static const char *rcsid = "$Id$"; +#endif + +/* + * 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 "lib.h" + +/* These are global for all utils */ +Boolean Verbose = FALSE; +Boolean Fake = FALSE; +Boolean Force = FALSE; +int AutoAnswer = FALSE; + + diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h new file mode 100644 index 0000000..5fda891 --- /dev/null +++ b/usr.sbin/pkg_install/lib/lib.h @@ -0,0 +1,177 @@ +/* $Id$ */ + +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/file.h> + +/* Macros */ +#define SUCCESS (0) +#define FAIL (-1) + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#define YES 2 +#define NO 1 + +/* Usually "rm", but often "echo" during debugging! */ +#define REMOVE_CMD "rm" + +/* Usually "rm", but often "echo" during debugging! */ +#define RMDIR_CMD "rmdir" + +/* Where we put logging information by default, else ${PKG_DBDIR} if set */ +#define DEF_LOG_DIR "/var/db/pkg" +/* just in case we change the environment variable name */ +#define PKG_DBDIR "PKG_DBDIR" + +/* The names of our "special" files */ +#define CONTENTS_FNAME "+CONTENTS" +#define COMMENT_FNAME "+COMMENT" +#define DESC_FNAME "+DESC" +#define INSTALL_FNAME "+INSTALL" +#define DEINSTALL_FNAME "+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" + +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_MTREE, PLIST_DIR_RM, PLIST_IGNORE_INST, + PLIST_OPTION +}; +typedef enum _plist_t plist_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; +}; +typedef struct _pack Package; + +/* Prototypes */ +/* Misc */ +int vsystem(const char *, ...); +void cleanup(int); +char *make_playpen(char *, size_t); +char *where_playpen(void); +void leave_playpen(char *); +off_t min_free(char *); + +/* String */ +char *get_dash_string(char **); +char *copy_string(char *); +Boolean suffix(char *, char *); +void nuke_suffix(char *); +void str_lowercase(char *); +char *basename_of(char *); +char *strconcat(char *, char *); + +/* File */ +Boolean fexists(char *); +Boolean isdir(char *); +Boolean isemptydir(char *fname); +Boolean isemptyfile(char *fname); +Boolean isfile(char *); +Boolean isempty(char *); +Boolean isURL(char *); +char *fileGetURL(char *, char *); +char *fileURLFilename(char *, char *, int); +char *fileURLHost(char *, char *, int); +char *fileFindByPath(char *, char *); +char *fileGetContents(char *); +void write_file(char *, char *); +void copy_file(char *, char *, char *); +void move_file(char *, char *, char *); +void copy_hierarchy(char *, char *, Boolean); +int delete_hierarchy(char *, Boolean, Boolean); +int unpack(char *, char *); +void format_cmd(char *, char *, char *, 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 *, char *name); +void plist_delete(Package *, Boolean, plist_t, char *); +void free_plist(Package *); +void mark_plist(Package *); +void csum_plist_entry(char *, PackingList); +void add_plist(Package *, plist_t, char *); +void add_plist_top(Package *, plist_t, char *); +void delete_plist(Package *pkg, Boolean all, plist_t type, char *name); +void write_plist(Package *, FILE *); +void read_plist(Package *, FILE *); +int plist_cmd(char *, char **); +int delete_package(Boolean, Boolean, Package *); + +/* For all */ +void usage(const char *, const char *, ...); +int pkg_perform(char **); + +/* Externs */ +extern Boolean Verbose; +extern Boolean Fake; +extern Boolean Force; +extern int AutoAnswer; + +#endif /* _INST_LIB_LIB_H_ */ diff --git a/usr.sbin/pkg_install/lib/msg.c b/usr.sbin/pkg_install/lib/msg.c new file mode 100644 index 0000000..e35aba8 --- /dev/null +++ b/usr.sbin/pkg_install/lib/msg.c @@ -0,0 +1,101 @@ +#ifndef lint +static const char *rcsid = "$Id$"; +#endif + +/* + * 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 "lib.h" + +/* Die a relatively simple death */ +void +upchuck(const char *err) +{ + fprintf(stderr, "Fatal error during execution: "); + perror(err); + cleanup(0); + exit(1); +} + +/* Die a more complex death */ +void +barf(const char *err, ...) +{ + va_list args; + + va_start(args, err); + vfprintf(stderr, err, args); + fputc('\n', stderr); + va_end(args); + cleanup(0); + exit(2); +} + +/* Get annoyed about something but don't go to pieces over it */ +void +whinge(const char *err, ...) +{ + va_list args; + + va_start(args, err); + vfprintf(stderr, err, args); + fputc('\n', stderr); + va_end(args); +} + +/* + * 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("/dev/tty", "r"); + if (!tty) + barf("Can't open /dev/tty!\n"); + 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 0000000..4b636de --- /dev/null +++ b/usr.sbin/pkg_install/lib/pen.c @@ -0,0 +1,141 @@ +#ifndef lint +static const char *rcsid = "$Id$"; +#endif + +/* + * 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 "lib.h" +#include <sys/signal.h> +#include <sys/param.h> +#include <sys/mount.h> + +/* For keeping track of where we are */ +static char Current[FILENAME_MAX]; +static char Previous[FILENAME_MAX]; + +char * +where_playpen(void) +{ + return Current; +} + +/* Find a good place to play. */ +static char * +find_play_pen(char *pen, size_t sz) +{ + char *cp; + struct stat sb; + + if (pen[0] && stat(pen, &sb) != FAIL && (min_free(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 { + barf("Can't find enough temporary space to extract the files, please set\n" + "your PKG_TMPDIR environment variable to a location with at least %d bytes\n" + "free.", sz); + return NULL; + } + return pen; +} + +/* + * Make a temporary directory to play in and chdir() to it, returning + * pathname of previous working directory. + */ +char * +make_playpen(char *pen, size_t sz) +{ + if (!find_play_pen(pen, sz)) + return NULL; + + if (!mktemp(pen)) { + barf("Can't mktemp '%s'.", pen); + return NULL; + } + if (mkdir(pen, 0755) == FAIL) { + barf("Can't mkdir '%s'.", pen); + return NULL; + } + if (Verbose) { + if (sz) + fprintf(stderr, "Requested space: %d bytes, free space: %qd bytes in %s\n", (int)sz, min_free(pen), pen); + } + if (min_free(pen) < sz) { + rmdir(pen); + barf("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.", pen); + return NULL; + } + if (Current[0]) + strcpy(Previous, Current); + else if (!getcwd(Previous, FILENAME_MAX)) { + upchuck("getcwd"); + return NULL; + } + if (chdir(pen) == FAIL) + barf("Can't chdir to '%s'.", pen); + strcpy(Current, pen); + return Previous; +} + +/* Convenience routine for getting out of playpen */ +void +leave_playpen(char *save) +{ + void (*oldsig)(int); + + /* Don't interrupt while we're cleaning up */ + oldsig = signal(SIGINT, SIG_IGN); + if (Previous[0] && chdir(Previous) == FAIL) + barf("Can't chdir back to '%s'.", Previous); + else if (Current[0] && strcmp(Current, Previous)) { + if (vsystem("rm -rf %s", Current)) + whinge("Couldn't remove temporary dir '%s'", Current); + strcpy(Current, Previous); + } + if (save) + strcpy(Previous, save); + else + Previous[0] = '\0'; + signal(SIGINT, oldsig); +} + +off_t +min_free(char *tmpdir) +{ + struct statfs buf; + + if (statfs(tmpdir, &buf) != 0) { + perror("Error in statfs"); + return -1; + } + return (off_t)buf.f_bavail * (off_t)buf.f_bsize; +} diff --git a/usr.sbin/pkg_install/lib/plist.c b/usr.sbin/pkg_install/lib/plist.c new file mode 100644 index 0000000..58907b3 --- /dev/null +++ b/usr.sbin/pkg_install/lib/plist.c @@ -0,0 +1,503 @@ +#ifndef lint +static const char *rcsid = "$Id: plist.c,v 1.21 1997/06/30 03:15:40 jkh Exp $"; +#endif + +/* + * 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 "lib.h" +#include <errno.h> +#include <md5.h> + +/* Add an item to a packing list */ +void +add_plist(Package *p, plist_t type, 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; + } +} + +void +add_plist_top(Package *p, plist_t type, 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, 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, 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(char *s, char **arg) +{ + char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */ + char *cp, *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 = 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, "comment")) + 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, "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; + + 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_cmd(pline + 1, &cp); + if (cmd == FAIL) + barf("Bad command '%s'", pline); + if (*cp == '\0') + cp = NULL; + } + else + cmd = PLIST_FILE; + 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); + 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_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_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; + + default: + barf("Unknown command type %d (%s)\n", 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; + char *Where = ".", *last_file = ""; + Boolean fail = SUCCESS; + Boolean preserve; + char tmp[FILENAME_MAX], *name = 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: + Where = p->name; + if (Verbose) + printf("Change working directory to %s\n", Where); + break; + + case PLIST_UNEXEC: + format_cmd(tmp, p->name, Where, last_file); + if (Verbose) + printf("Execute `%s'\n", tmp); + if (!Fake && system(tmp)) { + whinge("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)) { + whinge("Attempting to delete directory `%s' as a file\n" + "This packing list is incorrect - ignoring delete request.\n", tmp); + } + else { + if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) { + char *cp, buf[33]; + + if ((cp = MD5File(tmp, buf)) != NULL) { + /* Mismatch? */ + if (strcmp(cp, p->next->name + 4)) { + if (Verbose) + printf("%s fails original MD5 checksum - %s\n", + 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)) { + whinge("Unable to completely remove file '%s'", tmp); + 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)) + whinge("preserve: Unable to restore %s as %s, errno = %d", tmp2, tmp, errno); + } + } + } + } + } + break; + + case PLIST_DIR_RM: + sprintf(tmp, "%s/%s", Where, p->name); + if (!isdir(tmp)) { + whinge("Attempting to delete file `%s' as a directory\n" + "This packing list is incorrect - ignoring delete request.\n", tmp); + } + else { + if (Verbose) + printf("Delete directory %s\n", tmp); + if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) { + whinge("Unable to completely remove directory '%s'", tmp); + fail = FAIL; + } + } + last_file = p->name; + 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(char *dir, Boolean ign_err, Boolean nukedirs) +{ + char *cp1, *cp2; + + cp1 = cp2 = dir; + if (!fexists(dir)) { + if (!ign_err) + whinge("%s `%s' doesn't really 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)) { + if (RMDIR(dir) && !ign_err) + return 1; + } + else { + if (REMOVE(dir, ign_err)) + return 1; + } + + if (!nukedirs) + return 0; + while (cp2) { + if ((cp2 = rindex(cp1, '/')) != NULL) + *cp2 = '\0'; + if (!isemptydir(dir)) + return 0; + if (RMDIR(dir) && !ign_err) + if (!fexists(dir)) + whinge("Directory `%s' doesn't really exist.", dir); + else + return 1; + /* back up the pathname one component */ + if (cp2) { + cp1 = 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 0000000..a9f1300 --- /dev/null +++ b/usr.sbin/pkg_install/lib/str.c @@ -0,0 +1,110 @@ +#ifndef lint +static const char *rcsid = "$Id"; +#endif + +/* + * 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 "lib.h" + +/* Return the filename portion of a path */ +char * +basename_of(char *str) +{ + char *basename = str + strlen(str) - 1; + + while (basename != str && basename[-1] != '/') + --basename; + return basename; +} + +char * +strconcat(char *s1, char *s2) +{ + static char tmp[FILENAME_MAX]; + + tmp[0] = '\0'; + strncpy(tmp, s1 ? s1 : s2, FILENAME_MAX); + 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(s + 1); + else + *str = fileGetContents(s); + return *str; +} + +/* Rather Obvious */ +char * +copy_string(char *str) +{ + char *ret; + + if (!str) + ret = NULL; + else { + ret = (char *)malloc(strlen(str) + 1); + strcpy(ret, str); + } + return ret; +} + +/* Return TRUE if 'str' ends in suffix 'suff' */ +Boolean +suffix(char *str, char *suff) +{ + char *idx; + Boolean ret = FALSE; + + idx = rindex(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 = rindex(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; + } +} |