diff options
Diffstat (limited to 'usr.sbin/pkg_install/add/extract.c')
-rw-r--r-- | usr.sbin/pkg_install/add/extract.c | 128 |
1 files changed, 88 insertions, 40 deletions
diff --git a/usr.sbin/pkg_install/add/extract.c b/usr.sbin/pkg_install/add/extract.c index a769b490165..7e330a860a8 100644 --- a/usr.sbin/pkg_install/add/extract.c +++ b/usr.sbin/pkg_install/add/extract.c @@ -1,7 +1,7 @@ -/* $OpenBSD: extract.c,v 1.5 1998/06/23 23:17:16 millert Exp $ */ +/* $OpenBSD: extract.c,v 1.6 1998/09/07 22:30:13 marc Exp $ */ #ifndef lint -static const char *rcsid = "$OpenBSD: extract.c,v 1.5 1998/06/23 23:17:16 millert Exp $"; +static const char *rcsid = "$OpenBSD: extract.c,v 1.6 1998/09/07 22:30:13 marc Exp $"; #endif /* @@ -24,20 +24,22 @@ static const char *rcsid = "$OpenBSD: extract.c,v 1.5 1998/06/23 23:17:16 miller * */ +#include <err.h> #include "lib.h" #include "add.h" -#define STARTSTRING "tar cf -" -#define TOOBIG(str) ((strlen(str) + 6 + strlen(home) + where_count > maxargs) \ +#define STARTSTRING "tar cf - " +#define TOOBIG(str) ((strlen(str) + 22 + strlen(home) + where_count > maxargs) \ || (strlen(str) + 6 + strlen(home) + perm_count > maxargs)) #define PUSHOUT(todir) /* push out string */ \ - if (strlen(where_args) > sizeof(STARTSTRING)-1) { \ - strcat(where_args, "|tar xpf - -C "); \ + if (where_count > sizeof(STARTSTRING)-1) { \ + strcat(where_args, "|tar xf - -C "); \ strcat(where_args, todir); \ if (system(where_args)) \ - barf("can't invoke tar pipeline"); \ + cleanup(0), errx(2, "can not invoke %lu byte tar pipeline: %s", \ + (u_long)strlen(where_args), where_args); \ strcpy(where_args, STARTSTRING); \ where_count = sizeof(STARTSTRING)-1; \ } \ @@ -47,6 +49,32 @@ static const char *rcsid = "$OpenBSD: extract.c,v 1.5 1998/06/23 23:17:16 miller perm_count = 0; \ } +static void +rollback(char *name, char *home, PackingList start, PackingList stop) +{ + PackingList q; + char try[FILENAME_MAX], bup[FILENAME_MAX], *dir; + + dir = home; + for (q = start; q != stop; q = q->next) { + if (q->type == PLIST_FILE) { + snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name); + if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) { + (void)chflags(try, 0); + (void)unlink(try); + if (rename(bup, try)) + warnx("rollback: unable to rename %s back to %s", bup, try); + } + } + else if (q->type == PLIST_CWD) { + if (strcmp(q->name, ".")) + dir = q->name; + else + dir = home; + } + } +} + void extract_plist(char *home, Package *pkg) { @@ -54,22 +82,22 @@ extract_plist(char *home, Package *pkg) char *last_file; char *where_args, *perm_args, *last_chdir; int maxargs, where_count = 0, perm_count = 0, add_count; + Boolean preserve; - maxargs = sysconf(_SC_ARG_MAX); - maxargs -= 64; /* some slop for the tar cmd text, - and sh -c */ - where_args = malloc(maxargs); + maxargs = sysconf(_SC_ARG_MAX) / 2; /* Just use half the argument space */ + where_args = alloca(maxargs); if (!where_args) - barf("can't get argument list space"); - perm_args = malloc(maxargs); + cleanup(0), errx(2, "can't get argument list space"); + perm_args = alloca(maxargs); if (!perm_args) - barf("can't get argument list space"); + cleanup(0), errx(2, "can't get argument list space"); strcpy(where_args, STARTSTRING); where_count = sizeof(STARTSTRING)-1; perm_args[0] = 0; last_chdir = 0; + preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; /* Reset the world */ Owner = NULL; @@ -96,43 +124,56 @@ extract_plist(char *home, Package *pkg) if (!Fake) { char try[FILENAME_MAX]; + if (strrchr(p->name,'\'')) + cleanup(0), errx(2, "Bogus filename \"%s\"", p->name); + /* first try to rename it into place */ - sprintf(try, "%s/%s", Directory, p->name); + snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name); + if (fexists(try)) { + (void)chflags(try, 0); /* XXX hack - if truly immutable, rename fails */ + if (preserve && PkgName) { + char pf[FILENAME_MAX]; + + if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) { + if (rename(try, pf)) { + warnx( + "unable to back up %s to %s, aborting pkg_add", + try, pf); + rollback(PkgName, home, pkg->head, p); + return; + } + } + } + } if (rename(p->name, try) == 0) { - /* try to add to list of perms to be changed, - and run in bulk. */ - add_count = snprintf(&perm_args[perm_count], - maxargs - perm_count, - "'%s' ", p->name); - if (add_count >= maxargs - perm_count) - barf("oops, miscounted strings!"); - perm_count += add_count; - if (p->name[0] == '/') { + /* try to add to list of perms to be changed and run in bulk. */ + if (p->name[0] == '/' || TOOBIG(p->name)) { PUSHOUT(Directory); } - } else { + add_count = snprintf(&perm_args[perm_count], maxargs - perm_count, "'%s' ", p->name); + if (add_count > maxargs - perm_count) + cleanup(0), errx(2, "oops, miscounted strings!"); + perm_count += add_count; + } + else { /* rename failed, try copying with a big tar command */ - if (p->name[0] == '/' || - TOOBIG(p->name) || - last_chdir != Directory) { + if (last_chdir != Directory) { PUSHOUT(last_chdir); last_chdir = Directory; } - add_count = snprintf(&where_args[where_count], - maxargs - where_count, - " %s", p->name); - if (add_count >= maxargs - where_count) - barf("oops, miscounted strings!"); + else if (p->name[0] == '/' || TOOBIG(p->name)) { + PUSHOUT(Directory); + } + add_count = snprintf(&where_args[where_count], maxargs - where_count, " '%s'", p->name); + if (add_count > maxargs - where_count) + cleanup(0), errx(2, "oops, miscounted strings!"); where_count += add_count; add_count = snprintf(&perm_args[perm_count], maxargs - perm_count, "'%s' ", p->name); - if (add_count >= maxargs - perm_count) - barf("oops, miscounted strings!"); + if (add_count > maxargs - perm_count) + cleanup(0), errx(2, "oops, miscounted strings!"); perm_count += add_count; - if (p->name[0] == '/') { - PUSHOUT(Directory); - } } } break; @@ -143,7 +184,8 @@ extract_plist(char *home, Package *pkg) PUSHOUT(Directory); if (strcmp(p->name, ".")) { if (!Fake && make_hierarchy(p->name) == FAIL) - barf("Unable make directory '%s'.", p->name); + cleanup(0), errx(2, "unable to make directory '%s'", + p->name); Directory = p->name; } else @@ -151,12 +193,15 @@ extract_plist(char *home, Package *pkg) break; case PLIST_CMD: + if (last_file == NULL) + cleanup(0), errx(2, "no last file specified for '%s' command", + p->name); format_cmd(cmd, p->name, Directory, last_file); PUSHOUT(Directory); if (Verbose) printf("extract: execute '%s'\n", cmd); if (!Fake && system(cmd)) - whinge("Command '%s' failed.", cmd); + warnx("command '%s' failed", cmd); break; case PLIST_CHMOD: @@ -180,6 +225,9 @@ extract_plist(char *home, Package *pkg) case PLIST_IGNORE: p = p->next; break; + + default: + break; } p = p->next; } |