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
main(int argc,char * argv[])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
setpathlist(char * file)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
quit(int n)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
usage(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