2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
17 * This is the main body of the add module.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
33 static int pkg_do(char *);
34 static int sanity_check(char *);
35 static char LogDir
[FILENAME_MAX
];
36 static int zapLogDir
; /* Should we delete LogDir? */
39 pkg_perform(char **pkgs
)
43 signal(SIGINT
, cleanup
);
44 signal(SIGHUP
, cleanup
);
47 err_cnt
= pkg_do(NULL
);
49 for (i
= 0; pkgs
[i
]; i
++)
50 err_cnt
+= pkg_do(pkgs
[i
]);
59 * This is seriously ugly code following. Written very fast!
60 * [And subsequently made even worse.. Sigh! This code was just born
61 * to be hacked, I guess.. :) -jkh]
66 char pkg_fullname
[FILENAME_MAX
];
67 char playpen
[FILENAME_MAX
];
68 char extract_contents
[FILENAME_MAX
];
69 char *where_to
, *extract
;
74 int inPlace
, conflictsfound
, errcode
;
75 /* support for separate pre/post install scripts */
77 char pre_script
[FILENAME_MAX
] = INSTALL_FNAME
;
78 char post_script
[FILENAME_MAX
];
79 char pre_arg
[FILENAME_MAX
], post_arg
[FILENAME_MAX
];
87 strcpy(playpen
, FirstPen
);
90 /* Are we coming in for a second pass, everything already extracted? */
92 fgets(playpen
, FILENAME_MAX
, stdin
);
93 playpen
[strlen(playpen
) - 1] = '\0'; /* pesky newline! */
94 if (chdir(playpen
) == FAIL
) {
95 warnx("pkg_add in SLAVE mode can't chdir to %s", playpen
);
98 read_plist(&Plist
, stdin
);
101 /* Nope - do it now */
103 /* Is it an ftp://foo.bar.baz/file.t[bg]z specification? */
105 if (!(Home
= fileGetURL(NULL
, pkg
, KeepPackage
))) {
106 warnx("unable to fetch '%s' by URL", pkg
);
110 strcpy(pkg_fullname
, pkg
);
111 cfile
= fopen(CONTENTS_FNAME
, "r");
114 "unable to open table of contents file '%s' - not a package?",
118 read_plist(&Plist
, cfile
);
122 strcpy(pkg_fullname
, pkg
); /*
123 * Copy for sanity's sake,
124 * could remove pkg_fullname
126 if (strcmp(pkg
, "-")) {
127 if (stat(pkg_fullname
, &sb
) == FAIL
) {
128 warnx("can't stat package file '%s'", pkg_fullname
);
131 sprintf(extract_contents
, "--fast-read %s", CONTENTS_FNAME
);
132 extract
= extract_contents
;
136 sb
.st_size
= 100000; /* Make up a plausible average size */
138 Home
= make_playpen(playpen
, sb
.st_size
* 4);
140 errx(1, "unable to make playpen for %lld bytes", (long long)sb
.st_size
* 4);
142 /* Since we can call ourselves recursively, keep notes on where we came from */
144 setenv("_TOP", Home
, 1);
145 if (unpack(pkg_fullname
, extract
)) {
147 "unable to extract table of contents file from '%s' - not a package?",
151 cfile
= fopen(CONTENTS_FNAME
, "r");
154 "unable to open table of contents file '%s' - not a package?",
158 read_plist(&Plist
, cfile
);
161 /* Extract directly rather than moving? Oh goodie! */
162 if (find_plist_option(&Plist
, "extract-in-place")) {
164 printf("Doing in-place extraction for %s\n", pkg_fullname
);
165 p
= find_plist(&Plist
, PLIST_CWD
);
167 if (!isdir(p
->name
) && !Fake
) {
169 printf("Desired prefix of %s does not exist, creating..\n", p
->name
);
170 vsystem("/bin/mkdir -p %s", p
->name
);
171 if (chdir(p
->name
) == -1) {
172 warn("unable to change directory to '%s'", p
->name
);
181 "no prefix specified in '%s' - this is a bad package!",
188 * Apply a crude heuristic to see how much space the package will
189 * take up once it's unpacked. I've noticed that most packages
190 * compress an average of 75%, so multiply by 4 for good measure.
193 if (!extract
&& !inPlace
&& min_free(playpen
) < sb
.st_size
* 4) {
194 warnx("projected size of %lld exceeds available free space.\n"
195 "Please set your PKG_TMPDIR variable to point to a location with more\n"
196 "free space and try again", (long long)sb
.st_size
* 4);
197 warnx("not extracting %s\ninto %s, sorry!",
198 pkg_fullname
, where_to
);
202 /* If this is a direct extract and we didn't want it, stop now */
206 /* Finally unpack the whole mess. If extract is null we
207 already + did so so don't bother doing it again. */
208 if (extract
&& unpack(pkg_fullname
, NULL
)) {
209 warnx("unable to extract '%s'!", pkg_fullname
);
214 /* Check for sanity and dependencies */
215 if (sanity_check(pkg
))
218 /* If we're running in MASTER mode, just output the plist and return */
219 if (AddMode
== MASTER
) {
220 printf("%s\n", where_playpen());
221 write_plist(&Plist
, stdout
);
227 * If we have a prefix, delete the first one we see and add this
228 * one in place of it.
231 delete_plist(&Plist
, FALSE
, PLIST_CWD
, NULL
);
232 add_plist_top(&Plist
, PLIST_CWD
, Prefix
);
235 setenv(PKG_PREFIX_VNAME
, (p
= find_plist(&Plist
, PLIST_CWD
)) ? p
->name
: ".", 1);
236 /* Protect against old packages with bogus @name and origin fields */
237 if (Plist
.name
== NULL
)
238 Plist
.name
= "anonymous";
239 if (Plist
.origin
== NULL
)
240 Plist
.origin
= "anonymous/anonymous";
243 * See if we're already registered either with the same name (the same
244 * version) or some other version with the same origin.
246 if ((isinstalledpkg(Plist
.name
) > 0 ||
247 matchbyorigin(Plist
.origin
, NULL
) != NULL
) && !Force
) {
248 warnx("package '%s' or its older version already installed%s",
249 Plist
.name
, FailOnAlreadyInstalled
? "" : " (ignored)");
250 code
= FailOnAlreadyInstalled
!= FALSE
;
251 goto success
; /* close enough for government work */
254 /* Now check the packing list for conflicts */
256 for (p
= Plist
.head
; p
!= NULL
; p
= p
->next
) {
257 if (p
->type
== PLIST_CONFLICTS
) {
259 conflict
[0] = strdup(p
->name
);
261 matched
= matchinstalled(MATCH_GLOB
, conflict
, &errcode
);
263 if (errcode
== 0 && matched
!= NULL
)
264 for (i
= 0; matched
[i
] != NULL
; i
++)
265 if (isinstalledpkg(matched
[i
]) > 0) {
266 warnx("package '%s' conflicts with %s", Plist
.name
,
276 warnx("please use pkg_delete first to remove conflicting package(s) or -f to force installation");
280 warnx("-f specified; proceeding anyway");
283 /* Now check the packing list for dependencies */
284 for (p
= Plist
.head
; p
; p
= p
->next
) {
287 if (p
->type
!= PLIST_PKGDEP
)
289 deporigin
= (p
->next
->type
== PLIST_DEPORIGIN
) ? p
->next
->name
: NULL
;
291 printf("Package '%s' depends on '%s'", Plist
.name
, p
->name
);
292 if (deporigin
!= NULL
)
293 printf(" with '%s' origin", deporigin
);
296 if (isinstalledpkg(p
->name
) <= 0 &&
297 !(deporigin
!= NULL
&& matchbyorigin(deporigin
, NULL
) != NULL
)) {
298 char path
[FILENAME_MAX
], *cp
= NULL
;
301 char prefixArg
[2 + MAXPATHLEN
]; /* "-P" + Prefix */
302 if (PrefixRecursive
) {
303 strlcpy(prefixArg
, "-P", sizeof(prefixArg
));
304 strlcat(prefixArg
, Prefix
, sizeof(prefixArg
));
306 if (!isURL(pkg
) && !getenv("PKG_ADD_BASE")) {
309 ext
= strrchr(pkg_fullname
, '.');
312 snprintf(path
, FILENAME_MAX
, "%s/%s%s", getenv("_TOP"), p
->name
, ext
);
316 cp
= fileFindByPath(pkg
, p
->name
);
319 printf("Loading it from %s.\n", cp
);
320 if (vsystem("%s %s %s '%s'", PkgAddCmd
, Verbose
? "-v " : "", PrefixRecursive
? prefixArg
: "", cp
)) {
321 warnx("autoload of dependency '%s' failed%s",
322 cp
, Force
? " (proceeding anyway)" : "!");
328 warnx("could not find package %s %s",
329 p
->name
, Force
? " (proceeding anyway)" : "!");
334 else if ((cp
= fileGetURL(pkg
, p
->name
, KeepPackage
)) != NULL
) {
336 printf("Finished loading %s over FTP.\n", p
->name
);
337 if (!fexists("+CONTENTS")) {
338 warnx("autoloaded package %s has no +CONTENTS file?",
343 else if (vsystem("(pwd; /bin/cat +CONTENTS) | %s %s %s %s -S", PkgAddCmd
, Verbose
? "-v" : "", PrefixRecursive
? prefixArg
: "", KeepPackage
? "-K" : "")) {
344 warnx("pkg_add of dependency '%s' failed%s",
345 p
->name
, Force
? " (proceeding anyway)" : "!");
350 printf("\t'%s' loaded successfully.\n", p
->name
);
351 /* Nuke the temporary playpen */
357 printf("and was not found%s.\n", Force
? " (proceeding anyway)" : "");
359 printf("Package dependency %s for %s not found%s\n", p
->name
, pkg
,
360 Force
? " (proceeding anyway)" : "!");
366 printf(" - already installed.\n");
368 } /* if (!IgnoreDeps) */
373 /* Look for the requirements file */
374 if (fexists(REQUIRE_FNAME
)) {
375 vsystem("/bin/chmod +x %s", REQUIRE_FNAME
); /* be sure */
377 printf("Running requirements file first for %s..\n", Plist
.name
);
378 if (!Fake
&& vsystem("./%s %s INSTALL", REQUIRE_FNAME
, Plist
.name
)) {
379 warnx("package %s fails requirements %s", pkg_fullname
,
380 Force
? "installing anyway" : "- not installed");
383 goto success
; /* close enough for government work */
389 * Test whether to use the old method of passing tokens to installation
390 * scripts, and set appropriate variables..
393 if (fexists(POST_INSTALL_FNAME
)) {
395 sprintf(post_script
, "%s", POST_INSTALL_FNAME
);
399 if (fexists(INSTALL_FNAME
)) {
400 sprintf(post_script
, "%s", INSTALL_FNAME
);
401 sprintf(pre_arg
, "PRE-INSTALL");
402 sprintf(post_arg
, "POST-INSTALL");
406 /* If we're really installing, and have an installation file, run it */
407 if (!NoInstall
&& fexists(pre_script
)) {
408 vsystem("/bin/chmod +x %s", pre_script
); /* make sure */
410 printf("Running pre-install for %s..\n", Plist
.name
);
411 if (!Fake
&& vsystem("./%s %s %s", pre_script
, Plist
.name
, pre_arg
)) {
412 warnx("install script returned error status");
415 goto success
; /* nothing to uninstall yet */
419 /* Now finally extract the entire show if we're not going direct */
420 if (!inPlace
&& !Fake
)
421 extract_plist(".", &Plist
);
423 if (!Fake
&& fexists(MTREE_FNAME
)) {
425 printf("Running mtree for %s..\n", Plist
.name
);
426 p
= find_plist(&Plist
, PLIST_CWD
);
428 printf("mtree -U -f %s -d -e -p %s >%s\n", MTREE_FNAME
, p
? p
->name
: "/", _PATH_DEVNULL
);
430 if (vsystem("/usr/sbin/mtree -U -f %s -d -e -p %s >%s", MTREE_FNAME
, p
? p
->name
: "/", _PATH_DEVNULL
))
431 warnx("mtree returned a non-zero status - continuing");
435 /* Run the installation script one last time? */
436 if (!NoInstall
&& fexists(post_script
)) {
437 vsystem("/bin/chmod +x %s", post_script
); /* make sure */
439 printf("Running post-install for %s..\n", Plist
.name
);
440 if (!Fake
&& vsystem("./%s %s %s", post_script
, Plist
.name
, post_arg
)) {
441 warnx("install script returned error status");
448 /* Time to record the deed? */
449 if (!NoRecord
&& !Fake
) {
450 char contents
[FILENAME_MAX
];
451 char **depnames
= NULL
, **deporigins
= NULL
, ***depmatches
;
452 int i
, dep_count
= 0;
456 warnx("not running as root - trying to record install anyway");
457 sprintf(LogDir
, "%s/%s", LOG_DIR
, Plist
.name
);
460 printf("Attempting to record package into %s..\n", LogDir
);
461 if (make_hierarchy(LogDir
)) {
462 warnx("can't record package into '%s', you're on your own!",
464 bzero(LogDir
, FILENAME_MAX
);
466 goto success
; /* close enough for government work */
468 /* Make sure pkg_info can read the entry */
469 vsystem("/bin/chmod a+rx %s", LogDir
);
470 move_file(".", DESC_FNAME
, LogDir
);
471 move_file(".", COMMENT_FNAME
, LogDir
);
472 if (fexists(INSTALL_FNAME
))
473 move_file(".", INSTALL_FNAME
, LogDir
);
474 if (fexists(POST_INSTALL_FNAME
))
475 move_file(".", POST_INSTALL_FNAME
, LogDir
);
476 if (fexists(DEINSTALL_FNAME
))
477 move_file(".", DEINSTALL_FNAME
, LogDir
);
478 if (fexists(POST_DEINSTALL_FNAME
))
479 move_file(".", POST_DEINSTALL_FNAME
, LogDir
);
480 if (fexists(REQUIRE_FNAME
))
481 move_file(".", REQUIRE_FNAME
, LogDir
);
482 if (fexists(DISPLAY_FNAME
))
483 move_file(".", DISPLAY_FNAME
, LogDir
);
484 if (fexists(MTREE_FNAME
))
485 move_file(".", MTREE_FNAME
, LogDir
);
486 sprintf(contents
, "%s/%s", LogDir
, CONTENTS_FNAME
);
487 contfile
= fopen(contents
, "w");
489 warnx("can't open new contents file '%s'! can't register pkg",
491 goto success
; /* can't log, but still keep pkg */
493 write_plist(&Plist
, contfile
);
495 for (p
= Plist
.head
; p
; p
= p
->next
) {
498 if (p
->type
!= PLIST_PKGDEP
)
500 deporigin
= (p
->next
->type
== PLIST_DEPORIGIN
) ? p
->next
->name
:
503 printf("Trying to record dependency on package '%s'", p
->name
);
504 if (deporigin
!= NULL
)
505 printf(" with '%s' origin", deporigin
);
510 /* Defer to origin lookup */
511 depnames
= realloc(depnames
, (dep_count
+ 1) * sizeof(*depnames
));
512 depnames
[dep_count
] = p
->name
;
513 deporigins
= realloc(deporigins
, (dep_count
+ 2) * sizeof(*deporigins
));
514 deporigins
[dep_count
] = deporigin
;
515 deporigins
[dep_count
+ 1] = NULL
;
518 /* No origin recorded, try to register on literal package name */
519 sprintf(contents
, "%s/%s/%s", LOG_DIR
, p
->name
,
521 contfile
= fopen(contents
, "a");
523 warnx("can't open dependency file '%s'!\n"
524 "dependency registration is incomplete", contents
);
526 fprintf(contfile
, "%s\n", Plist
.name
);
527 if (fclose(contfile
) == EOF
) {
528 warnx("cannot properly close file %s", contents
);
534 depmatches
= matchallbyorigin((const char **)deporigins
, NULL
);
536 if (!IgnoreDeps
&& depmatches
) {
537 for (i
= 0; i
< dep_count
; i
++) {
540 char **tmp
= depmatches
[i
];
541 for (j
= 0; tmp
[j
] != NULL
; j
++) {
542 /* Origin looked up */
543 sprintf(contents
, "%s/%s/%s", LOG_DIR
, tmp
[j
],
545 if (depnames
[i
] && strcmp(depnames
[i
], tmp
[j
]) != 0)
546 warnx("warning: package '%s' requires '%s', but '%s' "
547 "is installed", Plist
.name
, depnames
[i
], tmp
[j
]);
548 contfile
= fopen(contents
, "a");
550 warnx("can't open dependency file '%s'!\n"
551 "dependency registration is incomplete", contents
);
553 fprintf(contfile
, "%s\n", Plist
.name
);
554 if (fclose(contfile
) == EOF
)
555 warnx("cannot properly close file %s", contents
);
558 } else if (depnames
[i
]) {
559 /* No package present with this origin, try literal package name */
560 sprintf(contents
, "%s/%s/%s", LOG_DIR
, depnames
[i
],
562 contfile
= fopen(contents
, "a");
564 warnx("can't open dependency file '%s'!\n"
565 "dependency registration is incomplete", contents
);
567 fprintf(contfile
, "%s\n", Plist
.name
);
568 if (fclose(contfile
) == EOF
) {
569 warnx("cannot properly close file %s", contents
);
577 printf("Package %s registered in %s\n", Plist
.name
, LogDir
);
580 if ((p
= find_plist(&Plist
, PLIST_DISPLAY
)) != NULL
) {
584 snprintf(buf
, sizeof buf
, "%s/%s", LogDir
, p
->name
);
585 fp
= fopen(buf
, "r");
588 while (fgets(buf
, sizeof(buf
), fp
))
594 warnx("cannot open %s as display file", buf
);
606 /* Nuke the whole (installed) show, XXX but don't clean directories */
608 delete_package(FALSE
, FALSE
, &Plist
);
611 /* delete the packing list contents */
618 sanity_check(char *pkg
)
622 if (!fexists(CONTENTS_FNAME
)) {
623 warnx("package %s has no CONTENTS file!", pkg
);
626 else if (!fexists(COMMENT_FNAME
)) {
627 warnx("package %s has no COMMENT file!", pkg
);
630 else if (!fexists(DESC_FNAME
)) {
631 warnx("package %s has no DESC file!", pkg
);
640 static int in_cleanup
= 0;
645 printf("Signal %d received, cleaning up..\n", sig
);
646 if (!Fake
&& zapLogDir
&& LogDir
[0])
647 vsystem("%s -rf %s", REMOVE_CMD
, LogDir
);