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