1/* 2 * FreeBSD install - a package for the installation and maintenance 3 * of non-core utilities. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * Jordan K. Hubbard 15 * 18 July 1993 16 * 17 * Routines for dealing with the packing list. 18 * 19 */ 20 21#include <sys/cdefs.h> 22__FBSDID("$FreeBSD$"); 23 24#include "lib.h" 25#include "create.h" 26#include <errno.h> 27#include <err.h> 28#include <md5.h> 29 30/* Add an MD5 checksum entry for a file or link */ 31void 32add_cksum(Package *pkg, PackingList p, const char *fname) 33{ 34 char *cp = NULL, buf[33]; 35 36 if (issymlink(fname)) { 37 int len; 38 char lnk[FILENAME_MAX]; 39 40 if ((len = readlink(fname, lnk, FILENAME_MAX)) > 0) 41 cp = MD5Data((unsigned char *)lnk, len, buf); 42 } else if (isfile(fname)) { 43 /* Don't record MD5 checksum for device nodes and such */ 44 cp = MD5File(fname, buf); 45 } 46 47 if (cp != NULL) { 48 PackingList tmp = new_plist_entry(); 49 50 tmp->name = copy_string(strconcat("MD5:", cp)); 51 tmp->type = PLIST_COMMENT; 52 tmp->next = p->next; 53 tmp->prev = p; 54 p->next = tmp; 55 if (pkg->tail == p) 56 pkg->tail = tmp; 57 } 58} 59 60/* Check a list for files that require preconversion */ 61void 62check_list(const char *home, Package *pkg) 63{ 64 const char *where = home; 65 const char *there = NULL; 66 char name[FILENAME_MAX]; 67 char *prefix = NULL; 68 PackingList p; 69 70 for (p = pkg->head; p != NULL; p = p->next) 71 switch (p->type) { 72 case PLIST_CWD: 73 if (!prefix) 74 prefix = p->name; 75 where = (p->name == NULL) ? prefix : p->name; 76 break; 77 78 case PLIST_IGNORE: 79 p = p->next; 80 break; 81 82 case PLIST_SRC: 83 there = p->name; 84 break; 85 86 case PLIST_FILE: 87 if (there) 88 snprintf(name, sizeof(name), "%s/%s", there, p->name); 89 else 90 snprintf(name, sizeof(name), "%s%s/%s", 91 BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name); 92 93 add_cksum(pkg, p, name); 94 break; 95 default: 96 break; 97 } 98} 99 100static int 101trylink(const char *from, const char *to) 102{ 103 if (link(from, to) == 0) 104 return 0; 105 if (errno == ENOENT) { 106 /* try making the container directory */ 107 char *cp = strrchr(to, '/'); 108 if (cp) 109 vsystem("/bin/mkdir -p %.*s", cp - to, 110 to); 111 return link(from, to); 112 } 113 return -1; 114} 115 116#define STARTSTRING "/usr/bin/tar cf -" 117#define TOOBIG(str) (int)strlen(str) + 6 + (int)strlen(home) + where_count > maxargs 118#define PUSHOUT() /* push out string */ \ 119 if (where_count > (int)sizeof(STARTSTRING)-1) { \ 120 strcat(where_args, "|/usr/bin/tar xpf -"); \ 121 if (system(where_args)) { \ 122 cleanup(0); \ 123 errx(2, "%s: can't invoke tar pipeline", __func__); \ 124 } \ 125 memset(where_args, 0, maxargs); \ 126 last_chdir = NULL; \ 127 strcpy(where_args, STARTSTRING); \ 128 where_count = sizeof(STARTSTRING)-1; \ 129 } 130 131/* 132 * Copy unmarked files in packing list to playpen - marked files 133 * have already been copied in an earlier pass through the list. 134 */ 135void 136copy_plist(const char *home, Package *plist) 137{ 138 PackingList p = plist->head; 139 const char *where = home; 140 const char *there = NULL, *mythere; 141 char *where_args, *prefix = NULL; 142 const char *last_chdir, *root = "/"; 143 long maxargs; 144 int where_count = 0, add_count; 145 struct stat stb; 146 dev_t curdir; 147 148 maxargs = sysconf(_SC_ARG_MAX); 149 maxargs -= 64; /* 150 * Some slop for the tar cmd text, 151 * and sh -c 152 */ 153 where_args = malloc(maxargs); 154 if (!where_args) { 155 cleanup(0); 156 errx(2, "%s: can't get argument list space", __func__); 157 } 158 159 memset(where_args, 0, maxargs); 160 strcpy(where_args, STARTSTRING); 161 where_count = sizeof(STARTSTRING)-1; 162 last_chdir = 0; 163 164 if (stat(".", &stb) == 0) 165 curdir = stb.st_dev; 166 else 167 curdir = (dev_t) -1; /* 168 * It's ok if this is a valid dev_t; 169 * this is just a hint for an 170 * optimization. 171 */ 172 173 while (p) { 174 if (p->type == PLIST_CWD) 175 { 176 if (!prefix) 177 prefix = p->name; 178 where = p->name == NULL ? prefix : p->name; 179 } 180 else if (p->type == PLIST_SRC) 181 there = p->name; 182 else if (p->type == PLIST_IGNORE) 183 p = p->next; 184 else if (p->type == PLIST_FILE && !p->marked) { 185 char fn[FILENAME_MAX]; 186 187 188 /* First, look for it in the "home" dir */ 189 sprintf(fn, "%s/%s", home, p->name); 190 if (fexists(fn)) { 191 if (lstat(fn, &stb) == 0 && stb.st_dev == curdir && 192 S_ISREG(stb.st_mode)) { 193 /* 194 * If we can link it to the playpen, that avoids a copy 195 * and saves time. 196 */ 197 if (p->name[0] != '/') { 198 /* 199 * Don't link abspn stuff--it doesn't come from 200 * local dir! 201 */ 202 if (trylink(fn, p->name) == 0) { 203 p = p->next; 204 continue; 205 } 206 } 207 } 208 if (TOOBIG(fn)) { 209 PUSHOUT(); 210 } 211 if (p->name[0] == '/') { 212 add_count = snprintf(&where_args[where_count], 213 maxargs - where_count, 214 " %s %s", 215 last_chdir == root ? "" : "-C /", 216 p->name); 217 last_chdir = root; 218 } else { 219 add_count = snprintf(&where_args[where_count], 220 maxargs - where_count, 221 " %s%s %s", 222 last_chdir == home ? "" : "-C ", 223 last_chdir == home ? "" : home, 224 p->name); 225 last_chdir = home; 226 } 227 if (add_count < 0 || add_count >= maxargs - where_count) { 228 cleanup(0); 229 errx(2, "%s: oops, miscounted strings!", __func__); 230 } 231 where_count += add_count; 232 } 233 /* 234 * Otherwise, try along the actual extraction path.. 235 */ 236 else { 237 if (p->name[0] == '/') 238 mythere = root; 239 else mythere = there; 240 if (mythere) 241 snprintf(fn, sizeof(fn), "%s/%s", mythere, p->name); 242 else 243 snprintf(fn, sizeof(fn), "%s%s/%s", 244 BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name); 245 if (lstat(fn, &stb) == 0 && stb.st_dev == curdir && 246 S_ISREG(stb.st_mode)) { 247 /* 248 * If we can link it to the playpen, that avoids a copy 249 * and saves time. 250 */ 251 if (trylink(fn, p->name) == 0) { 252 p = p->next; 253 continue; 254 } 255 } 256 if (TOOBIG(p->name)) { 257 PUSHOUT(); 258 } 259 if (last_chdir == (mythere ? mythere : where)) 260 add_count = snprintf(&where_args[where_count], 261 maxargs - where_count, 262 " %s", p->name); 263 else 264 add_count = snprintf(&where_args[where_count], 265 maxargs - where_count, 266 " -C %s %s", 267 mythere ? mythere : where, 268 p->name); 269 if (add_count < 0 || add_count >= maxargs - where_count) { 270 cleanup(0); 271 errx(2, "%s: oops, miscounted strings!", __func__); 272 } 273 where_count += add_count; 274 last_chdir = (mythere ? mythere : where); 275 } 276 } 277 p = p->next; 278 } 279 PUSHOUT(); 280 free(where_args); 281} 282