main.c revision 162663
12089Ssos/*
216565Ssos *
32089Ssos * FreeBSD install - a package for the installation and maintainance
42089Ssos * of non-core utilities.
5146736Sdelphij *
6146736Sdelphij * Redistribution and use in source and binary forms, with or without
7146736Sdelphij * modification, are permitted provided that the following conditions
82089Ssos * are met:
92089Ssos * 1. Redistributions of source code must retain the above copyright
102089Ssos *    notice, this list of conditions and the following disclaimer.
112089Ssos * 2. Redistributions in binary form must reproduce the above copyright
125994Ssos *    notice, this list of conditions and the following disclaimer in the
135994Ssos *    documentation and/or other materials provided with the distribution.
142089Ssos *
152089Ssos * Jordan K. Hubbard
162089Ssos * 18 July 1993
172089Ssos *
1897748Sschweikh * This is the add module.
192089Ssos */
202089Ssos
212089Ssos#include <sys/cdefs.h>
222089Ssos__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/add/main.c 162663 2006-09-26 14:51:33Z kensmith $");
232089Ssos
242089Ssos#include <err.h>
252089Ssos#include <sys/param.h>
262089Ssos#include <sys/utsname.h>
272089Ssos#include "lib.h"
282089Ssos#include "add.h"
292089Ssos
30146736Sdelphijstatic char Options[] = "hvIRfFnrp:P:SMt:C:K";
31146736Sdelphij
322089Ssoschar	*Prefix		= NULL;
332089SsosBoolean	PrefixRecursive	= FALSE;
3430764Scharnierchar	*Chroot		= NULL;
3530764ScharnierBoolean	NoInstall	= FALSE;
3650479SpeterBoolean	NoRecord	= FALSE;
3730764ScharnierBoolean Remote		= FALSE;
3830764ScharnierBoolean KeepPackage	= FALSE;
392089SsosBoolean FailOnAlreadyInstalled	= TRUE;
4030764Scharnier
4155849Syokotachar	*Mode		= NULL;
422089Ssoschar	*Owner		= NULL;
4323457Sbrianchar	*Group		= NULL;
4430764Scharnierchar	*PkgName	= NULL;
4523702Speterchar	*PkgAddCmd	= NULL;
4666834Sphkchar	*Directory	= NULL;
4766834Sphkchar	FirstPen[FILENAME_MAX];
482089Ssosadd_mode_t AddMode	= NORMAL;
4975344Ssobomax
5075344Ssobomax#define MAX_PKGS	200
512089Ssoschar	pkgnames[MAX_PKGS][MAXPATHLEN];
5223457Sbrianchar	*pkgs[MAX_PKGS];
532089Ssos
5471642Ssobomaxstruct {
55146736Sdelphij	int lowver;	/* Lowest version number to match */
56146736Sdelphij	int hiver;	/* Highest version number to match */
57102111Ssobomax	const char *directory;	/* Directory it lives in */
58102111Ssobomax} releases[] = {
59102111Ssobomax	{ 410000, 410000, "/packages-4.1-release" },
60102111Ssobomax	{ 420000, 420000, "/packages-4.2-release" },
61102111Ssobomax	{ 430000, 430000, "/packages-4.3-release" },
62102111Ssobomax	{ 440000, 440000, "/packages-4.4-release" },
63102111Ssobomax	{ 450000, 450000, "/packages-4.5-release" },
6476845Ssobomax	{ 460000, 460001, "/packages-4.6-release" },
6576845Ssobomax	{ 460002, 460099, "/packages-4.6.2-release" },
662089Ssos	{ 470000, 470099, "/packages-4.7-release" },
672089Ssos	{ 480000, 480099, "/packages-4.8-release" },
682089Ssos	{ 490000, 490099, "/packages-4.9-release" },
692089Ssos	{ 491000, 491099, "/packages-4.10-release" },
702089Ssos	{ 492000, 492099, "/packages-4.11-release" },
716628Ssos	{ 500000, 500099, "/packages-5.0-release" },
722089Ssos	{ 501000, 501099, "/packages-5.1-release" },
73146736Sdelphij	{ 502000, 502009, "/packages-5.2-release" },
74146736Sdelphij	{ 502010, 502099, "/packages-5.2.1-release" },
75146736Sdelphij	{ 503000, 503099, "/packages-5.3-release" },
76146736Sdelphij	{ 504000, 504099, "/packages-5.4-release" },
77146736Sdelphij	{ 505000, 505099, "/packages-5.5-release" },
78146736Sdelphij	{ 600000, 600099, "/packages-6.0-release" },
79146736Sdelphij	{ 601000, 601099, "/packages-6.1-release" },
802089Ssos	{ 602000, 602099, "/packages-6.2-release" },
81146736Sdelphij	{ 300000, 399000, "/packages-3-stable" },
82146736Sdelphij	{ 400000, 499000, "/packages-4-stable" },
83146736Sdelphij	{ 502100, 502128, "/packages-5-current" },
84146736Sdelphij	{ 503100, 599000, "/packages-5-stable" },
85146736Sdelphij	{ 600100, 699000, "/packages-6-stable" },
86146736Sdelphij	{ 700000, 799000, "/packages-7-current" },
87146736Sdelphij	{ 0, 9999999, "/packages-current" },
88146736Sdelphij	{ 0, 0, NULL }
89146736Sdelphij};
90146736Sdelphij
91146736Sdelphijstatic char *getpackagesite(void);
92146736Sdelphijint getosreldate(void);
93146736Sdelphij
94146736Sdelphijstatic void usage __P((void));
95146736Sdelphij
96146736Sdelphijint
97146736Sdelphijmain(int argc, char **argv)
98146736Sdelphij{
99146736Sdelphij    int ch, error;
100146736Sdelphij    char **start;
101146736Sdelphij    char *cp, *packagesite = NULL, *remotepkg = NULL, *ptr;
102146736Sdelphij    static char temppackageroot[MAXPATHLEN];
103146736Sdelphij    static char pkgaddpath[MAXPATHLEN];
104146736Sdelphij
105146736Sdelphij    if (*argv[0] != '/' && strchr(argv[0], '/') != NULL)
106146736Sdelphij	PkgAddCmd = realpath(argv[0], pkgaddpath);
107146736Sdelphij    else
108146736Sdelphij	PkgAddCmd = argv[0];
10930764Scharnier
110146736Sdelphij    start = argv;
111146736Sdelphij    while ((ch = getopt(argc, argv, Options)) != -1) {
112146736Sdelphij	switch(ch) {
113146736Sdelphij	case 'v':
114146736Sdelphij	    Verbose++;
115146736Sdelphij	    break;
116146736Sdelphij
117146736Sdelphij	case 'p':
118146736Sdelphij	    Prefix = optarg;
119146736Sdelphij	    PrefixRecursive = FALSE;
120146736Sdelphij	    break;
121146736Sdelphij
122146736Sdelphij	case 'P':
123146736Sdelphij	    Prefix = optarg;
124146736Sdelphij	    PrefixRecursive = TRUE;
125146736Sdelphij	    break;
126146736Sdelphij
127146736Sdelphij	case 'I':
128146736Sdelphij	    NoInstall = TRUE;
129146736Sdelphij	    break;
130146736Sdelphij
131146736Sdelphij	case 'R':
132146736Sdelphij	    NoRecord = TRUE;
133146736Sdelphij	    break;
134146736Sdelphij
135146736Sdelphij	case 'f':
136146736Sdelphij	    Force = TRUE;
137146736Sdelphij	    break;
138146736Sdelphij
139146736Sdelphij	case 'F':
140146736Sdelphij	    FailOnAlreadyInstalled = FALSE;
141146736Sdelphij	    break;
142146736Sdelphij
143146736Sdelphij	case 'K':
144146736Sdelphij	    KeepPackage = TRUE;
145146736Sdelphij	    break;
146146736Sdelphij
147146736Sdelphij	case 'n':
148146736Sdelphij	    Fake = TRUE;
149146736Sdelphij	    break;
150146736Sdelphij
151146736Sdelphij	case 'r':
152146736Sdelphij	    Remote = TRUE;
153146736Sdelphij	    break;
154146736Sdelphij
155146736Sdelphij	case 't':
156146736Sdelphij	    if (strlcpy(FirstPen, optarg, sizeof(FirstPen)) >= sizeof(FirstPen))
157146736Sdelphij		errx(1, "-t Argument too long.");
158146736Sdelphij	    break;
159146736Sdelphij
160146736Sdelphij	case 'S':
161146736Sdelphij	    AddMode = SLAVE;
162146736Sdelphij	    break;
163146736Sdelphij
164146736Sdelphij	case 'M':
165146736Sdelphij	    AddMode = MASTER;
166146736Sdelphij	    break;
167146736Sdelphij
168146736Sdelphij	case 'C':
169146736Sdelphij	    Chroot = optarg;
170146736Sdelphij	    break;
171146736Sdelphij
172146736Sdelphij	case 'h':
173146736Sdelphij	case '?':
174146736Sdelphij	default:
175146736Sdelphij	    usage();
176146736Sdelphij	    break;
177146736Sdelphij	}
178146736Sdelphij    }
179146736Sdelphij    argc -= optind;
180146736Sdelphij    argv += optind;
181146736Sdelphij
182140159Sdelphij    if (argc > MAX_PKGS) {
1836628Ssos	errx(1, "too many packages (max %d)", MAX_PKGS);
18499706Sdd    }
185102111Ssobomax
18677329Sdes    if (AddMode != SLAVE) {
18799706Sdd	for (ch = 0; ch < MAX_PKGS; pkgs[ch++] = NULL) ;
18899706Sdd
18999706Sdd	/* Get all the remaining package names, if any */
19030764Scharnier	for (ch = 0; *argv; ch++, argv++) {
1916628Ssos    	    if (Remote) {
1926628Ssos		if ((packagesite = getpackagesite()) == NULL)
193146736Sdelphij		    errx(1, "package name too long");
194146736Sdelphij		if (strlcpy(temppackageroot, packagesite,
195146736Sdelphij		    sizeof(temppackageroot)) >= sizeof(temppackageroot))
196146736Sdelphij		    errx(1, "package name too long");
197146736Sdelphij		if (strlcat(temppackageroot, *argv, sizeof(temppackageroot))
198146736Sdelphij		    >= sizeof(temppackageroot))
199140159Sdelphij		    errx(1, "package name too long");
20075344Ssobomax		remotepkg = temppackageroot;
2012089Ssos		if (!((ptr = strrchr(remotepkg, '.')) && ptr[1] == 't' &&
2022089Ssos			(ptr[2] == 'b' || ptr[2] == 'g') && ptr[3] == 'z' &&
2032089Ssos			!ptr[4]))
204146736Sdelphij		    if (strlcat(remotepkg,
205146736Sdelphij#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039
206146736Sdelphij			".tbz",
20775344Ssobomax#else
208146736Sdelphij			".tgz",
209146736Sdelphij#endif
21075344Ssobomax			sizeof(temppackageroot)) >= sizeof(temppackageroot))
2112089Ssos			errx(1, "package name too long");
2122089Ssos    	    }
213146736Sdelphij	    if (!strcmp(*argv, "-"))	/* stdin? */
214146736Sdelphij		pkgs[ch] = (char *)"-";
215146736Sdelphij	    else if (isURL(*argv)) {  	/* preserve URLs */
216146736Sdelphij		if (strlcpy(pkgnames[ch], *argv, sizeof(pkgnames[ch]))
217146736Sdelphij		    >= sizeof(pkgnames[ch]))
218146736Sdelphij		    errx(1, "package name too long");
219140159Sdelphij		pkgs[ch] = pkgnames[ch];
220140159Sdelphij	    }
2212089Ssos	    else if ((Remote) && isURL(remotepkg)) {
22292460Ssobomax	    	if (strlcpy(pkgnames[ch], remotepkg, sizeof(pkgnames[ch]))
22392460Ssobomax		    >= sizeof(pkgnames[ch]))
2242089Ssos		    errx(1, "package name too long");
22592460Ssobomax		pkgs[ch] = pkgnames[ch];
22692460Ssobomax	    } else {			/* expand all pathnames to fullnames */
22792460Ssobomax		if (fexists(*argv)) /* refers to a file directly */
22892460Ssobomax		    pkgs[ch] = realpath(*argv, pkgnames[ch]);
229146736Sdelphij		else {		/* look for the file in the expected places */
230146736Sdelphij		    if (!(cp = fileFindByPath(NULL, *argv))) {
231146736Sdelphij			/* let pkg_do() fail later, so that error is reported */
23292460Ssobomax			if (strlcpy(pkgnames[ch], *argv, sizeof(pkgnames[ch]))
233146736Sdelphij			    >= sizeof(pkgnames[ch]))
23492460Ssobomax			    errx(1, "package name too long");
23592460Ssobomax			pkgs[ch] = pkgnames[ch];
236146736Sdelphij		    } else {
23792460Ssobomax			if (strlcpy(pkgnames[ch], cp, sizeof(pkgnames[ch]))
23892460Ssobomax			    >= sizeof(pkgnames[ch]))
23992460Ssobomax			    errx(1, "package name too long");
24092460Ssobomax			pkgs[ch] = pkgnames[ch];
24152262Sbillf		    }
24292460Ssobomax		}
2432089Ssos	    }
2442089Ssos	    if (packagesite != NULL)
245146736Sdelphij		packagesite[0] = '\0';
246146736Sdelphij	}
247146736Sdelphij    }
248146736Sdelphij    /* If no packages, yelp */
249146736Sdelphij    else if (!ch) {
250140159Sdelphij	warnx("missing package name(s)");
251140159Sdelphij	usage();
2522089Ssos    }
25392460Ssobomax    else if (ch > 1 && AddMode == MASTER) {
25492460Ssobomax	warnx("only one package name may be specified with master mode");
2552089Ssos	usage();
2562089Ssos    }
257140159Sdelphij    /* Perform chroot if requested */
258140159Sdelphij    if (Chroot != NULL) {
259140159Sdelphij	if (chroot(Chroot))
260140159Sdelphij	    errx(1, "chroot to %s failed", Chroot);
2612089Ssos    }
26292460Ssobomax    /* Make sure the sub-execs we invoke get found */
263146736Sdelphij    setenv("PATH",
2642089Ssos	   "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin",
265146736Sdelphij	   1);
266146736Sdelphij
2672089Ssos    /* Set a reasonable umask */
268146736Sdelphij    umask(022);
2692089Ssos
270146736Sdelphij    if ((error = pkg_perform(pkgs)) != 0) {
27175344Ssobomax	if (Verbose)
2722089Ssos	    warnx("%d package addition(s) failed", error);
273146736Sdelphij	return error;
274146736Sdelphij    }
27530764Scharnier    else
27623457Sbrian	return 0;
277146736Sdelphij}
278146736Sdelphij
2792089Ssosstatic char *
2802089Ssosgetpackagesite(void)
281146736Sdelphij{
282146736Sdelphij    int reldate, i;
283146736Sdelphij    static char sitepath[MAXPATHLEN];
284146736Sdelphij    struct utsname u;
285146736Sdelphij
286146736Sdelphij    if (getenv("PACKAGESITE")) {
28723457Sbrian	if (strlcpy(sitepath, getenv("PACKAGESITE"), sizeof(sitepath))
2882089Ssos	    >= sizeof(sitepath))
2892089Ssos	    return NULL;
290146736Sdelphij	return sitepath;
291146736Sdelphij    }
292146736Sdelphij
293146736Sdelphij    if (getenv("PACKAGEROOT")) {
294146736Sdelphij	if (strlcpy(sitepath, getenv("PACKAGEROOT"), sizeof(sitepath))
295140159Sdelphij	    >= sizeof(sitepath))
296140159Sdelphij	    return NULL;
2972089Ssos    } else {
2986628Ssos	if (strlcat(sitepath, "ftp://ftp.freebsd.org", sizeof(sitepath))
2992089Ssos	    >= sizeof(sitepath))
3002089Ssos	    return NULL;
3012089Ssos    }
3022089Ssos
303146736Sdelphij    if (strlcat(sitepath, "/pub/FreeBSD/ports/", sizeof(sitepath))
304146736Sdelphij	>= sizeof(sitepath))
305146736Sdelphij	return NULL;
306146736Sdelphij
307146736Sdelphij    uname(&u);
3082089Ssos    if (strlcat(sitepath, u.machine, sizeof(sitepath)) >= sizeof(sitepath))
3092089Ssos	return NULL;
310146736Sdelphij
311146736Sdelphij    reldate = getosreldate();
312146736Sdelphij    for(i = 0; releases[i].directory != NULL; i++) {
313146736Sdelphij	if (reldate >= releases[i].lowver && reldate <= releases[i].hiver) {
314146736Sdelphij	    if (strlcat(sitepath, releases[i].directory, sizeof(sitepath))
315140159Sdelphij		>= sizeof(sitepath))
316140159Sdelphij		return NULL;
3172089Ssos	    break;
3182089Ssos	}
319140159Sdelphij    }
3202089Ssos
321146736Sdelphij    if (strlcat(sitepath, "/Latest/", sizeof(sitepath)) >= sizeof(sitepath))
322146736Sdelphij	return NULL;
323146736Sdelphij
3242089Ssos    return sitepath;
3252089Ssos
326140159Sdelphij}
3272089Ssos
328146736Sdelphijstatic void
329146736Sdelphijusage()
3308857Srgrimes{
3312089Ssos    fprintf(stderr, "%s\n%s\n",
3322089Ssos	"usage: pkg_add [-vInrfRMSK] [-t template] [-p prefix] [-P prefix] [-C chrootdir]",
3332089Ssos	"               pkg-name [pkg-name ...]");
3342089Ssos    exit(1);
3352089Ssos}
3362089Ssos