perform.c revision 102384
1/* 2 * FreeBSD install - a package for the installation and maintainance 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 * This is the main body of the create module. 18 * 19 */ 20 21#include <sys/cdefs.h> 22__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/create/perform.c 102384 2002-08-25 01:01:08Z obrien $"); 23 24#include "lib.h" 25#include "create.h" 26 27#include <err.h> 28#include <libgen.h> 29#include <signal.h> 30#include <stdlib.h> 31#include <sys/syslimits.h> 32#include <sys/wait.h> 33#include <unistd.h> 34 35static void sanity_check(void); 36static void make_dist(const char *, const char *, const char *, Package *); 37static int create_from_installed(const char *, const char *); 38 39static char *home; 40 41int 42pkg_perform(char **pkgs) 43{ 44 char *pkg = *pkgs; /* Only one arg to create */ 45 char *cp; 46 FILE *pkg_in, *fp; 47 Package plist; 48 int len; 49 const char *suf; 50 51 /* Preliminary setup */ 52 if (InstalledPkg == NULL) 53 sanity_check(); 54 if (Verbose && !PlistOnly) 55 printf("Creating package %s\n", pkg); 56 57 /* chop suffix off if already specified, remembering if we want to compress */ 58 len = strlen(pkg); 59 if (len > 4) { 60 if (!strcmp(&pkg[len - 4], ".tbz")) { 61 Zipper = BZIP2; 62 pkg[len - 4] = '\0'; 63 } 64 else if (!strcmp(&pkg[len - 4], ".tgz")) { 65 Zipper = GZIP; 66 pkg[len - 4] = '\0'; 67 } 68 else if (!strcmp(&pkg[len - 4], ".tar")) { 69 Zipper = NONE; 70 pkg[len - 4] = '\0'; 71 } 72 } 73 if (Zipper == BZIP2) { 74 suf = "tbz"; 75 setenv("BZIP2", "--best", 0); 76 } else if (Zipper == GZIP) { 77 suf = "tgz"; 78 setenv("GZIP", "-9", 0); 79 } else 80 suf = "tar"; 81 82 if (InstalledPkg != NULL) 83 return (create_from_installed(pkg, suf)); 84 85 get_dash_string(&Comment); 86 get_dash_string(&Desc); 87 if (!strcmp(Contents, "-")) 88 pkg_in = stdin; 89 else { 90 pkg_in = fopen(Contents, "r"); 91 if (!pkg_in) { 92 cleanup(0); 93 errx(2, "%s: unable to open contents file '%s' for input", 94 __func__, Contents); 95 } 96 } 97 plist.head = plist.tail = NULL; 98 99 /* Stick the dependencies, if any, at the top */ 100 if (Pkgdeps) { 101 char **deps, *deporigin; 102 int i; 103 int ndeps = 0; 104 105 if (Verbose && !PlistOnly) 106 printf("Registering depends:"); 107 108 /* Count number of dependencies */ 109 for (cp = Pkgdeps; cp != NULL && *cp != '\0'; 110 cp = strpbrk(++cp, " \t\n")) { 111 ndeps++; 112 } 113 114 if (ndeps != 0) { 115 /* Create easy to use NULL-terminated list */ 116 deps = alloca(sizeof(*deps) * ndeps + 1); 117 if (deps == NULL) { 118 errx(2, "%s: alloca() failed", __func__); 119 /* Not reached */ 120 } 121 for (i = 0; Pkgdeps;) { 122 cp = strsep(&Pkgdeps, " \t\n"); 123 if (*cp) { 124 deps[i] = cp; 125 i++; 126 } 127 } 128 ndeps = i; 129 deps[ndeps] = NULL; 130 131 sortdeps(deps); 132 for (i = 0; i < ndeps; i++) { 133 deporigin = strchr(deps[i], ':'); 134 if (deporigin != NULL) { 135 *deporigin = '\0'; 136 add_plist_top(&plist, PLIST_DEPORIGIN, ++deporigin); 137 } 138 add_plist_top(&plist, PLIST_PKGDEP, deps[i]); 139 if (Verbose && !PlistOnly) 140 printf(" %s", deps[i]); 141 } 142 } 143 144 if (Verbose && !PlistOnly) 145 printf(".\n"); 146 } 147 148 /* If a SrcDir override is set, add it now */ 149 if (SrcDir) { 150 if (Verbose && !PlistOnly) 151 printf("Using SrcDir value of %s\n", SrcDir); 152 add_plist(&plist, PLIST_SRC, SrcDir); 153 } 154 155 /* Slurp in the packing list */ 156 read_plist(&plist, pkg_in); 157 158 /* Prefix should add an @cwd to the packing list */ 159 if (Prefix) 160 add_plist_top(&plist, PLIST_CWD, Prefix); 161 162 /* Add the origin if asked, at the top */ 163 if (Origin) 164 add_plist_top(&plist, PLIST_ORIGIN, Origin); 165 166 /* 167 * Run down the list and see if we've named it, if not stick in a name 168 * at the top. 169 */ 170 if (find_plist(&plist, PLIST_NAME) == NULL) 171 add_plist_top(&plist, PLIST_NAME, basename(pkg)); 172 173 if (asprintf(&cp, "PKG_FORMAT_REVISION:%d.%d", PLIST_FMT_VER_MAJOR, 174 PLIST_FMT_VER_MINOR) == -1) { 175 errx(2, "%s: asprintf() failed", __func__); 176 } 177 add_plist_top(&plist, PLIST_COMMENT, cp); 178 free(cp); 179 180 /* 181 * We're just here for to dump out a revised plist for the FreeBSD ports 182 * hack. It's not a real create in progress. 183 */ 184 if (PlistOnly) { 185 check_list(home, &plist); 186 write_plist(&plist, stdout); 187 exit(0); 188 } 189 190 /* Make a directory to stomp around in */ 191 home = make_playpen(PlayPen, 0); 192 signal(SIGINT, cleanup); 193 signal(SIGHUP, cleanup); 194 195 /* Make first "real contents" pass over it */ 196 check_list(home, &plist); 197 (void) umask(022); /* 198 * Make sure gen'ed directories, files don't have 199 * group or other write bits. 200 */ 201 /* copy_plist(home, &plist); */ 202 /* mark_plist(&plist); */ 203 204 /* Now put the release specific items in */ 205 add_plist(&plist, PLIST_CWD, "."); 206 write_file(COMMENT_FNAME, Comment); 207 add_plist(&plist, PLIST_IGNORE, NULL); 208 add_plist(&plist, PLIST_FILE, COMMENT_FNAME); 209 write_file(DESC_FNAME, Desc); 210 add_plist(&plist, PLIST_IGNORE, NULL); 211 add_plist(&plist, PLIST_FILE, DESC_FNAME); 212 213 if (Install) { 214 copy_file(home, Install, INSTALL_FNAME); 215 add_plist(&plist, PLIST_IGNORE, NULL); 216 add_plist(&plist, PLIST_FILE, INSTALL_FNAME); 217 } 218 if (PostInstall) { 219 copy_file(home, PostInstall, POST_INSTALL_FNAME); 220 add_plist(&plist, PLIST_IGNORE, NULL); 221 add_plist(&plist, PLIST_FILE, POST_INSTALL_FNAME); 222 } 223 if (DeInstall) { 224 copy_file(home, DeInstall, DEINSTALL_FNAME); 225 add_plist(&plist, PLIST_IGNORE, NULL); 226 add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME); 227 } 228 if (PostDeInstall) { 229 copy_file(home, PostDeInstall, POST_DEINSTALL_FNAME); 230 add_plist(&plist, PLIST_IGNORE, NULL); 231 add_plist(&plist, PLIST_FILE, POST_DEINSTALL_FNAME); 232 } 233 if (Require) { 234 copy_file(home, Require, REQUIRE_FNAME); 235 add_plist(&plist, PLIST_IGNORE, NULL); 236 add_plist(&plist, PLIST_FILE, REQUIRE_FNAME); 237 } 238 if (Display) { 239 copy_file(home, Display, DISPLAY_FNAME); 240 add_plist(&plist, PLIST_IGNORE, NULL); 241 add_plist(&plist, PLIST_FILE, DISPLAY_FNAME); 242 add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME); 243 } 244 if (Mtree) { 245 copy_file(home, Mtree, MTREE_FNAME); 246 add_plist(&plist, PLIST_IGNORE, NULL); 247 add_plist(&plist, PLIST_FILE, MTREE_FNAME); 248 add_plist(&plist, PLIST_MTREE, MTREE_FNAME); 249 } 250 251 /* Finally, write out the packing list */ 252 fp = fopen(CONTENTS_FNAME, "w"); 253 if (!fp) { 254 cleanup(0); 255 errx(2, "%s: can't open file %s for writing", 256 __func__, CONTENTS_FNAME); 257 } 258 write_plist(&plist, fp); 259 if (fclose(fp)) { 260 cleanup(0); 261 errx(2, "%s: error while closing %s", 262 __func__, CONTENTS_FNAME); 263 } 264 265 /* And stick it into a tar ball */ 266 make_dist(home, pkg, suf, &plist); 267 268 /* Cleanup */ 269 free(Comment); 270 free(Desc); 271 free_plist(&plist); 272 leave_playpen(); 273 return TRUE; /* Success */ 274} 275 276static void 277make_dist(const char *homedir, const char *pkg, const char *suff, Package *plist) 278{ 279 char tball[FILENAME_MAX]; 280 PackingList p; 281 int ret; 282 const char *args[50]; /* Much more than enough. */ 283 int nargs = 0; 284 int pipefds[2]; 285 FILE *totar; 286 pid_t pid; 287 const char *cname; 288 289 args[nargs++] = "tar"; /* argv[0] */ 290 291 if (*pkg == '/') 292 snprintf(tball, FILENAME_MAX, "%s.%s", pkg, suff); 293 else 294 snprintf(tball, FILENAME_MAX, "%s/%s.%s", homedir, pkg, suff); 295 296 args[nargs++] = "-c"; 297 args[nargs++] = "-f"; 298 args[nargs++] = tball; 299 if (strchr(suff, 'z')) { /* Compress/gzip/bzip2? */ 300 if (Zipper == BZIP2) { 301 args[nargs++] = "-j"; 302 cname = "bzip'd "; 303 } 304 else { 305 args[nargs++] = "-z"; 306 cname = "gzip'd "; 307 } 308 } else { 309 cname = ""; 310 } 311 if (Dereference) 312 args[nargs++] = "-h"; 313 if (ExcludeFrom) { 314 args[nargs++] = "-X"; 315 args[nargs++] = ExcludeFrom; 316 } 317 args[nargs++] = "-T"; /* Take filenames from file instead of args. */ 318 args[nargs++] = "-"; /* Use stdin for the file. */ 319 args[nargs] = NULL; 320 321 if (Verbose) 322 printf("Creating %star ball in '%s'\n", cname, tball); 323 324 /* Set up a pipe for passing the filenames, and fork off a tar process. */ 325 if (pipe(pipefds) == -1) { 326 cleanup(0); 327 errx(2, "%s: cannot create pipe", __func__); 328 } 329 if ((pid = fork()) == -1) { 330 cleanup(0); 331 errx(2, "%s: cannot fork process for tar", __func__); 332 } 333 if (pid == 0) { /* The child */ 334 dup2(pipefds[0], 0); 335 close(pipefds[0]); 336 close(pipefds[1]); 337 execv("/usr/bin/tar", (char * const *)(uintptr_t)args); 338 cleanup(0); 339 errx(2, "%s: failed to execute tar command", __func__); 340 } 341 342 /* Meanwhile, back in the parent process ... */ 343 close(pipefds[0]); 344 if ((totar = fdopen(pipefds[1], "w")) == NULL) { 345 cleanup(0); 346 errx(2, "%s: fdopen failed", __func__); 347 } 348 349 fprintf(totar, "%s\n", CONTENTS_FNAME); 350 fprintf(totar, "%s\n", COMMENT_FNAME); 351 fprintf(totar, "%s\n", DESC_FNAME); 352 353 if (Install) 354 fprintf(totar, "%s\n", INSTALL_FNAME); 355 if (PostInstall) 356 fprintf(totar, "%s\n", POST_INSTALL_FNAME); 357 if (DeInstall) 358 fprintf(totar, "%s\n", DEINSTALL_FNAME); 359 if (PostDeInstall) 360 fprintf(totar, "%s\n", POST_DEINSTALL_FNAME); 361 if (Require) 362 fprintf(totar, "%s\n", REQUIRE_FNAME); 363 if (Display) 364 fprintf(totar, "%s\n", DISPLAY_FNAME); 365 if (Mtree) 366 fprintf(totar, "%s\n", MTREE_FNAME); 367 368 for (p = plist->head; p; p = p->next) { 369 if (p->type == PLIST_FILE) 370 fprintf(totar, "%s\n", p->name); 371 else if (p->type == PLIST_CWD || p->type == PLIST_SRC) 372 fprintf(totar, "-C\n%s\n", p->name); 373 else if (p->type == PLIST_IGNORE) 374 p = p->next; 375 } 376 377 fclose(totar); 378 wait(&ret); 379 /* assume either signal or bad exit is enough for us */ 380 if (ret) { 381 cleanup(0); 382 errx(2, "%s: tar command failed with code %d", __func__, ret); 383 } 384} 385 386static void 387sanity_check() 388{ 389 if (!Comment) { 390 cleanup(0); 391 errx(2, "%s: required package comment string is missing (-c comment)", 392 __func__); 393 } 394 if (!Desc) { 395 cleanup(0); 396 errx(2, "%s: required package description string is missing (-d desc)", 397 __func__); 398 } 399 if (!Contents) { 400 cleanup(0); 401 errx(2, "%s: required package contents list is missing (-f [-]file)", 402 __func__); 403 } 404} 405 406 407/* Clean up those things that would otherwise hang around */ 408void 409cleanup(int sig) 410{ 411 int in_cleanup = 0; 412 413 if (!in_cleanup) { 414 in_cleanup = 1; 415 leave_playpen(); 416 } 417 if (sig) 418 exit(1); 419} 420 421static int 422create_from_installed(const char *pkg, const char *suf) 423{ 424 FILE *fp; 425 Package plist; 426 char homedir[MAXPATHLEN], log_dir[FILENAME_MAX]; 427 428 snprintf(log_dir, sizeof(log_dir), "%s/%s", LOG_DIR, InstalledPkg); 429 if (!fexists(log_dir)) { 430 warnx("can't find package '%s' installed!", InstalledPkg); 431 return FALSE; 432 } 433 getcwd(homedir, sizeof(homedir)); 434 if (chdir(log_dir) == FAIL) { 435 warnx("can't change directory to '%s'!", log_dir); 436 return FALSE; 437 } 438 /* Suck in the contents list */ 439 plist.head = plist.tail = NULL; 440 fp = fopen(CONTENTS_FNAME, "r"); 441 if (!fp) { 442 warnx("unable to open %s file", CONTENTS_FNAME); 443 return FALSE; 444 } 445 read_plist(&plist, fp); 446 fclose(fp); 447 448 (const char *)Install = isfile(INSTALL_FNAME) ? INSTALL_FNAME : NULL; 449 (const char *)PostInstall = isfile(POST_INSTALL_FNAME) ? POST_INSTALL_FNAME : NULL; 450 (const char *)DeInstall = isfile(DEINSTALL_FNAME) ? DEINSTALL_FNAME : NULL; 451 (const char *)PostDeInstall = isfile(POST_DEINSTALL_FNAME) ? POST_DEINSTALL_FNAME : NULL; 452 (const char *)Require = isfile(REQUIRE_FNAME) ? REQUIRE_FNAME : NULL; 453 (const char *)Display = isfile(DISPLAY_FNAME) ? DISPLAY_FNAME : NULL; 454 (const char *)Mtree = isfile(MTREE_FNAME) ? MTREE_FNAME : NULL; 455 456 make_dist(homedir, pkg, suf, &plist); 457 458 free_plist(&plist); 459 return TRUE; 460} 461