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