extract.c revision 27137
1#ifndef lint 2static const char *rcsid = "$Id: extract.c,v 1.15 1997/06/30 02:57:40 jkh Exp $"; 3#endif 4 5/* 6 * FreeBSD install - a package for the installation and maintainance 7 * of non-core utilities. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Jordan K. Hubbard 19 * 18 July 1993 20 * 21 * This is the package extraction code for the add module. 22 * 23 */ 24 25#include "lib.h" 26#include "add.h" 27 28 29#define STARTSTRING "tar cf - " 30#define TOOBIG(str) ((strlen(str) + 22 + strlen(home) + where_count > maxargs) \ 31 || (strlen(str) + 6 + strlen(home) + perm_count > maxargs)) 32 33#define PUSHOUT(todir) /* push out string */ \ 34 if (where_count > sizeof(STARTSTRING)-1) { \ 35 strcat(where_args, "|tar xf - -C "); \ 36 strcat(where_args, todir); \ 37 if (system(where_args)) \ 38 barf("can not invoke %d byte tar pipeline: %s", strlen(where_args), where_args); \ 39 strcpy(where_args, STARTSTRING); \ 40 where_count = sizeof(STARTSTRING)-1; \ 41 } \ 42 if (perm_count) { \ 43 apply_perms(todir, perm_args); \ 44 perm_args[0] = 0;\ 45 perm_count = 0; \ 46 } 47 48static void 49rollback(char *name, char *home, PackingList start, PackingList stop) 50{ 51 PackingList q; 52 char try[FILENAME_MAX], bup[FILENAME_MAX], *dir; 53 54 dir = home; 55 for (q = start; q != stop; q = q->next) { 56 if (q->type == PLIST_FILE) { 57 snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name); 58 if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) { 59 (void)chflags(try, 0); 60 (void)unlink(try); 61 if (rename(bup, try)) 62 whinge("rollback: unable to rename %s back to %s.", bup, try); 63 } 64 } 65 else if (q->type == PLIST_CWD) { 66 if (strcmp(q->name, ".")) 67 dir = q->name; 68 else 69 dir = home; 70 } 71 } 72} 73 74void 75extract_plist(char *home, Package *pkg) 76{ 77 PackingList p = pkg->head; 78 char *last_file; 79 char *where_args, *perm_args, *last_chdir; 80 int maxargs, where_count = 0, perm_count = 0, add_count; 81 Boolean preserve; 82 83 maxargs = sysconf(_SC_ARG_MAX) / 2; /* Just use half the argument space */ 84 where_args = alloca(maxargs); 85 if (!where_args) 86 barf("can't get argument list space"); 87 perm_args = alloca(maxargs); 88 if (!perm_args) 89 barf("can't get argument list space"); 90 91 strcpy(where_args, STARTSTRING); 92 where_count = sizeof(STARTSTRING)-1; 93 perm_args[0] = 0; 94 95 last_chdir = 0; 96 preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; 97 98 /* Reset the world */ 99 Owner = NULL; 100 Group = NULL; 101 Mode = NULL; 102 last_file = NULL; 103 Directory = home; 104 105 /* Do it */ 106 while (p) { 107 char cmd[FILENAME_MAX]; 108 109 switch(p->type) { 110 case PLIST_NAME: 111 PkgName = p->name; 112 if (Verbose) 113 printf("extract: Package name is %s\n", p->name); 114 break; 115 116 case PLIST_FILE: 117 last_file = p->name; 118 if (Verbose) 119 printf("extract: %s/%s\n", Directory, p->name); 120 if (!Fake) { 121 char try[FILENAME_MAX]; 122 123 /* first try to rename it into place */ 124 snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name); 125 if (fexists(try)) { 126 (void)chflags(try, 0); /* XXX hack - if truly immutable, rename fails */ 127 if (preserve && PkgName) { 128 char pf[FILENAME_MAX]; 129 130 if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) { 131 if (rename(try, pf)) { 132 whinge("Unable to back up %s to %s, aborting pkg_add", try, pf); 133 rollback(PkgName, home, pkg->head, p); 134 return; 135 } 136 } 137 } 138 } 139 if (rename(p->name, try) == 0) { 140 /* try to add to list of perms to be changed and run in bulk. */ 141 if (p->name[0] == '/' || TOOBIG(p->name)) { 142 PUSHOUT(Directory); 143 } 144 add_count = snprintf(&perm_args[perm_count], maxargs - perm_count, "%s ", p->name); 145 if (add_count > maxargs - perm_count) 146 barf("oops, miscounted strings!"); 147 perm_count += add_count; 148 } 149 else { 150 /* rename failed, try copying with a big tar command */ 151 if (last_chdir != Directory) { 152 PUSHOUT(last_chdir); 153 last_chdir = Directory; 154 } 155 else if (p->name[0] == '/' || TOOBIG(p->name)) { 156 PUSHOUT(Directory); 157 } 158 add_count = snprintf(&where_args[where_count], maxargs - where_count, " %s", p->name); 159 if (add_count > maxargs - where_count) 160 barf("oops, miscounted strings!"); 161 where_count += add_count; 162 add_count = snprintf(&perm_args[perm_count], 163 maxargs - perm_count, 164 "%s ", p->name); 165 if (add_count > maxargs - perm_count) 166 barf("oops, miscounted strings!"); 167 perm_count += add_count; 168 } 169 } 170 break; 171 172 case PLIST_CWD: 173 if (Verbose) 174 printf("extract: CWD to %s\n", p->name); 175 PUSHOUT(Directory); 176 if (strcmp(p->name, ".")) { 177 if (!Fake && make_hierarchy(p->name) == FAIL) 178 barf("Unable make directory '%s'.", p->name); 179 Directory = p->name; 180 } 181 else 182 Directory = home; 183 break; 184 185 case PLIST_CMD: 186 if (last_file == NULL) 187 barf("No last file specified for '%s' command.", p->name); 188 format_cmd(cmd, p->name, Directory, last_file); 189 PUSHOUT(Directory); 190 if (Verbose) 191 printf("extract: execute '%s'\n", cmd); 192 if (!Fake && system(cmd)) 193 whinge("Command '%s' failed.", cmd); 194 break; 195 196 case PLIST_CHMOD: 197 PUSHOUT(Directory); 198 Mode = p->name; 199 break; 200 201 case PLIST_CHOWN: 202 PUSHOUT(Directory); 203 Owner = p->name; 204 break; 205 206 case PLIST_CHGRP: 207 PUSHOUT(Directory); 208 Group = p->name; 209 break; 210 211 case PLIST_COMMENT: 212 break; 213 214 case PLIST_IGNORE: 215 p = p->next; 216 break; 217 } 218 p = p->next; 219 } 220 PUSHOUT(Directory); 221} 222