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 pathtype; 158 159 /* initialize locale mechanism */ 160 161 (void) setlocale(LC_ALL, ""); 162 163 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 164 #define TEXT_DOMAIN "SYS_TEST" 165 #endif 166 (void) textdomain(TEXT_DOMAIN); 167 168 /* determine program name */ 169 170 prog = set_prog_name(argv[0]); 171 172 /* establish installation root directory */ 173 174 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) { 175 progerr(gettext(ERR_ROOT_SET)); 176 quit(1); 177 } 178 179 /* check if not ABI compliant mode */ 180 abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS"); 181 if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) { 182 set_nonABI_symlinks(); 183 } 184 185 /* bugId 4012147 */ 186 if ((uniTmp = getenv("PKG_NO_UNIFIED")) != NULL) 187 map_client = 0; 188 189 while ((c = getopt(argc, argv, "Y:R:e:p:d:nLli:vaV:Mm:cqxfP:?")) 190 != EOF) { 191 switch (c) { 192 case 'p': 193 pathlist[npaths] = strtok(optarg, " , "); 194 if (pathlist[npaths++] == NULL) { 195 progerr(gettext(ERR_POPTION)); 196 quit(1); 197 } 198 while (pathlist[npaths] = strtok(NULL, " , ")) { 199 if (npaths++ >= MAXPATHS) { 200 progerr(gettext(ERR_MAXPATHS), 201 MAXPATHS); 202 quit(1); 203 } 204 } 205 break; 206 207 case 'd': 208 dvalue = optarg; 209 dflag = 1; 210 break; 211 212 case 'n': 213 nflag++; 214 break; 215 216 case 'M': 217 map_client = 0; 218 break; 219 220 /* 221 * Allow admin to establish the client filesystem using a 222 * vfstab-like file of stable format. 223 */ 224 case 'V': 225 vfstab_file = flex_device(optarg, 2); 226 map_client = 1; 227 break; 228 229 case 'f': 230 if (getuid()) { 231 progerr(gettext(ERR_NOTROOT), prog); 232 quit(1); 233 } 234 fflag++; 235 break; 236 237 case 'i': 238 setpathlist(optarg); 239 break; 240 241 case 'v': 242 vflag++; 243 break; 244 245 case 'l': 246 lflag++; 247 break; 248 249 case 'L': 250 Lflag++; 251 break; 252 253 case 'x': 254 if (aflag < 0) 255 aflag = 0; 256 if (cflag < 0) 257 cflag = 0; 258 xflag++; 259 break; 260 261 case 'q': 262 qflag++; 263 break; 264 265 case 'a': 266 if (cflag < 0) 267 cflag = 0; 268 aflag = 1; 269 break; 270 271 case 'c': 272 if (aflag < 0) 273 aflag = 0; 274 cflag = 1; 275 break; 276 277 case 'e': 278 envfile = optarg; 279 break; 280 281 case 'm': 282 mapfile = optarg; 283 break; 284 285 case 'R': 286 Rvalue = optarg; 287 Rflag = 1; 288 break; 289 290 case 'Y': 291 catg_arg = strdup(optarg); 292 293 if ((category = get_categories(catg_arg)) == NULL) { 294 progerr(gettext(ERR_CAT_INV), catg_arg); 295 quit(1); 296 } else if (is_not_valid_length(category)) { 297 progerr(gettext(ERR_CAT_LNGTH)); 298 quit(1); 299 } 300 break; 301 302 case 'P': 303 ppathlist[npaths] = strtok(optarg, " , "); 304 if ((ppathlist[npaths] == NULL) || 305 (ppathlist[npaths][0] == '-')) { 306 progerr(gettext(ERR_PARTIAL_POPTION)); 307 quit(1); 308 } 309 npaths++; 310 while (ppathlist[npaths] = strtok(NULL, " , ")) { 311 if (npaths++ >= MAXPATHS) { 312 progerr(gettext(ERR_MAXPATHS), 313 MAXPATHS); 314 quit(1); 315 } 316 } 317 break; 318 319 default: 320 usage(); 321 /*NOTREACHED*/ 322 /* 323 * Although usage() calls a noreturn function, 324 * needed to add return (1); so that main() would 325 * pass compilation checks. The statement below 326 * should never be executed. 327 */ 328 return (1); 329 } 330 } 331 332 /* Check for incompatible options */ 333 if (dflag && Rflag) 334 usage(); 335 336 /* Check for root dir and device dir if set */ 337 if (Rflag) { 338 if (!set_inst_root(Rvalue)) { 339 progerr(gettext(ERR_ROOT_CMD)); 340 quit(1); 341 } 342 } 343 344 if (dflag) 345 device = flex_device(dvalue, 1); 346 347 if (lflag || Lflag) { 348 /* we're only supposed to list information */ 349 if ((cflag >= 0) || (aflag >= 0) || 350 qflag || xflag || fflag || nflag || vflag) 351 usage(); 352 } 353 354 set_PKGpaths(get_inst_root()); 355 356 if (catg_arg != NULL && device == NULL) { 357 if (argc - optind) { 358 usage(); 359 } 360 pkg = gpkglist(pkgdir, all_pkgs, category); 361 if (pkg == NULL) { 362 progerr(gettext(ERR_CAT_FND), catg_arg); 363 quit(1); 364 } else { 365 for (pkgcnt = 0; pkg[pkgcnt] != NULL; pkgcnt++) 366 ; 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 quit(n); 417 if (catg_arg != NULL) 418 pkg = gpkglist(spooldir, all_pkgs, category); 419 else 420 pkg = gpkglist(spooldir, all_pkgs, NULL); 421 pkgfmt = 0; 422 } else { 423 if (catg_arg != NULL) 424 pkg = gpkglist(spooldir, 425 pkgcnt ? pkg : all_pkgs, category); 426 else 427 pkg = gpkglist(spooldir, 428 pkgcnt ? pkg : all_pkgs, NULL); 429 pkgfmt = 1; 430 } 431 432 /* 433 * At this point pkg[] is the list of packages to check. They 434 * are in directory format in spooldir. 435 */ 436 if (pkg == NULL) { 437 if (catg_arg != NULL) { 438 progerr(gettext(ERR_CAT_FND), catg_arg); 439 quit(1); 440 } else { 441 progerr(gettext(ERR_SEL_PKG)); 442 quit(1); 443 } 444 } 445 446 aflag = 0; 447 448 for (n = 0; pkg[n]; n++) { 449 char locenv[PATH_MAX]; 450 451 if (pkgfmt) 452 (void) printf( 453 gettext(MSG_CHK_DIR), pkg[n], device); 454 else 455 (void) printf( 456 gettext(MSG_CHK_STRM), pkg[n], device); 457 458 (void) snprintf(pkgspool, sizeof (pkgspool), 459 "%s/%s", spooldir, pkg[n]); 460 (void) snprintf(file, sizeof (file), 461 "%s/install", pkgspool); 462 /* Here we check the install scripts. */ 463 (void) printf( 464 gettext("## Checking control scripts.\n")); 465 (void) checkscripts(file, 0); 466 /* Verify consistency with the pkgmap. */ 467 (void) printf( 468 gettext("## Checking package objects.\n")); 469 (void) snprintf(file, sizeof (file), 470 "%s/pkgmap", pkgspool); 471 (void) snprintf(locenv, sizeof (locenv), 472 "%s/pkginfo", pkgspool); 473 envfile = locenv; 474 475 /* 476 * NOTE : checkmap() frees the environ data and 477 * pointer when it's through with them. 478 */ 479 if (checkmap(0, (device != NULL), file, envfile, 480 pkg[n], NULL, 0)) 481 errflg++; 482 (void) printf( 483 gettext("## Checking is complete.\n")); 484 } 485 } else { 486 if (envfile) 487 usage(); 488 489 put_path_params(); /* Restore what's needed. */ 490 491 /* 492 * If this is a check of a client of some sort, we'll need to 493 * mount up the client's filesystems. If the caller isn't 494 * root, this may not be possible. 495 */ 496 if (is_an_inst_root()) { 497 if (getuid()) { 498 logerr(gettext(MSG_NOTROOT)); 499 logerr(gettext(MSG_CONT)); 500 } else { 501 if (get_mntinfo(map_client, vfstab_file)) 502 map_client = 0; 503 if (map_client) 504 mount_client(); 505 } 506 } 507 508 (void) snprintf(file, sizeof (file), 509 "%s/contents", get_PKGADM()); 510 if (ppathlist[0] != NULL) { 511 for (n = 0; ppathlist[n]; n++) { 512 if (checkmap(1, (device != NULL), file, NULL, 513 NULL, ppathlist[n], 1)) 514 errflg++; 515 } 516 } else if (pkg[0] != NULL) { 517 if (checkmap(1, (device != NULL), file, NULL, 518 pkg[0], NULL, 0)) { 519 errflg++; 520 } 521 } else { 522 if (checkmap(1, (device != NULL), file, NULL, 523 NULL, NULL, 0)) { 524 errflg++; 525 } 526 } 527 528 if (map_client) { 529 unmount_client(); 530 } 531 } 532 quit(errflg ? 1 : 0); 533 /* LINTED: no return */ 534 } 535 536 static void 537 setpathlist(char *file) 538 { 539 int fd; 540 struct stat st; 541 FILE *fplist; 542 char pathname[PATH_MAX]; 543 /* 544 * This trap laid to catch a mismatch between the declaration above and 545 * the hard-coded constant in the fscanf below 546 */ 547 #if PATH_MAX != 1024 548 #error "PATH_MAX changed, so we have a bug to fix" 549 #endif 550 551 if (strcmp(file, "-") == 0) { 552 fplist = stdin; 553 } else { 554 if ((fd = open(file, O_RDONLY)) == -1) { 555 progerr(gettext(ERR_IOPEN), file); 556 quit(1); 557 } 558 if (fstat(fd, &st) == -1) { 559 progerr(gettext(ERR_IOPEN), file); 560 quit(1); 561 } 562 if (S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) { 563 progerr(gettext(ERR_PATHS_INVALID), file); 564 quit(1); 565 } 566 if ((fplist = fdopen(fd, "r")) == NULL) { 567 progerr(gettext(ERR_IOPEN), file); 568 quit(1); 569 } 570 } 571 while (fscanf(fplist, "%1024s", pathname) == 1) { 572 if (*pathname == '\0') { 573 progerr(gettext(ERR_PATHS_INVALID), file); 574 quit(1); 575 } 576 pathlist[npaths] = qstrdup(pathname); 577 if (npaths++ > MAXPATHS) { 578 progerr(gettext(ERR_TOO_MANY), MAXPATHS); 579 quit(1); 580 } 581 } 582 if (npaths == 0) { 583 progerr(gettext(ERR_IEMPTY)); 584 quit(1); 585 } 586 (void) fclose(fplist); 587 } 588 589 void 590 quit(int n) 591 { 592 /* cleanup any temporary directories */ 593 (void) chdir("/"); 594 if (tmpdir != NULL) { 595 (void) rrmdir(tmpdir); 596 free(tmpdir); 597 tmpdir = NULL; 598 } 599 (void) pkghead(NULL); 600 exit(n); 601 /*NOTREACHED*/ 602 } 603 604 static void 605 usage(void) 606 { 607 char *prog = get_prog_name(); 608 609 (void) fprintf(stderr, gettext(ERR_USAGE), prog, prog); 610 quit(1); 611 /*NOTREACHED*/ 612 } 613