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