main.c revision 173513
14Srgrimes/* 24Srgrimes * 34Srgrimes * FreeBSD install - a package for the installation and maintainance 44Srgrimes * of non-core utilities. 54Srgrimes * 64Srgrimes * Redistribution and use in source and binary forms, with or without 74Srgrimes * modification, are permitted provided that the following conditions 84Srgrimes * are met: 94Srgrimes * 1. Redistributions of source code must retain the above copyright 104Srgrimes * notice, this list of conditions and the following disclaimer. 114Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer in the 134Srgrimes * documentation and/or other materials provided with the distribution. 144Srgrimes * 154Srgrimes * Jordan K. Hubbard 164Srgrimes * 18 July 1993 174Srgrimes * 184Srgrimes * This is the add module. 194Srgrimes */ 204Srgrimes 214Srgrimes#include <sys/cdefs.h> 224Srgrimes__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/add/main.c 173513 2007-11-10 09:40:39Z krion $"); 234Srgrimes 244Srgrimes#include <err.h> 254Srgrimes#include <sys/param.h> 264Srgrimes#include <sys/utsname.h> 274Srgrimes#include "lib.h" 284Srgrimes#include "add.h" 294Srgrimes 304Srgrimesstatic char Options[] = "hviIRfFnrp:P:SMt:C:K"; 314Srgrimes 324Srgrimeschar *Prefix = NULL; 334SrgrimesBoolean PrefixRecursive = FALSE; 344Srgrimeschar *Chroot = NULL; 354SrgrimesBoolean NoInstall = FALSE; 364SrgrimesBoolean NoRecord = FALSE; 37621SrgrimesBoolean Remote = FALSE; 38621SrgrimesBoolean KeepPackage = FALSE; 394SrgrimesBoolean FailOnAlreadyInstalled = TRUE; 404SrgrimesBoolean IgnoreDeps = FALSE; 414Srgrimes 424Srgrimeschar *Mode = NULL; 434Srgrimeschar *Owner = NULL; 444Srgrimeschar *Group = NULL; 454Srgrimeschar *PkgName = NULL; 464Srgrimeschar *PkgAddCmd = NULL; 474Srgrimeschar *Directory = NULL; 484Srgrimeschar FirstPen[FILENAME_MAX]; 494Srgrimesadd_mode_t AddMode = NORMAL; 504Srgrimes 514Srgrimeschar **pkgs; 524Srgrimes 534Srgrimesstruct { 544Srgrimes int lowver; /* Lowest version number to match */ 554Srgrimes int hiver; /* Highest version number to match */ 564Srgrimes const char *directory; /* Directory it lives in */ 574Srgrimes} releases[] = { 584Srgrimes { 410000, 410000, "/packages-4.1-release" }, 594Srgrimes { 420000, 420000, "/packages-4.2-release" }, 604Srgrimes { 430000, 430000, "/packages-4.3-release" }, 614Srgrimes { 440000, 440000, "/packages-4.4-release" }, 624Srgrimes { 450000, 450000, "/packages-4.5-release" }, 634Srgrimes { 460000, 460001, "/packages-4.6-release" }, 644Srgrimes { 460002, 460099, "/packages-4.6.2-release" }, 654Srgrimes { 470000, 470099, "/packages-4.7-release" }, 664Srgrimes { 480000, 480099, "/packages-4.8-release" }, 674Srgrimes { 490000, 490099, "/packages-4.9-release" }, 684Srgrimes { 491000, 491099, "/packages-4.10-release" }, 694Srgrimes { 492000, 492099, "/packages-4.11-release" }, 704Srgrimes { 500000, 500099, "/packages-5.0-release" }, 714Srgrimes { 501000, 501099, "/packages-5.1-release" }, 724Srgrimes { 502000, 502009, "/packages-5.2-release" }, 734Srgrimes { 502010, 502099, "/packages-5.2.1-release" }, 744Srgrimes { 503000, 503099, "/packages-5.3-release" }, 754Srgrimes { 504000, 504099, "/packages-5.4-release" }, 764Srgrimes { 505000, 505099, "/packages-5.5-release" }, 774Srgrimes { 600000, 600099, "/packages-6.0-release" }, 784Srgrimes { 601000, 601099, "/packages-6.1-release" }, 794Srgrimes { 602000, 602099, "/packages-6.2-release" }, 804Srgrimes { 300000, 399000, "/packages-3-stable" }, 814Srgrimes { 400000, 499000, "/packages-4-stable" }, 824Srgrimes { 502100, 502128, "/packages-5-current" }, 834Srgrimes { 503100, 599000, "/packages-5-stable" }, 844Srgrimes { 600100, 699000, "/packages-6-stable" }, 854Srgrimes { 700000, 799000, "/packages-7-stable" }, 864Srgrimes { 800000, 899000, "/packages-8-current" }, 874Srgrimes { 0, 9999999, "/packages-current" }, 884Srgrimes { 0, 0, NULL } 894Srgrimes}; 904Srgrimes 914Srgrimesstatic char *getpackagesite(void); 924Srgrimesint getosreldate(void); 934Srgrimes 944Srgrimesstatic void usage(void); 954Srgrimes 964Srgrimesint 974Srgrimesmain(int argc, char **argv) 984Srgrimes{ 994Srgrimes int ch, error; 1004Srgrimes char **start; 1014Srgrimes char *cp, *packagesite = NULL, *remotepkg = NULL, *ptr; 1024Srgrimes static char temppackageroot[MAXPATHLEN]; 1034Srgrimes static char pkgaddpath[MAXPATHLEN]; 1044Srgrimes 1054Srgrimes if (*argv[0] != '/' && strchr(argv[0], '/') != NULL) 1064Srgrimes PkgAddCmd = realpath(argv[0], pkgaddpath); 1074Srgrimes else 1084Srgrimes PkgAddCmd = argv[0]; 1094Srgrimes 1104Srgrimes start = argv; 1114Srgrimes while ((ch = getopt(argc, argv, Options)) != -1) { 1124Srgrimes switch(ch) { 1134Srgrimes case 'v': 1144Srgrimes Verbose++; 1154Srgrimes break; 1164Srgrimes 1174Srgrimes case 'p': 1184Srgrimes Prefix = optarg; 1194Srgrimes PrefixRecursive = FALSE; 1204Srgrimes break; 1214Srgrimes 1224Srgrimes case 'P': 1234Srgrimes Prefix = optarg; 1244Srgrimes PrefixRecursive = TRUE; 1254Srgrimes break; 1264Srgrimes 1274Srgrimes case 'I': 1284Srgrimes NoInstall = TRUE; 1294Srgrimes break; 1304Srgrimes 1314Srgrimes case 'R': 1324Srgrimes NoRecord = TRUE; 1334Srgrimes break; 1344Srgrimes 1354Srgrimes case 'f': 1364Srgrimes Force = TRUE; 1374Srgrimes break; 1384Srgrimes 1394Srgrimes case 'F': 1404Srgrimes FailOnAlreadyInstalled = FALSE; 1414Srgrimes break; 1424Srgrimes 1434Srgrimes case 'K': 1444Srgrimes KeepPackage = TRUE; 1454Srgrimes break; 1464Srgrimes 1474Srgrimes case 'n': 1484Srgrimes Fake = TRUE; 1494Srgrimes break; 1504Srgrimes 1514Srgrimes case 'r': 1524Srgrimes Remote = TRUE; 1534Srgrimes break; 1544Srgrimes 1554Srgrimes case 't': 1564Srgrimes if (strlcpy(FirstPen, optarg, sizeof(FirstPen)) >= sizeof(FirstPen)) 1574Srgrimes errx(1, "-t Argument too long."); 1584Srgrimes break; 1594Srgrimes 1604Srgrimes case 'S': 1614Srgrimes AddMode = SLAVE; 1624Srgrimes break; 1634Srgrimes 1644Srgrimes case 'M': 1654Srgrimes AddMode = MASTER; 1664Srgrimes break; 1674Srgrimes 1684Srgrimes case 'C': 1694Srgrimes Chroot = optarg; 1704Srgrimes break; 1714Srgrimes case 'i': 1724Srgrimes IgnoreDeps = TRUE; 1734Srgrimes break; 1744Srgrimes 1754Srgrimes case 'h': 1764Srgrimes case '?': 1774Srgrimes default: 1784Srgrimes usage(); 1794Srgrimes break; 1804Srgrimes } 1814Srgrimes } 1824Srgrimes argc -= optind; 1834Srgrimes argv += optind; 1844Srgrimes 1854Srgrimes if (AddMode != SLAVE) { 1864Srgrimes pkgs = (char **)malloc((argc+1) * sizeof(char *)); 1874Srgrimes for (ch = 0; ch <= argc; pkgs[ch++] = NULL) ; 1884Srgrimes 1894Srgrimes /* Get all the remaining package names, if any */ 1904Srgrimes for (ch = 0; *argv; ch++, argv++) { 1914Srgrimes char temp[MAXPATHLEN]; 1924Srgrimes if (Remote) { 1934Srgrimes if ((packagesite = getpackagesite()) == NULL) 1944Srgrimes errx(1, "package name too long"); 1954Srgrimes if (strlcpy(temppackageroot, packagesite, 1964Srgrimes sizeof(temppackageroot)) >= sizeof(temppackageroot)) 1974Srgrimes errx(1, "package name too long"); 198 if (strlcat(temppackageroot, *argv, sizeof(temppackageroot)) 199 >= sizeof(temppackageroot)) 200 errx(1, "package name too long"); 201 remotepkg = temppackageroot; 202 if (!((ptr = strrchr(remotepkg, '.')) && ptr[1] == 't' && 203 (ptr[2] == 'b' || ptr[2] == 'g') && ptr[3] == 'z' && 204 !ptr[4])) 205 if (strlcat(remotepkg, 206#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039 207 ".tbz", 208#else 209 ".tgz", 210#endif 211 sizeof(temppackageroot)) >= sizeof(temppackageroot)) 212 errx(1, "package name too long"); 213 } 214 if (!strcmp(*argv, "-")) /* stdin? */ 215 pkgs[ch] = (char *)"-"; 216 else if (isURL(*argv)) { /* preserve URLs */ 217 if (strlcpy(temp, *argv, sizeof(temp)) >= sizeof(temp)) 218 errx(1, "package name too long"); 219 pkgs[ch] = strdup(temp); 220 } 221 else if ((Remote) && isURL(remotepkg)) { 222 if (strlcpy(temp, remotepkg, sizeof(temp)) >= sizeof(temp)) 223 errx(1, "package name too long"); 224 pkgs[ch] = strdup(temp); 225 } else { /* expand all pathnames to fullnames */ 226 if (fexists(*argv)) /* refers to a file directly */ 227 pkgs[ch] = strdup(realpath(*argv, temp)); 228 else { /* look for the file in the expected places */ 229 if (!(cp = fileFindByPath(NULL, *argv))) { 230 /* let pkg_do() fail later, so that error is reported */ 231 if (strlcpy(temp, *argv, sizeof(temp)) >= sizeof(temp)) 232 errx(1, "package name too long"); 233 pkgs[ch] = strdup(temp); 234 } else { 235 if (strlcpy(temp, cp, sizeof(temp)) >= sizeof(temp)) 236 errx(1, "package name too long"); 237 pkgs[ch] = strdup(temp); 238 } 239 } 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 [-viInfFrRMSK] [-t template] [-p prefix] [-P prefix] [-C chrootdir]", 330 " pkg-name [pkg-name ...]"); 331 exit(1); 332} 333