main.c revision 159554
111820Sjulian/*
211820Sjulian *
311820Sjulian * FreeBSD install - a package for the installation and maintainance
411820Sjulian * of non-core utilities.
511820Sjulian *
611820Sjulian * Redistribution and use in source and binary forms, with or without
711820Sjulian * modification, are permitted provided that the following conditions
811820Sjulian * are met:
911820Sjulian * 1. Redistributions of source code must retain the above copyright
1011820Sjulian *    notice, this list of conditions and the following disclaimer.
1111820Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211820Sjulian *    notice, this list of conditions and the following disclaimer in the
1311820Sjulian *    documentation and/or other materials provided with the distribution.
1411820Sjulian *
1511820Sjulian * Jordan K. Hubbard
1611820Sjulian * 18 July 1993
1711820Sjulian *
1811820Sjulian * This is the add module.
1911820Sjulian */
2011820Sjulian
2111820Sjulian#include <sys/cdefs.h>
2211820Sjulian__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/add/main.c 159554 2006-06-12 22:39:32Z obrien $");
2311820Sjulian
2411820Sjulian#include <err.h>
2511820Sjulian#include <sys/param.h>
2611820Sjulian#include <sys/utsname.h>
2711820Sjulian#include "lib.h"
2811820Sjulian#include "add.h"
2911820Sjulian
3011820Sjulianstatic char Options[] = "hvIRfFnrp:P:SMt:C:K";
3111820Sjulian
3211820Sjulianchar	*Prefix		= NULL;
3311820SjulianBoolean	PrefixRecursive	= FALSE;
3411820Sjulianchar	*Chroot		= NULL;
3511820SjulianBoolean	NoInstall	= FALSE;
3611820SjulianBoolean	NoRecord	= FALSE;
3711820SjulianBoolean Remote		= FALSE;
3850479SpeterBoolean KeepPackage	= FALSE;
3911820SjulianBoolean FailOnAlreadyInstalled	= TRUE;
4011820Sjulian
4111820Sjulianchar	*Mode		= NULL;
42122760Strhodeschar	*Owner		= NULL;
4311820Sjulianchar	*Group		= NULL;
4411820Sjulianchar	*PkgName	= NULL;
4511820Sjulianchar	*PkgAddCmd	= NULL;
4611820Sjulianchar	*Directory	= NULL;
4711820Sjulianchar	FirstPen[FILENAME_MAX];
4811820Sjulianadd_mode_t AddMode	= NORMAL;
4911820Sjulian
5011820Sjulian#define MAX_PKGS	200
5111820Sjulianchar	pkgnames[MAX_PKGS][MAXPATHLEN];
5211820Sjulianchar	*pkgs[MAX_PKGS];
5311820Sjulian
5411820Sjulianstruct {
5511820Sjulian	int lowver;	/* Lowest version number to match */
5611820Sjulian	int hiver;	/* Highest version number to match */
5711820Sjulian	const char *directory;	/* Directory it lives in */
5811820Sjulian} releases[] = {
5911820Sjulian	{ 410000, 410000, "/packages-4.1-release" },
6011820Sjulian	{ 420000, 420000, "/packages-4.2-release" },
6111820Sjulian	{ 430000, 430000, "/packages-4.3-release" },
6211820Sjulian	{ 440000, 440000, "/packages-4.4-release" },
6311820Sjulian	{ 450000, 450000, "/packages-4.5-release" },
6411820Sjulian	{ 460000, 460001, "/packages-4.6-release" },
6511820Sjulian	{ 460002, 460099, "/packages-4.6.2-release" },
6627244Sjhay	{ 470000, 470099, "/packages-4.7-release" },
6711820Sjulian	{ 480000, 480099, "/packages-4.8-release" },
6811820Sjulian	{ 490000, 490099, "/packages-4.9-release" },
6911820Sjulian	{ 491000, 491099, "/packages-4.10-release" },
7011820Sjulian	{ 492000, 492099, "/packages-4.11-release" },
7111820Sjulian	{ 500000, 500099, "/packages-5.0-release" },
7211820Sjulian	{ 501000, 501099, "/packages-5.1-release" },
7311820Sjulian	{ 502000, 502009, "/packages-5.2-release" },
7411820Sjulian	{ 502010, 502099, "/packages-5.2.1-release" },
7511820Sjulian	{ 503000, 503099, "/packages-5.3-release" },
7627244Sjhay	{ 504000, 504099, "/packages-5.4-release" },
7711820Sjulian	{ 600000, 600099, "/packages-6.0-release" },
7811820Sjulian	{ 300000, 399000, "/packages-3-stable" },
7911820Sjulian	{ 400000, 499000, "/packages-4-stable" },
8011820Sjulian	{ 502100, 502128, "/packages-5-current" },
8111820Sjulian	{ 503100, 599000, "/packages-5-stable" },
8211820Sjulian	{ 600100, 699000, "/packages-6-stable" },
8311820Sjulian	{ 700000, 799000, "/packages-7-current" },
8411820Sjulian	{ 0, 9999999, "/packages-current" },
8511820Sjulian	{ 0, 0, NULL }
8611820Sjulian};
8711820Sjulian
8811820Sjulianstatic char *getpackagesite(void);
8911820Sjulianint getosreldate(void);
9011820Sjulian
9111820Sjulianstatic void usage __P((void));
9211820Sjulian
9311820Sjulianint
9411820Sjulianmain(int argc, char **argv)
9511820Sjulian{
9611820Sjulian    int ch, error;
9711820Sjulian    char **start;
9811820Sjulian    char *cp, *packagesite = NULL, *remotepkg = NULL, *ptr;
9911820Sjulian    static char temppackageroot[MAXPATHLEN];
10011820Sjulian    static char pkgaddpath[MAXPATHLEN];
10111820Sjulian
10211820Sjulian    if (*argv[0] != '/' && strchr(argv[0], '/') != NULL)
10311820Sjulian	PkgAddCmd = realpath(argv[0], pkgaddpath);
10411820Sjulian    else
10511820Sjulian	PkgAddCmd = argv[0];
10611820Sjulian
10711820Sjulian    start = argv;
10811820Sjulian    while ((ch = getopt(argc, argv, Options)) != -1) {
10911820Sjulian	switch(ch) {
11011820Sjulian	case 'v':
11111820Sjulian	    Verbose++;
11211820Sjulian	    break;
11327244Sjhay
11411820Sjulian	case 'p':
11527244Sjhay	    Prefix = optarg;
11627244Sjhay	    PrefixRecursive = FALSE;
11711820Sjulian	    break;
11811820Sjulian
11911820Sjulian	case 'P':
12011820Sjulian	    Prefix = optarg;
12111820Sjulian	    PrefixRecursive = TRUE;
12211820Sjulian	    break;
12311820Sjulian
12411820Sjulian	case 'I':
12511820Sjulian	    NoInstall = TRUE;
12611820Sjulian	    break;
12711820Sjulian
12827244Sjhay	case 'R':
12927244Sjhay	    NoRecord = TRUE;
13011820Sjulian	    break;
13111820Sjulian
13211820Sjulian	case 'f':
13311820Sjulian	    Force = TRUE;
13411820Sjulian	    break;
13511820Sjulian
13611820Sjulian	case 'F':
13727244Sjhay	    FailOnAlreadyInstalled = FALSE;
13811820Sjulian	    break;
13911820Sjulian
14011820Sjulian	case 'K':
14111820Sjulian	    KeepPackage = TRUE;
14227244Sjhay	    break;
14311820Sjulian
14411820Sjulian	case 'n':
14511820Sjulian	    Fake = TRUE;
14611820Sjulian	    break;
14711820Sjulian
14811820Sjulian	case 'r':
14911820Sjulian	    Remote = TRUE;
15011820Sjulian	    break;
15111820Sjulian
15211820Sjulian	case 't':
15311820Sjulian	    if (strlcpy(FirstPen, optarg, sizeof(FirstPen)) >= sizeof(FirstPen))
15411820Sjulian		errx(1, "-t Argument too long.");
15511820Sjulian	    break;
15611820Sjulian
15711820Sjulian	case 'S':
15811820Sjulian	    AddMode = SLAVE;
15911820Sjulian	    break;
16011820Sjulian
16111820Sjulian	case 'M':
16211820Sjulian	    AddMode = MASTER;
16311820Sjulian	    break;
16411820Sjulian
16511820Sjulian	case 'C':
16611820Sjulian	    Chroot = optarg;
16711820Sjulian	    break;
16811820Sjulian
16911820Sjulian	case 'h':
17011820Sjulian	case '?':
17111820Sjulian	default:
17227244Sjhay	    usage();
17327244Sjhay	    break;
17427244Sjhay	}
17527244Sjhay    }
17611820Sjulian    argc -= optind;
17711820Sjulian    argv += optind;
17811820Sjulian
17911820Sjulian    if (argc > MAX_PKGS) {
18011820Sjulian	errx(1, "too many packages (max %d)", MAX_PKGS);
18111820Sjulian    }
18211820Sjulian
18311820Sjulian    if (AddMode != SLAVE) {
18411820Sjulian	for (ch = 0; ch < MAX_PKGS; pkgs[ch++] = NULL) ;
18527244Sjhay
18627244Sjhay	/* Get all the remaining package names, if any */
18727244Sjhay	for (ch = 0; *argv; ch++, argv++) {
18827244Sjhay    	    if (Remote) {
18927244Sjhay		if ((packagesite = getpackagesite()) == NULL)
19027244Sjhay		    errx(1, "package name too long");
19127244Sjhay		if (strlcpy(temppackageroot, packagesite,
19227244Sjhay		    sizeof(temppackageroot)) >= sizeof(temppackageroot))
19327244Sjhay		    errx(1, "package name too long");
19427244Sjhay		if (strlcat(temppackageroot, *argv, sizeof(temppackageroot))
19527244Sjhay		    >= sizeof(temppackageroot))
19627244Sjhay		    errx(1, "package name too long");
19727244Sjhay		remotepkg = temppackageroot;
19827244Sjhay		if (!((ptr = strrchr(remotepkg, '.')) && ptr[1] == 't' &&
19927244Sjhay			(ptr[2] == 'b' || ptr[2] == 'g') && ptr[3] == 'z' &&
20011820Sjulian			!ptr[4]))
20111820Sjulian		    if (strlcat(remotepkg,
20211820Sjulian#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039
20327244Sjhay			".tbz",
20411820Sjulian#else
20511820Sjulian			".tgz",
20611820Sjulian#endif
20711820Sjulian			sizeof(temppackageroot)) >= sizeof(temppackageroot))
20811820Sjulian			errx(1, "package name too long");
20911820Sjulian    	    }
21011820Sjulian	    if (!strcmp(*argv, "-"))	/* stdin? */
21111820Sjulian		pkgs[ch] = (char *)"-";
21211820Sjulian	    else if (isURL(*argv)) {  	/* preserve URLs */
21311820Sjulian		if (strlcpy(pkgnames[ch], *argv, sizeof(pkgnames[ch]))
21411820Sjulian		    >= sizeof(pkgnames[ch]))
21511820Sjulian		    errx(1, "package name too long");
21611820Sjulian		pkgs[ch] = pkgnames[ch];
21711820Sjulian	    }
21811820Sjulian	    else if ((Remote) && isURL(remotepkg)) {
21911820Sjulian	    	if (strlcpy(pkgnames[ch], remotepkg, sizeof(pkgnames[ch]))
22027244Sjhay		    >= sizeof(pkgnames[ch]))
22111820Sjulian		    errx(1, "package name too long");
22211820Sjulian		pkgs[ch] = pkgnames[ch];
22311820Sjulian	    } else {			/* expand all pathnames to fullnames */
22411820Sjulian		if (fexists(*argv)) /* refers to a file directly */
22527244Sjhay		    pkgs[ch] = realpath(*argv, pkgnames[ch]);
22611820Sjulian		else {		/* look for the file in the expected places */
22711820Sjulian		    if (!(cp = fileFindByPath(NULL, *argv))) {
22811820Sjulian			/* let pkg_do() fail later, so that error is reported */
22911820Sjulian			if (strlcpy(pkgnames[ch], *argv, sizeof(pkgnames[ch]))
23011820Sjulian			    >= sizeof(pkgnames[ch]))
23111820Sjulian			    errx(1, "package name too long");
23211820Sjulian			pkgs[ch] = pkgnames[ch];
23311820Sjulian		    } else {
23411820Sjulian			if (strlcpy(pkgnames[ch], cp, sizeof(pkgnames[ch]))
23511820Sjulian			    >= sizeof(pkgnames[ch]))
23627244Sjhay			    errx(1, "package name too long");
23711820Sjulian			pkgs[ch] = pkgnames[ch];
23811820Sjulian		    }
23911820Sjulian		}
240	    }
241	    if (packagesite != NULL)
242		packagesite[0] = '\0';
243	}
244    }
245    /* If no packages, yelp */
246    else if (!ch) {
247	warnx("missing package name(s)");
248	usage();
249    }
250    else if (ch > 1 && AddMode == MASTER) {
251	warnx("only one package name may be specified with master mode");
252	usage();
253    }
254    /* Perform chroot if requested */
255    if (Chroot != NULL) {
256	if (chroot(Chroot))
257	    errx(1, "chroot to %s failed", Chroot);
258    }
259    /* Make sure the sub-execs we invoke get found */
260    setenv("PATH",
261	   "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin",
262	   1);
263
264    /* Set a reasonable umask */
265    umask(022);
266
267    if ((error = pkg_perform(pkgs)) != 0) {
268	if (Verbose)
269	    warnx("%d package addition(s) failed", error);
270	return error;
271    }
272    else
273	return 0;
274}
275
276static char *
277getpackagesite(void)
278{
279    int reldate, i;
280    static char sitepath[MAXPATHLEN];
281    struct utsname u;
282
283    if (getenv("PACKAGESITE")) {
284	if (strlcpy(sitepath, getenv("PACKAGESITE"), sizeof(sitepath))
285	    >= sizeof(sitepath))
286	    return NULL;
287	return sitepath;
288    }
289
290    if (getenv("PACKAGEROOT")) {
291	if (strlcpy(sitepath, getenv("PACKAGEROOT"), sizeof(sitepath))
292	    >= sizeof(sitepath))
293	    return NULL;
294    } else {
295	if (strlcat(sitepath, "ftp://ftp.freebsd.org", sizeof(sitepath))
296	    >= sizeof(sitepath))
297	    return NULL;
298    }
299
300    if (strlcat(sitepath, "/pub/FreeBSD/ports/", sizeof(sitepath))
301	>= sizeof(sitepath))
302	return NULL;
303
304    uname(&u);
305    if (strlcat(sitepath, u.machine, sizeof(sitepath)) >= sizeof(sitepath))
306	return NULL;
307
308    reldate = getosreldate();
309    for(i = 0; releases[i].directory != NULL; i++) {
310	if (reldate >= releases[i].lowver && reldate <= releases[i].hiver) {
311	    if (strlcat(sitepath, releases[i].directory, sizeof(sitepath))
312		>= sizeof(sitepath))
313		return NULL;
314	    break;
315	}
316    }
317
318    if (strlcat(sitepath, "/Latest/", sizeof(sitepath)) >= sizeof(sitepath))
319	return NULL;
320
321    return sitepath;
322
323}
324
325static void
326usage()
327{
328    fprintf(stderr, "%s\n%s\n",
329	"usage: pkg_add [-vInrfRMSK] [-t template] [-p prefix] [-P prefix] [-C chrootdir]",
330	"               pkg-name [pkg-name ...]");
331    exit(1);
332}
333