1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #include <stdio.h> 32 #include <limits.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <dirent.h> 38 #include <sys/stat.h> 39 #include <pkginfo.h> 40 #include <pkglocs.h> 41 #include <sys/types.h> 42 #include <pkgstrct.h> 43 #include <pkgtrans.h> 44 #include <locale.h> 45 #include <libintl.h> 46 #include <pkglib.h> 47 #include <libadm.h> 48 #include <libinst.h> 49 50 #define MAXPATHS 1024 51 52 #define MSG_CHK_STRM "Checking uninstalled stream format package " \ 53 "<%s> from <%s>\n" 54 #define MSG_CHK_DIR "Checking uninstalled directory format package " \ 55 "<%s> from <%s>\n" 56 #define MSG_NOTROOT "NOTE: \"root\" permission may be required to " \ 57 "validate all objects in the client filesystem." 58 #define MSG_CONT "Continuing." 59 60 #define WRN_F_SPOOL "WARNING: %s is spooled. Ignoring \"f\" argument" 61 62 #define ERR_ROOT_SET "Could not set install root from the environment." 63 #define ERR_ROOT_CMD "Command line install root contends with environment." 64 #define ERR_IOPEN "unable to open input file <%s>" 65 #define ERR_IEMPTY "no pathnames in file specified by -i option" 66 #define ERR_POPTION "no pathname included with -p option" 67 #define ERR_PARTIAL_POPTION "no pathname included with -P option" 68 #define ERR_MAXPATHS "too many pathnames in option list (limit is %d)" 69 #define ERR_NOTROOT "You must be \"root\" for \"%s -f\" to" \ 70 "execute properly." 71 #define ERR_SEL_PKG "No packages selected for verification." 72 #define ERR_CAT_LNGTH "The category argument exceeds the SVr4 ABI\n" \ 73 " defined maximum supported length of 16 characters." 74 #define ERR_CAT_FND "Category argument <%s> cannot be found." 75 #define ERR_CAT_INV "Category argument <%s> is invalid." 76 #define ERR_TOO_MANY "too many pathnames in list, limit is %d" 77 #define ERR_PATHS_INVALID "Pathnames in %s are not valid." 78 #define ERR_MKDIR "unable to make directory <%s>" 79 #define ERR_USAGE "usage:\n" \ 80 "\t%s [-l|vqacnxf] [-R rootdir] [-p path[, ...] | " \ 81 "-P path[, ...]]\n" \ 82 "\t\t[-i file] [options]\n" \ 83 "\t%s -d device [-f][-l|v] [-p path[, ...] | " \ 84 "-P path[, ...]]\n" \ 85 "\t\t[-V ...] [-M] [-i file] [-Y category[, ...] | " \ 86 "pkginst [...]]\n" \ 87 "\twhere options may include ONE of the " \ 88 "following:\n " \ 89 "\t\t-m pkgmap [-e envfile]\n" \ 90 "\t\tpkginst [...]\n" \ 91 "\t\t-Y category[, ...]\n" 92 93 #define LINK 1 94 95 char **pkg = NULL; 96 int pkgcnt = 0; 97 char *basedir; 98 char *pathlist[MAXPATHS], *ppathlist[MAXPATHS], pkgspool[PATH_MAX]; 99 short used[MAXPATHS]; 100 short npaths; 101 struct cfent **eptlist; 102 103 int aflag = (-1); 104 int cflag = (-1); 105 int vflag = 0; 106 int nflag = 0; 107 int lflag = 0; 108 int Lflag = 0; 109 int fflag = 0; 110 int xflag = 0; 111 int qflag = 0; 112 int Rflag = 0; 113 int dflag = 0; 114 char *device; 115 116 char *uniTmp; 117 118 static char *mapfile, 119 *spooldir, 120 *tmpdir, 121 *envfile; 122 static int errflg = 0; 123 static int map_client = 1; 124 125 void quit(int); 126 static void setpathlist(char *); 127 static void usage(void); 128 129 extern char **environ; 130 extern char *pkgdir; 131 132 /* checkmap.c */ 133 extern int checkmap(int, int, char *, char *, char *, char *, int); 134 /* scriptvfy.c */ 135 extern int checkscripts(char *inst_dir, int silent); 136 137 int 138 main(int argc, char *argv[]) 139 { 140 int pkgfmt = 0; /* Makes more sense as a pointer, but */ 141 /* 18N is compromised. */ 142 char file[PATH_MAX+1], 143 *abi_sym_ptr, 144 *vfstab_file = NULL; 145 char *all_pkgs[4] = {"all", NULL}; 146 char **category = NULL; 147 char *catg_arg = NULL; 148 int c; 149 int n = 0; 150 char *prog, 151 *Rvalue, 152 *dvalue; 153 int dbcreate = 0; 154 int pathtype; 155 156 /* initialize locale mechanism */ 157 158 (void) setlocale(LC_ALL, ""); 159 160 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 161 #define TEXT_DOMAIN "SYS_TEST" 162 #endif 163 (void) textdomain(TEXT_DOMAIN); 164 165 /* determine program name */ 166 167 prog = set_prog_name(argv[0]); 168 169 /* establish installation root directory */ 170 171 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) { 172 progerr(gettext(ERR_ROOT_SET)); 173 quit(1); 174 } 175 176 /* check if not ABI compliant mode */ 177 abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS"); 178 if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) { 179 set_nonABI_symlinks(); 180 } 181 182 /* bugId 4012147 */ 183 if ((uniTmp = getenv("PKG_NO_UNIFIED")) != NULL) 184 map_client = 0; 185 186 while ((c = getopt(argc, argv, "Y:R:e:p:d:nLli:vaV:Mm:cqxfQP:?")) 187 != EOF) { 188 switch (c) { 189 case 'p': 190 pathlist[npaths] = strtok(optarg, " , "); 191 if (pathlist[npaths++] == NULL) { 192 progerr(gettext(ERR_POPTION)); 193 quit(1); 194 } 195 while (pathlist[npaths] = strtok(NULL, " , ")) { 196 if (npaths++ >= MAXPATHS) { 197 progerr(gettext(ERR_MAXPATHS), 198 MAXPATHS); 199 quit(1); 200 } 201 } 202 break; 203 204 case 'd': 205 dvalue = optarg; 206 dflag = 1; 207 break; 208 209 case 'n': 210 nflag++; 211 break; 212 213 case 'M': 214 map_client = 0; 215 break; 216 217 /* 218 * Allow admin to establish the client filesystem using a 219 * vfstab-like file of stable format. 220 */ 221 case 'V': 222 vfstab_file = flex_device(optarg, 2); 223 map_client = 1; 224 break; 225 226 case 'f': 227 if (getuid()) { 228 progerr(gettext(ERR_NOTROOT), prog); 229 quit(1); 230 } 231 fflag++; 232 break; 233 234 case 'i': 235 setpathlist(optarg); 236 break; 237 238 case 'v': 239 vflag++; 240 break; 241 242 case 'l': 243 lflag++; 244 break; 245 246 case 'L': 247 Lflag++; 248 break; 249 250 case 'x': 251 if (aflag < 0) 252 aflag = 0; 253 if (cflag < 0) 254 cflag = 0; 255 xflag++; 256 break; 257 258 case 'q': 259 qflag++; 260 break; 261 262 case 'a': 263 if (cflag < 0) 264 cflag = 0; 265 aflag = 1; 266 break; 267 268 case 'c': 269 if (aflag < 0) 270 aflag = 0; 271 cflag = 1; 272 break; 273 274 case 'e': 275 envfile = optarg; 276 break; 277 278 case 'm': 279 mapfile = optarg; 280 break; 281 282 case 'R': 283 Rvalue = optarg; 284 Rflag = 1; 285 break; 286 287 case 'Y': 288 catg_arg = strdup(optarg); 289 290 if ((category = get_categories(catg_arg)) == NULL) { 291 progerr(gettext(ERR_CAT_INV), catg_arg); 292 quit(1); 293 } else if (is_not_valid_length(category)) { 294 progerr(gettext(ERR_CAT_LNGTH)); 295 quit(1); 296 } 297 break; 298 299 case 'Q': 300 dbcreate++; 301 break; 302 303 case 'P': 304 ppathlist[npaths] = strtok(optarg, " , "); 305 if ((ppathlist[npaths] == NULL) || 306 (ppathlist[npaths][0] == '-')) { 307 progerr(gettext(ERR_PARTIAL_POPTION)); 308 quit(1); 309 } 310 npaths++; 311 while (ppathlist[npaths] = strtok(NULL, " , ")) { 312 if (npaths++ >= MAXPATHS) { 313 progerr(gettext(ERR_MAXPATHS), 314 MAXPATHS); 315 quit(1); 316 } 317 } 318 break; 319 320 default: 321 usage(); 322 /*NOTREACHED*/ 323 /* 324 * Although usage() calls a noreturn function, 325 * needed to add return (1); so that main() would 326 * pass compilation checks. The statement below 327 * should never be executed. 328 */ 329 return (1); 330 } 331 } 332 333 /* Check for incompatible options */ 334 if (dflag && Rflag) 335 usage(); 336 337 /* Check for root dir and device dir if set */ 338 if (Rflag) { 339 if (!set_inst_root(Rvalue)) { 340 progerr(gettext(ERR_ROOT_CMD)); 341 quit(1); 342 } 343 } 344 345 if (dflag) 346 device = flex_device(dvalue, 1); 347 348 if (lflag || Lflag) { 349 /* we're only supposed to list information */ 350 if ((cflag >= 0) || (aflag >= 0) || 351 qflag || xflag || fflag || nflag || vflag) 352 usage(); 353 } 354 355 set_PKGpaths(get_inst_root()); 356 357 if (catg_arg != NULL && device == NULL) { 358 if (argc - optind) { 359 usage(); 360 } 361 pkg = gpkglist(pkgdir, all_pkgs, category); 362 if (pkg == NULL) { 363 progerr(gettext(ERR_CAT_FND), catg_arg); 364 quit(1); 365 } else { 366 for (pkgcnt = 0; pkg[pkgcnt] != NULL; pkgcnt++); 367 } 368 } else if (catg_arg != NULL && optind < argc) { 369 usage(); 370 } else { 371 pkg = &argv[optind]; 372 pkgcnt = (argc - optind); 373 } 374 375 /* read the environment for the pkgserver */ 376 pkgserversetmode(DEFAULTMODE); 377 378 environ = NULL; /* Sever the parent environment. */ 379 380 if (vcfile() == 0) { 381 quit(99); 382 } 383 384 errflg = 0; 385 if (mapfile) { 386 /* check for incompatible options */ 387 if (device || pkgcnt) 388 usage(); 389 put_path_params(); /* Restore what's needed. */ 390 391 /* send pathtype if partial path */ 392 pathtype = (ppathlist[0] != NULL) ? 1 : 0; 393 if (checkmap(0, (device != NULL), mapfile, envfile, NULL, 394 NULL, pathtype)) 395 errflg++; 396 } else if (device) { 397 /* check for incompatible options */ 398 if ((cflag >= 0) || (aflag >= 0)) 399 usage(); 400 if (qflag || xflag || nflag || envfile) 401 usage(); 402 tmpdir = NULL; 403 if ((spooldir = devattr(device, "pathname")) == NULL) 404 spooldir = device; 405 if (isdir(spooldir)) { 406 tmpdir = spooldir = qstrdup(tmpnam(NULL)); 407 if (fflag) { 408 logerr(gettext(WRN_F_SPOOL), *pkg); 409 fflag = 0; 410 } 411 if (mkdir(spooldir, 0755)) { 412 progerr(gettext(ERR_MKDIR), spooldir); 413 quit(99); 414 } 415 if (n = pkgtrans(device, spooldir, pkg, PT_SILENT, 416 NULL, NULL)) 417 quit(n); 418 if (catg_arg != NULL) 419 pkg = gpkglist(spooldir, all_pkgs, category); 420 else 421 pkg = gpkglist(spooldir, all_pkgs, NULL); 422 pkgfmt = 0; 423 } else { 424 if (catg_arg != NULL) 425 pkg = gpkglist(spooldir, 426 pkgcnt ? pkg : all_pkgs, category); 427 else 428 pkg = gpkglist(spooldir, 429 pkgcnt ? pkg : all_pkgs, NULL); 430 pkgfmt = 1; 431 } 432 433 /* 434 * At this point pkg[] is the list of packages to check. They 435 * are in directory format in spooldir. 436 */ 437 if (pkg == NULL) { 438 if (catg_arg != NULL) { 439 progerr(gettext(ERR_CAT_FND), catg_arg); 440 quit(1); 441 } else { 442 progerr(gettext(ERR_SEL_PKG)); 443 quit(1); 444 } 445 } 446 447 aflag = 0; 448 449 for (n = 0; pkg[n]; n++) { 450 char locenv[PATH_MAX]; 451 452 /* 453 * ********************************************************************* 454 * this feature is removed starting with Solaris 10 - there is no built 455 * in list of packages that should be run "the old way" 456 * ********************************************************************* 457 */ 458 #ifdef ALLOW_EXCEPTION_PKG_LIST 459 /* Until 2.9, set it from the execption list */ 460 if (exception_pkg(pkg[n], LINK)) 461 set_nonABI_symlinks(); 462 #endif 463 464 if (pkgfmt) 465 (void) printf( 466 gettext(MSG_CHK_DIR), pkg[n], device); 467 else 468 (void) printf( 469 gettext(MSG_CHK_STRM), pkg[n], device); 470 471 (void) snprintf(pkgspool, sizeof (pkgspool), 472 "%s/%s", spooldir, pkg[n]); 473 (void) snprintf(file, sizeof (file), 474 "%s/install", pkgspool); 475 /* Here we check the install scripts. */ 476 (void) printf( 477 gettext("## Checking control scripts.\n")); 478 (void) checkscripts(file, 0); 479 /* Verify consistency with the pkgmap. */ 480 (void) printf( 481 gettext("## Checking package objects.\n")); 482 (void) snprintf(file, sizeof (file), 483 "%s/pkgmap", pkgspool); 484 (void) snprintf(locenv, sizeof (locenv), 485 "%s/pkginfo", pkgspool); 486 envfile = locenv; 487 488 /* 489 * NOTE : checkmap() frees the environ data and 490 * pointer when it's through with them. 491 */ 492 if (checkmap(0, (device != NULL), file, envfile, 493 pkg[n], NULL, 0)) 494 errflg++; 495 (void) printf( 496 gettext("## Checking is complete.\n")); 497 } 498 } else { 499 if (envfile) 500 usage(); 501 502 put_path_params(); /* Restore what's needed. */ 503 504 /* 505 * If this is a check of a client of some sort, we'll need to 506 * mount up the client's filesystems. If the caller isn't 507 * root, this may not be possible. 508 */ 509 if (is_an_inst_root()) { 510 if (getuid()) { 511 logerr(gettext(MSG_NOTROOT)); 512 logerr(gettext(MSG_CONT)); 513 } else { 514 if (get_mntinfo(map_client, vfstab_file)) 515 map_client = 0; 516 if (map_client) 517 mount_client(); 518 } 519 } 520 521 (void) snprintf(file, sizeof (file), 522 "%s/contents", get_PKGADM()); 523 if (ppathlist[0] != NULL) { 524 for (n = 0; ppathlist[n]; n++) { 525 if (checkmap(1, (device != NULL), file, NULL, 526 NULL, ppathlist[n], 1)) 527 errflg++; 528 } 529 } else if (pkg[0] != NULL) { 530 if (checkmap(1, (device != NULL), file, NULL, 531 pkg[0], NULL, 0)) { 532 errflg++; 533 } 534 } else { 535 if (checkmap(1, (device != NULL), file, NULL, 536 NULL, NULL, 0)) { 537 errflg++; 538 } 539 } 540 541 if (map_client) { 542 unmount_client(); 543 } 544 } 545 quit(errflg ? 1 : 0); 546 /* LINTED: no return */ 547 } 548 549 static void 550 setpathlist(char *file) 551 { 552 int fd; 553 struct stat st; 554 FILE *fplist; 555 char pathname[PATH_MAX]; 556 /* 557 * This trap laid to catch a mismatch between the declaration above and 558 * the hard-coded constant in the fscanf below 559 */ 560 #if PATH_MAX != 1024 561 #error "PATH_MAX changed, so we have a bug to fix" 562 #endif 563 564 if (strcmp(file, "-") == 0) { 565 fplist = stdin; 566 } else { 567 if ((fd = open(file, O_RDONLY)) == -1) { 568 progerr(gettext(ERR_IOPEN), file); 569 quit(1); 570 } 571 if (fstat(fd, &st) == -1) { 572 progerr(gettext(ERR_IOPEN), file); 573 quit(1); 574 } 575 if (S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) { 576 progerr(gettext(ERR_PATHS_INVALID), file); 577 quit(1); 578 } 579 if ((fplist = fdopen(fd, "r")) == NULL) { 580 progerr(gettext(ERR_IOPEN), file); 581 quit(1); 582 } 583 } 584 while (fscanf(fplist, "%1024s", pathname) == 1) { 585 if (*pathname == '\0') { 586 progerr(gettext(ERR_PATHS_INVALID), file); 587 quit(1); 588 } 589 pathlist[npaths] = qstrdup(pathname); 590 if (npaths++ > MAXPATHS) { 591 progerr(gettext(ERR_TOO_MANY), MAXPATHS); 592 quit(1); 593 } 594 } 595 if (npaths == 0) { 596 progerr(gettext(ERR_IEMPTY)); 597 quit(1); 598 } 599 (void) fclose(fplist); 600 } 601 602 void 603 quit(int n) 604 { 605 /* cleanup any temporary directories */ 606 (void) chdir("/"); 607 if (tmpdir != NULL) { 608 (void) rrmdir(tmpdir); 609 free(tmpdir); 610 tmpdir = NULL; 611 } 612 (void) pkghead(NULL); 613 exit(n); 614 /*NOTREACHED*/ 615 } 616 617 static void 618 usage(void) 619 { 620 char *prog = get_prog_name(); 621 622 (void) fprintf(stderr, gettext(ERR_USAGE), prog, prog); 623 quit(1); 624 /*NOTREACHED*/ 625 } 626