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 environ = NULL; /* Sever the parent environment. */ 376 377 if (vcfile() == 0) { 378 quit(99); 379 } 380 381 errflg = 0; 382 if (mapfile) { 383 /* check for incompatible options */ 384 if (device || pkgcnt) 385 usage(); 386 put_path_params(); /* Restore what's needed. */ 387 388 /* send pathtype if partial path */ 389 pathtype = (ppathlist[0] != NULL) ? 1 : 0; 390 if (checkmap(0, (device != NULL), mapfile, envfile, NULL, 391 NULL, pathtype)) 392 errflg++; 393 } else if (device) { 394 /* check for incompatible options */ 395 if ((cflag >= 0) || (aflag >= 0)) 396 usage(); 397 if (qflag || xflag || nflag || envfile) 398 usage(); 399 tmpdir = NULL; 400 if ((spooldir = devattr(device, "pathname")) == NULL) 401 spooldir = device; 402 if (isdir(spooldir)) { 403 tmpdir = spooldir = qstrdup(tmpnam(NULL)); 404 if (fflag) { 405 logerr(gettext(WRN_F_SPOOL), *pkg); 406 fflag = 0; 407 } 408 if (mkdir(spooldir, 0755)) { 409 progerr(gettext(ERR_MKDIR), spooldir); 410 quit(99); 411 } 412 if (n = pkgtrans(device, spooldir, pkg, PT_SILENT, 413 NULL, NULL)) 414 quit(n); 415 if (catg_arg != NULL) 416 pkg = gpkglist(spooldir, all_pkgs, category); 417 else 418 pkg = gpkglist(spooldir, all_pkgs, NULL); 419 pkgfmt = 0; 420 } else { 421 if (catg_arg != NULL) 422 pkg = gpkglist(spooldir, 423 pkgcnt ? pkg : all_pkgs, category); 424 else 425 pkg = gpkglist(spooldir, 426 pkgcnt ? pkg : all_pkgs, NULL); 427 pkgfmt = 1; 428 } 429 430 /* 431 * At this point pkg[] is the list of packages to check. They 432 * are in directory format in spooldir. 433 */ 434 if (pkg == NULL) { 435 if (catg_arg != NULL) { 436 progerr(gettext(ERR_CAT_FND), catg_arg); 437 quit(1); 438 } else { 439 progerr(gettext(ERR_SEL_PKG)); 440 quit(1); 441 } 442 } 443 444 aflag = 0; 445 446 for (n = 0; pkg[n]; n++) { 447 char locenv[PATH_MAX]; 448 449 /* 450 * ********************************************************************* 451 * this feature is removed starting with Solaris 10 - there is no built 452 * in list of packages that should be run "the old way" 453 * ********************************************************************* 454 */ 455 #ifdef ALLOW_EXCEPTION_PKG_LIST 456 /* Until 2.9, set it from the execption list */ 457 if (exception_pkg(pkg[n], LINK)) 458 set_nonABI_symlinks(); 459 #endif 460 461 if (pkgfmt) 462 (void) printf( 463 gettext(MSG_CHK_DIR), pkg[n], device); 464 else 465 (void) printf( 466 gettext(MSG_CHK_STRM), pkg[n], device); 467 468 (void) snprintf(pkgspool, sizeof (pkgspool), 469 "%s/%s", spooldir, pkg[n]); 470 (void) snprintf(file, sizeof (file), 471 "%s/install", pkgspool); 472 /* Here we check the install scripts. */ 473 (void) printf( 474 gettext("## Checking control scripts.\n")); 475 (void) checkscripts(file, 0); 476 /* Verify consistency with the pkgmap. */ 477 (void) printf( 478 gettext("## Checking package objects.\n")); 479 (void) snprintf(file, sizeof (file), 480 "%s/pkgmap", pkgspool); 481 (void) snprintf(locenv, sizeof (locenv), 482 "%s/pkginfo", pkgspool); 483 envfile = locenv; 484 485 /* 486 * NOTE : checkmap() frees the environ data and 487 * pointer when it's through with them. 488 */ 489 if (checkmap(0, (device != NULL), file, envfile, 490 pkg[n], NULL, 0)) 491 errflg++; 492 (void) printf( 493 gettext("## Checking is complete.\n")); 494 } 495 } else { 496 if (envfile) 497 usage(); 498 499 put_path_params(); /* Restore what's needed. */ 500 501 /* 502 * If this is a check of a client of some sort, we'll need to 503 * mount up the client's filesystems. If the caller isn't 504 * root, this may not be possible. 505 */ 506 if (is_an_inst_root()) { 507 if (getuid()) { 508 logerr(gettext(MSG_NOTROOT)); 509 logerr(gettext(MSG_CONT)); 510 } else { 511 if (get_mntinfo(map_client, vfstab_file)) 512 map_client = 0; 513 if (map_client) 514 mount_client(); 515 } 516 } 517 518 (void) snprintf(file, sizeof (file), 519 "%s/contents", get_PKGADM()); 520 if (ppathlist[0] != NULL) { 521 for (n = 0; ppathlist[n]; n++) { 522 if (checkmap(1, (device != NULL), file, NULL, 523 NULL, ppathlist[n], 1)) 524 errflg++; 525 } 526 } else if (pkg[0] != NULL) { 527 if (checkmap(1, (device != NULL), file, NULL, 528 pkg[0], NULL, 0)) { 529 errflg++; 530 } 531 } else { 532 if (checkmap(1, (device != NULL), file, NULL, 533 NULL, NULL, 0)) { 534 errflg++; 535 } 536 } 537 538 if (map_client) { 539 unmount_client(); 540 } 541 } 542 quit(errflg ? 1 : 0); 543 /* LINTED: no return */ 544 } 545 546 static void 547 setpathlist(char *file) 548 { 549 int fd; 550 struct stat st; 551 FILE *fplist; 552 char pathname[PATH_MAX]; 553 /* 554 * This trap laid to catch a mismatch between the declaration above and 555 * the hard-coded constant in the fscanf below 556 */ 557 #if PATH_MAX != 1024 558 #error "PATH_MAX changed, so we have a bug to fix" 559 #endif 560 561 if (strcmp(file, "-") == 0) { 562 fplist = stdin; 563 } else { 564 if ((fd = open(file, O_RDONLY)) == -1) { 565 progerr(gettext(ERR_IOPEN), file); 566 quit(1); 567 } 568 if (fstat(fd, &st) == -1) { 569 progerr(gettext(ERR_IOPEN), file); 570 quit(1); 571 } 572 if (S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) { 573 progerr(gettext(ERR_PATHS_INVALID), file); 574 quit(1); 575 } 576 if ((fplist = fdopen(fd, "r")) == NULL) { 577 progerr(gettext(ERR_IOPEN), file); 578 quit(1); 579 } 580 } 581 while (fscanf(fplist, "%1024s", pathname) == 1) { 582 if (*pathname == '\0') { 583 progerr(gettext(ERR_PATHS_INVALID), file); 584 quit(1); 585 } 586 pathlist[npaths] = qstrdup(pathname); 587 if (npaths++ > MAXPATHS) { 588 progerr(gettext(ERR_TOO_MANY), MAXPATHS); 589 quit(1); 590 } 591 } 592 if (npaths == 0) { 593 progerr(gettext(ERR_IEMPTY)); 594 quit(1); 595 } 596 (void) fclose(fplist); 597 } 598 599 void 600 quit(int n) 601 { 602 /* cleanup any temporary directories */ 603 (void) chdir("/"); 604 if (tmpdir != NULL) { 605 (void) rrmdir(tmpdir); 606 free(tmpdir); 607 tmpdir = NULL; 608 } 609 (void) pkghead(NULL); 610 exit(n); 611 /*NOTREACHED*/ 612 } 613 614 static void 615 usage(void) 616 { 617 char *prog = get_prog_name(); 618 619 (void) fprintf(stderr, gettext(ERR_USAGE), prog, prog); 620 quit(1); 621 /*NOTREACHED*/ 622 } 623