summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pkg_install/create/pl.c
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1994-12-06 00:51:50 +0000
committerjkh <jkh@FreeBSD.org>1994-12-06 00:51:50 +0000
commit773a5f451d951042f1a9541533ee9b5c97430c39 (patch)
tree769d2ca49d84039a97bd74c4ce202b318da0828a /usr.sbin/pkg_install/create/pl.c
parentf9dc382f6c8f8900550f2f35436613d329df120d (diff)
downloadFreeBSD-src-773a5f451d951042f1a9541533ee9b5c97430c39.zip
FreeBSD-src-773a5f451d951042f1a9541533ee9b5c97430c39.tar.gz
Many of John T. Kohl's patches from NetBSD. Thanks, John!
Submitted by: jkohl
Diffstat (limited to 'usr.sbin/pkg_install/create/pl.c')
-rw-r--r--usr.sbin/pkg_install/create/pl.c133
1 files changed, 127 insertions, 6 deletions
diff --git a/usr.sbin/pkg_install/create/pl.c b/usr.sbin/pkg_install/create/pl.c
index 0d87779..f50bd8f 100644
--- a/usr.sbin/pkg_install/create/pl.c
+++ b/usr.sbin/pkg_install/create/pl.c
@@ -1,5 +1,5 @@
#ifndef lint
-static const char *rcsid = "$Id: pl.c,v 1.4 1994/08/29 16:31:38 adam Exp $";
+static const char *rcsid = "$Id: pl.c,v 1.5 1994/11/17 10:35:04 jkh Exp $";
#endif
/*
@@ -24,6 +24,7 @@ static const char *rcsid = "$Id: pl.c,v 1.4 1994/08/29 16:31:38 adam Exp $";
#include "lib.h"
#include "create.h"
+#include <errno.h>
/* Check a list for files that require preconversion */
void
@@ -59,6 +60,35 @@ check_list(char *home, Package *pkg)
}
}
+static int
+trylink(const char *from, const char *to)
+{
+ if (link(from, to) == 0)
+ return 0;
+ if (errno == ENOENT) {
+ /* try making the container directory */
+ char *cp = strrchr(to, '/');
+ if (cp)
+ vsystem("mkdir -p %.*s", cp - to,
+ to);
+ return link(from, to);
+ }
+ return -1;
+}
+
+#define STARTSTRING "tar cf -"
+#define TOOBIG(str) strlen(str) + 6 + strlen(home) + where_count > maxargs
+#define PUSHOUT() /* push out string */ \
+ if (where_count > sizeof(STARTSTRING)-1) { \
+ strcat(where_args, "|tar xpf -"); \
+ if (system(where_args)) \
+ barf("can't invoke tar pipeline"); \
+ memset(where_args, 0, maxargs); \
+ last_chdir = NULL; \
+ strcpy(where_args, STARTSTRING); \
+ where_count = sizeof(STARTSTRING)-1; \
+ }
+
/*
* Copy unmarked files in packing list to playpen - marked files
* have already been copied in an earlier pass through the list.
@@ -68,7 +98,30 @@ copy_plist(char *home, Package *plist)
{
PackingList p = plist->head;
char *where = home;
- char *there = NULL;
+ char *there = NULL, *mythere;
+ char *where_args, *last_chdir, *root = "/";
+ int maxargs, where_count = 0, add_count;
+ struct stat stb;
+ dev_t curdir;
+
+ maxargs = sysconf(_SC_ARG_MAX);
+ maxargs -= 64; /* some slop for the tar cmd text,
+ and sh -c */
+ where_args = malloc(maxargs);
+ if (!where_args)
+ barf("can't get argument list space");
+
+ memset(where_args, 0, maxargs);
+ strcpy(where_args, STARTSTRING);
+ where_count = sizeof(STARTSTRING)-1;
+ last_chdir = 0;
+
+ if (stat(".", &stb) == 0)
+ curdir = stb.st_dev;
+ else
+ curdir = (dev_t) -1; /* It's ok if this is a valid dev_t;
+ this is just a hint for an
+ optimization. */
while (p) {
if (p->type == PLIST_CWD)
@@ -80,16 +133,84 @@ copy_plist(char *home, Package *plist)
else if (p->type == PLIST_FILE && !p->marked) {
char fn[FILENAME_MAX];
+
/* First, look for it in the "home" dir */
sprintf(fn, "%s/%s", home, p->name);
- if (fexists(fn))
- copy_hierarchy(home, p->name, FALSE);
+ if (fexists(fn)) {
+ if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
+ S_ISREG(stb.st_mode)) {
+ /* if we can link it to the playpen, that avoids a copy
+ and saves time. */
+ if (p->name[0] != '/') {
+ /* don't link abspn stuff--it doesn't come from
+ local dir! */
+ if (trylink(fn, p->name) == 0) {
+ p = p->next;
+ continue;
+ }
+ }
+ }
+ if (TOOBIG(fn)) {
+ PUSHOUT();
+ }
+ if (p->name[0] == '/') {
+ add_count = snprintf(&where_args[where_count],
+ maxargs - where_count,
+ " %s %s",
+ last_chdir == root ? "" : "-C /",
+ p->name);
+ last_chdir = root;
+ } else {
+ add_count = snprintf(&where_args[where_count],
+ maxargs - where_count,
+ " %s%s %s",
+ last_chdir == home ? "" : "-C ",
+ last_chdir == home ? "" : home,
+ p->name);
+ last_chdir = home;
+ }
+ if (add_count > maxargs - where_count)
+ barf("oops, miscounted strings!");
+ where_count += add_count;
+ }
/*
* Otherwise, try along the actual extraction path..
*/
- else
- copy_hierarchy(there ? there : where, p->name, FALSE);
+ else {
+ if (p->name[0] == '/')
+ mythere = root;
+ else mythere = there;
+ sprintf(fn, "%s/%s", mythere ? mythere : where, p->name);
+ if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
+ S_ISREG(stb.st_mode)) {
+ /* if we can link it to the playpen, that avoids a copy
+ and saves time. */
+ if (trylink(fn, p->name) == 0) {
+ p = p->next;
+ continue;
+ }
+ }
+ if (TOOBIG(p->name)) {
+ PUSHOUT();
+ }
+ if (last_chdir == (mythere ? mythere : where))
+ add_count = snprintf(&where_args[where_count],
+ maxargs - where_count,
+ " %s", p->name);
+ else
+ add_count = snprintf(&where_args[where_count],
+ maxargs - where_count,
+ " -C %s %s",
+ mythere ? mythere : where,
+ p->name);
+ if (add_count > maxargs - where_count)
+ barf("oops, miscounted strings!");
+ where_count += add_count;
+ last_chdir = (mythere ? mythere : where);
+ }
}
p = p->next;
}
+ PUSHOUT();
+ free(where_args);
}
OpenPOWER on IntegriCloud