1327Sjkh/* 2228990Suqs * FreeBSD install - a package for the installation and maintenance 3327Sjkh * of non-core utilities. 4327Sjkh * 5327Sjkh * Redistribution and use in source and binary forms, with or without 6327Sjkh * modification, are permitted provided that the following conditions 7327Sjkh * are met: 8327Sjkh * 1. Redistributions of source code must retain the above copyright 9327Sjkh * notice, this list of conditions and the following disclaimer. 10327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 11327Sjkh * notice, this list of conditions and the following disclaimer in the 12327Sjkh * documentation and/or other materials provided with the distribution. 13327Sjkh * 14327Sjkh * Jordan K. Hubbard 15327Sjkh * 18 July 1993 16327Sjkh * 17327Sjkh * This is the package extraction code for the add module. 18327Sjkh * 19327Sjkh */ 20327Sjkh 2193520Sobrien#include <sys/cdefs.h> 2293520Sobrien__FBSDID("$FreeBSD$"); 2393520Sobrien 24124922Sdes#include <ctype.h> 2530221Scharnier#include <err.h> 26222035Sflz#include "lib.h" 27327Sjkh#include "add.h" 28327Sjkh 294996Sjkh 30131285Seik#define STARTSTRING "/usr/bin/tar cf -" 31124921Sdes#define TOOBIG(str) \ 32124921Sdes (((int)strlen(str) + FILENAME_MAX + where_count > maxargs) ||\ 33124921Sdes ((int)strlen(str) + FILENAME_MAX + perm_count > maxargs)) 344996Sjkh 354996Sjkh#define PUSHOUT(todir) /* push out string */ \ 36124921Sdes if (where_count > (int)sizeof(STARTSTRING)-1) { \ 37171934Skrion strcat(where_args, "|/usr/bin/tar --unlink -xpPf - -C "); \ 38124921Sdes strcat(where_args, todir); \ 39124921Sdes if (system(where_args)) { \ 40124921Sdes cleanup(0); \ 41124921Sdes errx(2, "%s: can not invoke %ld byte tar pipeline: %s", \ 42124921Sdes __func__, (long)strlen(where_args), where_args); \ 434996Sjkh } \ 44124921Sdes strcpy(where_args, STARTSTRING); \ 45124921Sdes where_count = sizeof(STARTSTRING)-1; \ 46124921Sdes } \ 47124921Sdes if (perm_count) { \ 48124921Sdes apply_perms(todir, perm_args); \ 49124921Sdes perm_args[0] = 0;\ 50124921Sdes perm_count = 0; \ 51124921Sdes } 524996Sjkh 5327056Sjkhstatic void 5484745Ssobomaxrollback(const char *name, const char *home, PackingList start, PackingList stop) 5527056Sjkh{ 5627056Sjkh PackingList q; 5784745Ssobomax char try[FILENAME_MAX], bup[FILENAME_MAX]; 5884745Ssobomax const char *dir; 59154102Skrion char *prefix = NULL; 6027056Sjkh 6127056Sjkh dir = home; 6227056Sjkh for (q = start; q != stop; q = q->next) { 6327056Sjkh if (q->type == PLIST_FILE) { 6427056Sjkh snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name); 6527137Sjkh if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) { 6627056Sjkh (void)chflags(try, 0); 6727056Sjkh (void)unlink(try); 6827056Sjkh if (rename(bup, try)) 6930221Scharnier warnx("rollback: unable to rename %s back to %s", bup, try); 7027056Sjkh } 7127056Sjkh } 7227056Sjkh else if (q->type == PLIST_CWD) { 73154102Skrion if (!prefix) 74154102Skrion prefix = q->name; 75154102Skrion if (q->name == NULL) 76154102Skrion q->name = prefix; 77154102Skrion else if (strcmp(q->name, ".")) 7827056Sjkh dir = q->name; 7927056Sjkh else 8027056Sjkh dir = home; 8127056Sjkh } 8227056Sjkh } 8327056Sjkh} 8427056Sjkh 85124922Sdes#define add_char(buf, len, pos, ch) do {\ 86124922Sdes if ((pos) < (len)) { \ 87124922Sdes buf[(pos)] = (ch); \ 88124922Sdes buf[(pos) + 1] = '\0'; \ 89124922Sdes } \ 90124922Sdes ++(pos); \ 91124922Sdes} while (0) 92124922Sdes 93131280Seikstatic int 94124922Sdesadd_arg(char *buf, int len, const char *str) 95124922Sdes{ 96124922Sdes int i = 0; 97124922Sdes 98124922Sdes add_char(buf, len, i, ' '); 99124922Sdes for (; *str != '\0'; ++str) { 100124922Sdes if (!isalnum(*str) && *str != '/' && *str != '.' && *str != '-') 101124922Sdes add_char(buf, len, i, '\\'); 102124922Sdes add_char(buf, len, i, *str); 103124922Sdes } 104124922Sdes return (i); 105124922Sdes} 106124922Sdes 107327Sjkhvoid 10884745Ssobomaxextract_plist(const char *home, Package *pkg) 109327Sjkh{ 110327Sjkh PackingList p = pkg->head; 111154102Skrion char *last_file, *prefix = NULL; 1124996Sjkh char *where_args, *perm_args, *last_chdir; 113252363Sobrien long maxargs; 114252363Sobrien int where_count = 0, perm_count = 0, add_count; 11527056Sjkh Boolean preserve; 116327Sjkh 11723109Sjkh maxargs = sysconf(_SC_ARG_MAX) / 2; /* Just use half the argument space */ 11822762Sjkh where_args = alloca(maxargs); 11939068Sjkh if (!where_args) { 12039068Sjkh cleanup(0); 12196392Salfred errx(2, "%s: can't get argument list space", __func__); 12239068Sjkh } 12322762Sjkh perm_args = alloca(maxargs); 12439068Sjkh if (!perm_args) { 12539068Sjkh cleanup(0); 12696392Salfred errx(2, "%s: can't get argument list space", __func__); 12739068Sjkh } 1284996Sjkh 1294996Sjkh strcpy(where_args, STARTSTRING); 1304996Sjkh where_count = sizeof(STARTSTRING)-1; 1314996Sjkh perm_args[0] = 0; 1324996Sjkh 1334996Sjkh last_chdir = 0; 13427056Sjkh preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; 1354996Sjkh 136327Sjkh /* Reset the world */ 137327Sjkh Owner = NULL; 138327Sjkh Group = NULL; 139327Sjkh Mode = NULL; 140327Sjkh last_file = NULL; 141132789Skan Directory = (char *)home; 142327Sjkh 143327Sjkh /* Do it */ 144327Sjkh while (p) { 145477Sjkh char cmd[FILENAME_MAX]; 146477Sjkh 147327Sjkh switch(p->type) { 148327Sjkh case PLIST_NAME: 149327Sjkh PkgName = p->name; 150327Sjkh if (Verbose) 151327Sjkh printf("extract: Package name is %s\n", p->name); 152327Sjkh break; 153327Sjkh 154327Sjkh case PLIST_FILE: 155327Sjkh last_file = p->name; 156327Sjkh if (Verbose) 157327Sjkh printf("extract: %s/%s\n", Directory, p->name); 158327Sjkh if (!Fake) { 159382Sjkh char try[FILENAME_MAX]; 160382Sjkh 161382Sjkh /* first try to rename it into place */ 16227137Sjkh snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name); 16327137Sjkh if (fexists(try)) { 16427137Sjkh (void)chflags(try, 0); /* XXX hack - if truly immutable, rename fails */ 16527137Sjkh if (preserve && PkgName) { 16627137Sjkh char pf[FILENAME_MAX]; 16727056Sjkh 16827137Sjkh if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) { 16927137Sjkh if (rename(try, pf)) { 17030221Scharnier warnx( 17130221Scharnier "unable to back up %s to %s, aborting pkg_add", 17230221Scharnier try, pf); 17327137Sjkh rollback(PkgName, home, pkg->head, p); 17427137Sjkh return; 17527137Sjkh } 17627137Sjkh } 17727056Sjkh } 17827056Sjkh } 1794996Sjkh if (rename(p->name, try) == 0) { 18023109Sjkh /* try to add to list of perms to be changed and run in bulk. */ 18123109Sjkh if (p->name[0] == '/' || TOOBIG(p->name)) { 18222762Sjkh PUSHOUT(Directory); 18323109Sjkh } 184124922Sdes add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name); 185123602Snectar if (add_count < 0 || add_count >= maxargs - perm_count) { 18639068Sjkh cleanup(0); 18796392Salfred errx(2, "%s: oops, miscounted strings!", __func__); 18839068Sjkh } 1894996Sjkh perm_count += add_count; 19022762Sjkh } 19122762Sjkh else { 1924996Sjkh /* rename failed, try copying with a big tar command */ 19323109Sjkh if (last_chdir != Directory) { 19437378Sjkh if (last_chdir == NULL) { 19537378Sjkh PUSHOUT(Directory); 19637378Sjkh } else { 19737378Sjkh PUSHOUT(last_chdir); 19837378Sjkh } 1994996Sjkh last_chdir = Directory; 2004996Sjkh } 20123109Sjkh else if (p->name[0] == '/' || TOOBIG(p->name)) { 20223109Sjkh PUSHOUT(Directory); 20323109Sjkh } 204124922Sdes add_count = add_arg(&where_args[where_count], maxargs - where_count, p->name); 205123602Snectar if (add_count < 0 || add_count >= maxargs - where_count) { 20639068Sjkh cleanup(0); 20796392Salfred errx(2, "%s: oops, miscounted strings!", __func__); 20839068Sjkh } 2094996Sjkh where_count += add_count; 210124922Sdes add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name); 211123602Snectar if (add_count < 0 || add_count >= maxargs - perm_count) { 21239068Sjkh cleanup(0); 21396392Salfred errx(2, "%s: oops, miscounted strings!", __func__); 21439068Sjkh } 2154996Sjkh perm_count += add_count; 2164996Sjkh } 217327Sjkh } 218327Sjkh break; 219327Sjkh 220327Sjkh case PLIST_CWD: 221154102Skrion if (!prefix) 222154102Skrion prefix = p->name; 223154102Skrion if (p->name == NULL) 224154102Skrion p->name = strdup(prefix); 225327Sjkh if (Verbose) 226327Sjkh printf("extract: CWD to %s\n", p->name); 2274996Sjkh PUSHOUT(Directory); 228327Sjkh if (strcmp(p->name, ".")) { 229240476Sjkim if (!Fake && make_hierarchy(p->name, TRUE) == FAIL) { 23039068Sjkh cleanup(0); 23196392Salfred errx(2, "%s: unable to cwd to '%s'", __func__, p->name); 23239068Sjkh } 233327Sjkh Directory = p->name; 234327Sjkh } 235327Sjkh else 236132789Skan Directory = (char *)home; 237327Sjkh break; 238327Sjkh 239327Sjkh case PLIST_CMD: 24030686Smax if ((strstr(p->name, "%B") || strstr(p->name, "%F") || 24139068Sjkh strstr(p->name, "%f")) && last_file == NULL) { 24239068Sjkh cleanup(0); 24396388Salfred errx(2, "%s: no last file specified for '%s' command", 24496392Salfred __func__, p->name); 24539068Sjkh } 24639068Sjkh if (strstr(p->name, "%D") && Directory == NULL) { 24739068Sjkh cleanup(0); 24896388Salfred errx(2, "%s: no directory specified for '%s' command", 24996392Salfred __func__, p->name); 25039068Sjkh } 251108778Sjkh format_cmd(cmd, FILENAME_MAX, p->name, Directory, last_file); 2524996Sjkh PUSHOUT(Directory); 253327Sjkh if (Verbose) 254477Sjkh printf("extract: execute '%s'\n", cmd); 255477Sjkh if (!Fake && system(cmd)) 25630221Scharnier warnx("command '%s' failed", cmd); 257327Sjkh break; 258327Sjkh 259327Sjkh case PLIST_CHMOD: 2604996Sjkh PUSHOUT(Directory); 261327Sjkh Mode = p->name; 262327Sjkh break; 263327Sjkh 264327Sjkh case PLIST_CHOWN: 2654996Sjkh PUSHOUT(Directory); 266327Sjkh Owner = p->name; 267327Sjkh break; 268327Sjkh 269327Sjkh case PLIST_CHGRP: 2704996Sjkh PUSHOUT(Directory); 271327Sjkh Group = p->name; 272327Sjkh break; 273327Sjkh 274147381Skrion case PLIST_COMMENT: /* FALLTHROUGH */ 275147381Skrion case PLIST_NOINST: 276327Sjkh break; 277327Sjkh 278327Sjkh case PLIST_IGNORE: 279327Sjkh p = p->next; 280327Sjkh break; 28171373Ssobomax 28271373Ssobomax default: 28371373Ssobomax break; 284327Sjkh } 285327Sjkh p = p->next; 286327Sjkh } 2874996Sjkh PUSHOUT(Directory); 288327Sjkh} 289