summaryrefslogtreecommitdiff
path: root/usr.sbin/pkg_install/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pkg_install/lib')
-rw-r--r--usr.sbin/pkg_install/lib/Makefile11
-rw-r--r--usr.sbin/pkg_install/lib/exec.c61
-rw-r--r--usr.sbin/pkg_install/lib/file.c516
-rw-r--r--usr.sbin/pkg_install/lib/ftp.c424
-rw-r--r--usr.sbin/pkg_install/lib/ftp.h27
-rw-r--r--usr.sbin/pkg_install/lib/global.c34
-rw-r--r--usr.sbin/pkg_install/lib/lib.h173
-rw-r--r--usr.sbin/pkg_install/lib/msg.c102
-rw-r--r--usr.sbin/pkg_install/lib/pen.c144
-rw-r--r--usr.sbin/pkg_install/lib/plist.c448
-rw-r--r--usr.sbin/pkg_install/lib/str.c111
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;
+ }
+}