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