diff options
Diffstat (limited to 'usr.sbin/pkg_install/lib')
-rw-r--r-- | usr.sbin/pkg_install/lib/Makefile | 11 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/exec.c | 61 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/file.c | 516 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/ftp.c | 424 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/ftp.h | 27 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/global.c | 34 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/lib.h | 173 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/msg.c | 102 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/pen.c | 144 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/plist.c | 448 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/str.c | 111 |
11 files changed, 2051 insertions, 0 deletions
diff --git a/usr.sbin/pkg_install/lib/Makefile b/usr.sbin/pkg_install/lib/Makefile new file mode 100644 index 00000000000..ff1e3e686e9 --- /dev/null +++ b/usr.sbin/pkg_install/lib/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 1996/06/04 07:56:11 niklas Exp $ +LIB= install +SRCS= file.c ftp.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 00000000000..6f10c3ce944 --- /dev/null +++ b/usr.sbin/pkg_install/lib/exec.c @@ -0,0 +1,61 @@ +# $OpenBSD: exec.c,v 1.1 1996/06/04 07:56:11 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD: exec.c,v 1.1 1996/06/04 07:56:11 niklas 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 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 00000000000..d37af1e8a07 --- /dev/null +++ b/usr.sbin/pkg_install/lib/file.c @@ -0,0 +1,516 @@ +# $OpenBSD: file.c,v 1.1 1996/06/04 07:56:11 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD: file.c,v 1.1 1996/06/04 07:56:11 niklas 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 "ftp.h" +#include <pwd.h> +#include <time.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) { + 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) { + 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], dir[FILENAME_MAX]; + char pword[HOSTNAME_MAX + 40], *uname, *cp, *rp, *tmp; + char fname[FILENAME_MAX]; + char pen[FILENAME_MAX]; + struct passwd *pw; + FTP_t ftp; + pid_t tpid; + int fd, fd2, i, len = 0; + char ch; + time_t start, stop; + char *hint; + + rp = NULL; + /* Special tip that sysinstall left for us */ + hint = getenv("PKG_ADD_BASE"); + if (!isURL(spec)) { + int len; + + 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); + } + 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); + ftp = FtpInit(); + 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 + snprintf(pword, HOSTNAME_MAX + 40, "%s@%s", pw->pw_name, host); + + if (Verbose) + printf("Trying to log into %s as %s.\n", host, uname); + FtpOpen(ftp, host, uname, pword); + if (getenv("FTP_PASSIVE_MODE")) + FtpPassive(ftp, TRUE); + + strcpy(dir, file); + for (i = strlen(dir); i && dir[i] != '/'; i--); + dir[i] = '\0'; + + if (dir[0]) { + if (Verbose) printf("FTP: chdir to %s\n", dir); + FtpChdir(ftp, dir); + } + FtpBinary(ftp, TRUE); + if (Verbose) printf("FTP: trying to get %s\n", basename_of(file)); + tmp = basename_of(file); + if (!strstr(tmp, ".tgz")) + tmp = strconcat(tmp, ".tgz"); + fd = FtpGet(ftp, tmp); + if (fd >= 0) { + pen[0] = '\0'; + if (rp = make_playpen(pen, 0)) { + if (Verbose) + printf("Extracting from FTP connection into %s\n", pen); + tpid = fork(); + if (!tpid) { + dup2(fd, 0); + i = execl("/usr/bin/tar", "tar", Verbose ? "-xzvf" : "-xzf", "-", 0); + if (Verbose) + printf("tar command returns %d status\n", i); + exit(i); + } + else { + int pstat; + + close(fd); + tpid = waitpid(tpid, &pstat, 0); + } + } + else + printf("Error: Unable to construct a new playpen for FTP!\n"); + } + else + printf("Error: FTP Unable to get %s\n", basename_of(file)); + FtpEOF(ftp); + FtpClose(ftp); + 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; +} + +/* 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("Can't 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("Couldn't 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("Couldn't 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: Couldn't 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/ftp.c b/usr.sbin/pkg_install/lib/ftp.c new file mode 100644 index 00000000000..ac507b6d6bd --- /dev/null +++ b/usr.sbin/pkg_install/lib/ftp.c @@ -0,0 +1,424 @@ + * $OpenBSD: ftp.c,v 1.1 1996/06/04 07:56:12 niklas Exp $ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * + * Return values have been sanitized: + * -1 error, but you (still) have a session. + * -2 error, your session is dead. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <netdb.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include "ftp.h" +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* Handy global for us to stick the port # */ +int FtpPort; + +static void +debug(FTP_t ftp, const char *fmt, ...) +{ + char p[BUFSIZ]; + va_list ap; + va_start(ap, fmt); + strcpy(p,"LIBFTP: "); + (void) vsnprintf(p+strlen(p), sizeof p - strlen(p), fmt, ap); + va_end(ap); + write(ftp->fd_debug,p,strlen(p)); +} + +static int +writes(int fd, char *s) +{ + int i = strlen(s); + if (i != write(fd,s,i)) + return -2; + return 0; +} + +static __inline char* +get_a_line(FTP_t ftp) +{ + static char buf[BUFSIZ]; + int i,j; + + for(i=0;i<BUFSIZ;) { + j = read(ftp->fd_ctrl,buf+i,1); + if (j != 1) + return 0; + if (buf[i] == '\r' || buf[i] == '\n') { + if (!i) + continue; + buf[i] = '\0'; + debug(ftp, "received <%s>\n",buf); + return buf; + } + i++; + } + return buf; +} + +static int +get_a_number(FTP_t ftp, char **q) +{ + char *p; + int i = -1,j; + + while(1) { + p = get_a_line(ftp); + if (!p) + return -2; + if (!(isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2]))) + continue; + if (i == -1 && p[3] == '-') { + i = strtol(p, 0, 0); + continue; + } + if (p[3] != ' ' && p[3] != '\t') + continue; + j = strtol(p, 0, 0); + if (i == -1) { + if (q) *q = p+4; + return j; + } else if (j == i) { + if (q) *q = p+4; + return j; + } + } +} + +static int +zap(FTP_t ftp) +{ + int i; + + i = writes(ftp->fd_ctrl,"QUIT\r\n"); + debug(ftp, "Zapping ftp connection on %d returns %d\n", ftp->fd_ctrl, i); + close(ftp->fd_ctrl); ftp->fd_ctrl = -1; + close(ftp->fd_xfer); ftp->fd_xfer = -1; + ftp->state = init; + return -2; +} + +static int +botch(FTP_t ftp, char *func, char *state) +{ + debug(ftp, "Botch: %s called outside state %s\n",func,state); + return -2; +} + +static int +cmd(FTP_t ftp, const char *fmt, ...) +{ + char p[BUFSIZ]; + int i; + + va_list ap; + va_start(ap, fmt); + (void) vsnprintf(p, sizeof p, fmt, ap); + va_end(ap); + + debug(ftp, "send <%s>\n",p); + strcat(p,"\r\n"); + if (writes(ftp->fd_ctrl,p)) + return -2; + i = get_a_number(ftp,0); + return i; +} + +FTP_t +FtpInit() +{ + FTP_t ftp; + + ftp = malloc(sizeof *ftp); + if (!ftp) + return ftp; + memset(ftp, 0, sizeof *ftp); + ftp->fd_ctrl = -1; + ftp->fd_xfer = -1; + ftp->fd_debug = -1; + ftp->state = init; + return ftp; +} + +void +FtpDebug(FTP_t ftp, int i) +{ + ftp->fd_debug = i; +} + +int +FtpOpen(FTP_t ftp, char *host, char *user, char *passwd) +{ + struct hostent *he = NULL; + struct sockaddr_in sin; + int s; + unsigned long temp; + int i; + + if (ftp->state != init) + return botch(ftp,"FtpOpen","init"); + + if (!user) + user = "ftp"; + + if (!passwd) + passwd = "??@??(FreeBSD:libftp)"; /* XXX */ + + debug(ftp, "FtpOpen(ftp, %s, %s, %s)\n", host, user, passwd); + + temp = inet_addr(host); + if (temp != INADDR_NONE) { + debug(ftp, "Using dotted IP address `%s'\n", host); + ftp->addrtype = sin.sin_family = AF_INET; + sin.sin_addr.s_addr = temp; + } + else { + debug(ftp, "Trying to resolve `%s'\n", host); + he = gethostbyname(host); + if (!he) { + debug(ftp, "Lookup of `%s' failed!\n", host); + return zap(ftp); + } + ftp->addrtype = sin.sin_family = he->h_addrtype; + bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); + } + + sin.sin_port = htons(FtpPort ? FtpPort : 21); + + if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) + { + debug(ftp, "Socket open failed: %s (%i)\n", strerror(errno), errno); + return zap(ftp); + } + + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + debug(ftp,"Connection failed: %s (%i)\n", strerror(errno), errno); + (void)close(s); + return zap(ftp); + } + + ftp->fd_ctrl = s; + + debug(ftp, "open (%d)\n",get_a_number(ftp,0)); + + i = cmd(ftp,"USER %s",user); + if (i >= 300 && i < 400) + i = cmd(ftp,"PASS %s",passwd); + if (i >= 299 || i < 0) { + close(ftp->fd_ctrl); ftp->fd_ctrl = -1; + return zap(ftp); + } + ftp->state = isopen; + return 0; +} + +void +FtpClose(FTP_t ftp) +{ + if (ftp->state != init) + return; + + if (ftp->state != isopen) + botch(ftp,"FtpClose","open or init"); + + debug(ftp, "FtpClose(ftp)\n"); + zap(ftp); +} + +int +FtpChdir(FTP_t ftp, char *dir) +{ + int i; + if (ftp->state != isopen) + return botch(ftp,"FtpChdir","open"); + i = cmd(ftp,"CWD %s",dir); + if (i < 0) + return i; + else if (i != 250) + return -1; + return 0; +} + +int +FtpGet(FTP_t ftp, char *file) +{ + int i,s; + char *q; + unsigned char addr[64]; + struct sockaddr_in sin; + u_long a; + + debug(ftp, "FtpGet(ftp,%s)\n",file); + if (ftp->state != isopen) + return botch(ftp,"FtpGet","open"); + if(ftp->binary) { + i = cmd(ftp,"TYPE I"); + if (i < 0) + return zap(ftp); + if (i > 299) + return -1; + } else { + return -1; + } + + if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) + return zap(ftp); + + if (ftp->passive) { + debug(ftp, "send <%s>\n","PASV"); + if (writes(ftp->fd_ctrl,"PASV\r\n")) + return zap(ftp); + i = get_a_number(ftp,&q); + if (i < 0) + return zap(ftp); + if (i != 227) + return zap(ftp); + while (*q && !isdigit(*q)) + q++; + if (!*q) + return zap(ftp); + q--; + for(i=0;i<6;i++) { + q++; + addr[i] = strtol(q,&q,10); + } + + sin.sin_family = ftp->addrtype; + bcopy(addr, (char *)&sin.sin_addr, 4); + bcopy(addr+4, (char *)&sin.sin_port, 2); + debug(ftp, "Opening active socket to %s : %u\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + + debug(ftp, "Connecting to %s:%u\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + (void)close(s); + debug(ftp, "connect: %s (%d)\n", strerror(errno), errno); + return -1; + } + ftp->fd_xfer = s; + i = cmd(ftp,"RETR %s",file); + if (i < 0) { + close(s); + return zap(ftp); + } + else if (i > 299) { + debug(ftp, "FTP: No such file %s, moving on.\n", file); + close(s); + return -1; + } + ftp->state = xfer; + return s; + } else { + i = sizeof sin; + getsockname(ftp->fd_ctrl,(struct sockaddr *)&sin,&i); + sin.sin_port = 0; + i = sizeof sin; + if (bind(s,(struct sockaddr *)&sin, i) < 0) { + close (s); + debug(ftp,"bind failed %d\n",errno); + return zap(ftp); + } + getsockname(s,(struct sockaddr *)&sin,&i); + if (listen(s,1) < 0) { + close (s); + debug(ftp,"listen failed %d\n",errno); + return zap(ftp); + } + a = ntohl(sin.sin_addr.s_addr); + i = cmd(ftp,"PORT %d,%d,%d,%d,%d,%d", + (a >> 24) & 0xff, + (a >> 16) & 0xff, + (a >> 8) & 0xff, + a & 0xff, + (ntohs(sin.sin_port) >> 8) & 0xff, + ntohs(sin.sin_port) & 0xff); + if (i != 200) + return -1; + i = cmd(ftp,"RETR %s",file); + if (i < 0) { + close(s); + return zap(ftp); + } + else if (i > 299) { + debug(ftp, "FTP: No such file %s, moving on.\n", file); + close(s); + return -1; + } + ftp->fd_xfer = accept(s, 0, 0); + if (ftp->fd_xfer < 0) { + close(s); + return zap(ftp); + } + ftp->state = xfer; + close(s); + return(ftp->fd_xfer); + } +} + +int +FtpEOF(FTP_t ftp) +{ + int i; + + if (ftp->state != xfer) + return botch(ftp,"FtpEOF","xfer"); + debug(ftp, "FtpEOF(ftp)\n"); + close(ftp->fd_xfer); ftp->fd_xfer = -1; + ftp->state = isopen; + i = get_a_number(ftp,0); + if (i < 0) + return zap(ftp); + else if (i != 250 && i != 226) + return -1; + else + return 0; +} + +#ifdef STANDALONE_FTP + +/* main.c */ +int +main(int argc, char **argv) +{ + FTP_t ftp; + int i; + char c; + + ftp = FtpInit(); + if (!ftp) + err(1, "FtpInit()"); + + FtpDebug(ftp, 1); + i = FtpOpen(ftp, "freefall.cdrom.com", "ftp", "phk-libftp@"); + FtpBinary(ftp, 1); + FtpPassive(ftp, 0); + FtpChdir(ftp, "/pub"); + FtpChdir(ftp, "FreeBSD"); + i = FtpGet(ftp, "README"); + while (1 == read(i, &c, 1)) + putchar(c); + FtpEOF(ftp); + return 0; +} + +#endif /*STANDALONE_FTP*/ diff --git a/usr.sbin/pkg_install/lib/ftp.h b/usr.sbin/pkg_install/lib/ftp.h new file mode 100644 index 00000000000..b272d1c62de --- /dev/null +++ b/usr.sbin/pkg_install/lib/ftp.h @@ -0,0 +1,27 @@ +# $OpenBSD: ftp.h,v 1.1 1996/06/04 07:56:12 niklas Exp $ +#ifndef _FTP_H_INCLUDE +#define _FTP_H_INCLUDE + +typedef struct { + enum {init, isopen, xfer} state; + int fd_ctrl; + int fd_xfer; + int fd_debug; + int binary; + int passive; + int addrtype; + char *host; + char *file; +} *FTP_t; + +FTP_t FtpInit(); +int FtpOpen(FTP_t, char *host, char *user, char *passwd); +#define FtpBinary(ftp,bool) { (ftp)->binary = (bool); } +#define FtpPassive(ftp,bool) { (ftp)->passive = (bool); } +int FtpChdir(FTP_t, char *); +int FtpGet(FTP_t, char *); +int FtpEOF(FTP_t); +void FtpClose(FTP_t); + +#endif +/* _FTP_H_INCLUDE */ diff --git a/usr.sbin/pkg_install/lib/global.c b/usr.sbin/pkg_install/lib/global.c new file mode 100644 index 00000000000..36d1a433b7b --- /dev/null +++ b/usr.sbin/pkg_install/lib/global.c @@ -0,0 +1,34 @@ +# $OpenBSD: global.c,v 1.1 1996/06/04 07:56:12 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD: global.c,v 1.1 1996/06/04 07:56:12 niklas 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 + * + * Semi-convenient place to stick some needed globals. + * + */ + +#include "lib.h" + +/* These are global for all utils */ +Boolean Verbose = FALSE; +Boolean Fake = 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 00000000000..f09d8228033 --- /dev/null +++ b/usr.sbin/pkg_install/lib/lib.h @@ -0,0 +1,173 @@ +/* $OpenBSD: lib.h,v 1.1 1996/06/04 07:56:13 niklas Exp $ */ + +/* + * 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 *); +size_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 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 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 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 00000000000..0ee3a57dbea --- /dev/null +++ b/usr.sbin/pkg_install/lib/msg.c @@ -0,0 +1,102 @@ +# $OpenBSD: msg.c,v 1.1 1996/06/04 07:56:13 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD: msg.c,v 1.1 1996/06/04 07:56:13 niklas 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 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 00000000000..e26ad037617 --- /dev/null +++ b/usr.sbin/pkg_install/lib/pen.c @@ -0,0 +1,144 @@ +# $OpenBSD: pen.c,v 1.1 1996/06/04 07:56:13 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD: pen.c,v 1.1 1996/06/04 07:56:13 niklas 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 + * + * 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) +{ + char *tmp; + + 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: %d 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); +} + +size_t +min_free(char *tmpdir) +{ + struct statfs buf; + + if (statfs(tmpdir, &buf) != 0) { + perror("Error in statfs"); + return -1; + } + return buf.f_bavail * 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 00000000000..a24e63176d9 --- /dev/null +++ b/usr.sbin/pkg_install/lib/plist.c @@ -0,0 +1,448 @@ +# $OpenBSD: plist.c,v 1.1 1996/06/04 07:56:14 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD: plist.c,v 1.1 1996/06/04 07:56:14 niklas 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" + +/* 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) - 1; + + while (isspace(pline[len])) + pline[len--] = '\0'; + if (len <= 0) + 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 = pkg->head; + char *Where = ".", *last_file = ""; + Boolean fail = SUCCESS; + + if (!p) + return FAIL; + while (p) { + if (p->type == PLIST_CWD) { + Where = p->name; + if (Verbose) + printf("Change working directory to %s\n", Where); + } + else if (p->type == PLIST_UNEXEC) { + char cmd[FILENAME_MAX]; + + format_cmd(cmd, p->name, Where, last_file); + if (Verbose) + printf("Execute `%s'\n", cmd); + if (!Fake && system(cmd)) { + whinge("unexec command for `%s' failed.", cmd); + fail = FAIL; + } + } + else if (p->type == PLIST_IGNORE) + p = p->next; + else if (p->type == PLIST_FILE || p->type == PLIST_DIR_RM) { + char full_name[FILENAME_MAX]; + + sprintf(full_name, "%s/%s", Where, p->name); + if (isdir(full_name) && p->type == PLIST_FILE) { + warn("Attempting to delete directory `%s' as a file\n" + "This packing list is incorrect - ignoring delete request.\n", full_name); + } + else { + if (Verbose) + printf("Delete %s %s\n", !isdir(full_name) ? "file" : " directory", full_name); + + if (!Fake && delete_hierarchy(full_name, ign_err, p->type == PLIST_DIR_RM ? FALSE : nukedirs)) { + whinge("Unable to completely remove file '%s'", full_name); + fail = FAIL; + } + } + last_file = p->name; + } + p = p->next; + } + 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); + } 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 00000000000..1d8ec1c5c99 --- /dev/null +++ b/usr.sbin/pkg_install/lib/str.c @@ -0,0 +1,111 @@ +# $OpenBSD: str.c,v 1.1 1996/06/04 07:56:14 niklas Exp $ +#ifndef lint +static const char *rcsid = "$OpenBSD"; +#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; + } +} |