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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26
27 /*
28 * Program: pkgcond
29 *
30 * Function: Implements the package command suite public utility pkgcond(1M)
31 *
32 * Usage: pkgcond [-nv] [-O debug] condition [ argument ]
33 *
34 * command options:
35 * -n - negate results of condition test
36 * -v - verbose output of condition testing
37 *
38 * <condition> may be any one of:
39 * can_add_driver [path]
40 * can_remove_driver [path]
41 * can_update_driver [path]
42 * is_alternative_root [path]
43 * is_boot_environment [path]
44 * is_diskless_client [path]
45 * is_global_zone [path]
46 * is_mounted_miniroot [path]
47 * is_netinstall_image [path]
48 * is_nonglobal_zone [path]
49 * is_path_writable path
50 * is_running_system [path]
51 * is_what [path]
52 * is_whole_root_nonglobal_zone [path]
53 *
54 * <option(s)> are specific to the condition used
55 *
56 * Input: depends on command
57 *
58 * Output: depends on command
59 *
60 * Exit status: If the -n option is not specified:
61 * == 0 - the specified condition is true (or exists).
62 * == 1 - the specified condition is false (or does not exist).
63 * == 2 - command line usage errors (including bad keywords)
64 * == 3 - command failed to perform the test due to a fatal error
65 *
66 * If the -n option is specified:
67 * == 0 - the specified condition is false (or does not exist).
68 * == 1 - the specified condition is true (or exists).
69 * == 2 - command line usage errors (including bad keywords)
70 * == 3 - command failed to perform the test due to a fatal error
71 */
72
73 #include <stdio.h>
74 #include <sys/mnttab.h>
75 #include <sys/mntent.h>
76 #include <stdarg.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <strings.h>
80 #include <fcntl.h>
81 #include <ctype.h>
82 #include <sys/types.h>
83 #include <sys/stat.h>
84 #include <unistd.h>
85 #include <locale.h>
86 #include <errno.h>
87 #include <sys/param.h>
88 #include <assert.h>
89
90 #include <instzones_api.h>
91 #include <pkglib.h>
92 #include <install.h>
93 #include <libinst.h>
94 #include <libadm.h>
95 #include <messages.h>
96 #include "pkgcond.h"
97 #include "pkgcond_msgs.h"
98
99 /* Should be defined by cc -D */
100
101 #if !defined(TEXT_DOMAIN)
102 #define TEXT_DOMAIN "SYS_TEST"
103 #endif
104
105 /* commands to execute */
106
107 #define LS_CMD "/usr/bin/ls"
108
109 /*
110 * type definition and "types" for testPath()
111 */
112
113 typedef enum {
114 TEST_EXISTS = 0x01,
115 TEST_NOT_EXISTS = 0x02,
116 TEST_IS_DIRECTORY = 0x04,
117 TEST_IS_FILE = 0x08,
118 TEST_NOT_DIRECTORY = 0x10,
119 TEST_NOT_FILE = 0x20,
120 TEST_IS_SYMBOLIC_LINK = 0x40,
121 TEST_NOT_SYMBOLIC_LINK = 0x80,
122 TEST_GLOBAL_TOKEN_IN_FILE = 0x100
123 } TEST_TYPES;
124
125 /* holds file system info */
126
127 struct fsi_t {
128 char *fsi_mntOptions;
129 char *fsi_fsType;
130 char *fsi_mntPoint;
131 };
132 typedef struct fsi_t FSI_T;
133
134 /* holds parsed global data */
135
136 struct globalData_t {
137 /* initial install: PKG_INIT_INSTALL=true */
138 boolean_t gd_initialInstall;
139 /* global zone install: SUNW_PKG_INSTALL_ZONENAME=global */
140 boolean_t gd_globalZoneInstall;
141 /* non-global zone install: SUNW_PKG_INSTALL_ZONENAME!=global */
142 boolean_t gd_nonglobalZoneInstall;
143 /* non-global zone is in a mounted state */
144 boolean_t inMountedState;
145 /* sorted list of all mounted file systems */
146 FSI_T *gd_fileSystemConfig;
147 /* number of mounted file systems in list */
148 long gd_fileSystemConfigLen;
149 /* current zone name */
150 char *gd_zoneName;
151 /* version of target: PATCH_CLIENT_VERSION */
152 char *gd_patchClientVersion;
153 /* SUNW_PKGCOND_GLOBAL_DATA:parentZone:zoneName */
154 char *gd_parentZoneName;
155 /* SUNW_PKGCOND_GLOBAL_DATA:parentZone:zoneType */
156 char *gd_parentZoneType;
157 /* root path to target: PKG_INSTALL_ROOT */
158 char *gd_installRoot;
159 /* SUNW_PKGCOND_GLOBAL_DATA:currentZone:zoneName */
160 char *gd_currentZoneName;
161 /* SUNW_PKGCOND_GLOBAL_DATA:currentZone:zoneType */
162 char *gd_currentZoneType;
163 /* path provided on command line */
164 char *gd_cmdline_path;
165 };
166 typedef struct globalData_t GLOBALDATA_T;
167
168 /* holds subcommands and their definitions */
169
170 struct cmd_t {
171 char *c_name;
172 char *c_args;
173 int (*c_func)(int argc, char **argv, GLOBALDATA_T *a_gdt);
174 };
175 typedef struct cmd_t CMD_T;
176
177 /* Command function prototypes */
178
179 static int cmd_can_add_driver(int argc, char **argv,
180 GLOBALDATA_T *a_gdt);
181 static int cmd_can_remove_driver(int argc, char **argv,
182 GLOBALDATA_T *a_gdt);
183 static int cmd_can_update_driver(int argc, char **argv,
184 GLOBALDATA_T *a_gdt);
185 static int cmd_is_alternative_root(int argc, char **argv,
186 GLOBALDATA_T *a_gdt);
187 static int cmd_is_boot_environment(int argc, char **argv,
188 GLOBALDATA_T *a_gdt);
189 static int cmd_is_diskless_client(int argc, char **argv,
190 GLOBALDATA_T *a_gdt);
191 static int cmd_is_global_zone(int argc, char **argv,
192 GLOBALDATA_T *a_gdt);
193 static int cmd_is_mounted_miniroot(int argc, char **argv,
194 GLOBALDATA_T *a_gdt);
195 static int cmd_is_netinstall_image(int argc, char **argv,
196 GLOBALDATA_T *a_gdt);
197 static int cmd_is_nonglobal_zone(int argc, char **argv,
198 GLOBALDATA_T *a_gdt);
199 static int cmd_is_path_writable(int argc, char **argv,
200 GLOBALDATA_T *a_gdt);
201 static int cmd_is_running_system(int argc, char **argv,
202 GLOBALDATA_T *a_gdt);
203 static int cmd_is_what(int argc, char **argv,
204 GLOBALDATA_T *a_gdt);
205
206 /* Utility function Prototypes */
207
208 static boolean_t getNegateResults(void);
209 static boolean_t recursionCheck(int *r_recursion, char *a_function);
210 static int adjustResults(int a_result);
211 static int calculateFileSystemConfig(GLOBALDATA_T *a_gdt);
212 static int getRootPath(char **r_rootPath);
213 static int getZoneName(char **r_zoneName);
214 static int mountOptionPresent(char *a_mntOptions, char *a_opt);
215 static int parseGlobalData(char *a_envVar, GLOBALDATA_T **a_gdt);
216 static int resolvePath(char **r_path);
217 static int setRootPath(char *a_path, char *a_envVar,
218 boolean_t a_mustExist);
219 static int testPath(TEST_TYPES a_tt, char *format, ...);
220 static int usage(char *a_format, ...);
221 static int findToken(char *path, char *token);
222 static char *getMountOption(char **p);
223 static void dumpGlobalData(GLOBALDATA_T *a_gdt);
224 static void removeLeadingWhitespace(char **a_str);
225 static void setNegateResults(boolean_t setting);
226 static void setVerbose(boolean_t);
227 static void sortedInsert(FSI_T **r_list, long *a_listSize,
228 char *a_mntPoint, char *a_fsType, char *a_mntOptions);
229 static void setCmdLinePath(char **a_path, char **args,
230 int num_args);
231
232 /* local static data */
233
234 static boolean_t _negateResults = B_FALSE;
235 static char *_rootPath = "/";
236
237 /* define subcommand data structure */
238
239 static CMD_T cmds[] = {
240 { "can_add_driver", " [path]",
241 cmd_can_add_driver },
242 { "can_remove_driver", " [path]",
243 cmd_can_remove_driver },
244 { "can_update_driver", " [path]",
245 cmd_can_update_driver },
246 { "is_alternative_root", " [path]",
247 cmd_is_alternative_root },
248 { "is_boot_environment", " [path]",
249 cmd_is_boot_environment },
250 { "is_diskless_client", " [path]",
251 cmd_is_diskless_client },
252 { "is_global_zone", " [path]",
253 cmd_is_global_zone },
254 { "is_mounted_miniroot", " [path]",
255 cmd_is_mounted_miniroot },
256 { "is_netinstall_image", " [path]",
257 cmd_is_netinstall_image },
258 { "is_nonglobal_zone", " [path]",
259 cmd_is_nonglobal_zone },
260 { "is_path_writable", " path",
261 cmd_is_path_writable },
262 { "is_running_system", " [path]",
263 cmd_is_running_system },
264 { "is_what", " [path]",
265 cmd_is_what },
266 /* last one must be all NULLs */
267 { NULL, NULL, NULL }
268 };
269
270 /*
271 * *****************************************************************************
272 * main
273 * *****************************************************************************
274 */
275
276 /*
277 * Name: main
278 * Description: main processing loop for pkgcond *
279 * Return: 0 - condition is satisfied (true)
280 * 1 - condition is not satisfied (false)
281 * 2 - command line usage errors
282 * 3 - failure to determine condition
283 */
284
285 int
main(int argc,char ** argv)286 main(int argc, char **argv)
287 {
288 GLOBALDATA_T *gdt = NULL;
289 char **newargv;
290 char *p;
291 int cur_cmd;
292 int i;
293 int newargc;
294
295 /* make standard output non-buffered */
296
297 setbuf(stdout, NULL);
298
299 /* set the default text domain for messaging */
300
301 (void) setlocale(LC_ALL, "");
302 (void) textdomain(TEXT_DOMAIN);
303
304 /* remember command name */
305
306 set_prog_name(argv[0]);
307
308 /* tell spmi zones interface how to access package output functions */
309
310 z_set_output_functions(echo, echoDebug, progerr);
311
312 /* set verbose mode if appropriate environment variable is set */
313
314 if (getenv(ENV_VAR_VERBOSE)) {
315 /* same as -v */
316 setVerbose(B_TRUE);
317 }
318
319 /* set debug mode if appropriate environment variable is set */
320
321 if (getenv(ENV_VAR_DEBUG)) {
322 /* same as -O debug */
323
324 /* set sml tracing (sml.c) */
325 smlSetVerbose(B_TRUE);
326
327 /* set log and echo (interactive) message tracing */
328 setVerbose(B_TRUE);
329
330 /* enable echoDebug debugging messages */
331 echoDebugSetFlag(B_TRUE);
332 }
333
334 /* generate usage if no options or arguments specified */
335
336 if (argc <= 1) {
337 (void) usage(MSG_NO_ARGUMENTS_SPECIFIED);
338 return (R_USAGE);
339 }
340
341 /*
342 * process any arguments that can appear before the subcommand
343 */
344
345 while ((i = getopt(argc, argv, ":O:vn?")) != EOF) {
346 switch (i) {
347 /*
348 * Not a public interface: the -O option allows the behavior
349 * of the package tools to be modified. Recognized options:
350 * -> debug
351 * ---> enable debugging output
352 */
353
354 case 'O':
355 for (p = strtok(optarg, ","); p != NULL;
356 p = strtok(NULL, ",")) {
357
358 /* debug - enable all tracing */
359
360 if (strcmp(p, "debug") == 0) {
361 /* set sml tracing */
362 smlSetVerbose(B_TRUE);
363 /* set log/echo tracing */
364 setVerbose(B_TRUE);
365 /* enable debugging messages */
366 echoDebugSetFlag(B_TRUE);
367 continue;
368 }
369
370 progerr(ERR_INVALID_O_OPTION, p);
371 return (adjustResults(R_USAGE));
372 }
373 break;
374
375 /*
376 * Public interface: enable verbose (debug) output.
377 */
378
379 case 'v': /* verbose mode enabled */
380 /* set command tracing only */
381 setVerbose(B_TRUE);
382 break;
383
384 /*
385 * Public interface: negate output results.
386 */
387
388 case 'n':
389 setNegateResults(B_TRUE);
390 break;
391
392 /*
393 * unrecognized option
394 */
395
396 case '?':
397 default:
398 (void) usage(MSG_INVALID_OPTION_SPECIFIED, optopt);
399 return (R_USAGE);
400 }
401 }
402
403 /*
404 * done processing options that can preceed subcommand
405 */
406
407 /* error if no subcommand specified */
408
409 if ((argc-optind) <= 0) {
410 (void) usage(MSG_NO_ARGUMENTS_SPECIFIED);
411 return (R_USAGE);
412 }
413
414 /* parse global data if environment variable set */
415
416 if (parseGlobalData(PKGCOND_GLOBAL_VARIABLE, &gdt) != R_SUCCESS) {
417 log_msg(LOG_MSG_ERR, ERR_CANNOT_USE_GLOBAL_DATA,
418 PKGCOND_GLOBAL_VARIABLE);
419 return (R_ERROR);
420 }
421
422 if (setRootPath(gdt->gd_installRoot,
423 (strcmp(gdt->gd_installRoot, "/") == 0) ? NULL :
424 ENV_VAR_SET, B_TRUE) != R_SUCCESS) {
425 log_msg(LOG_MSG_ERR, ERR_CANNOT_SET_ROOT_PATH,
426 ENV_VAR_PKGROOT);
427 return (R_ERROR);
428 }
429
430 /* set path provided on the command line */
431
432 setCmdLinePath(&(gdt->gd_cmdline_path), argv, argc);
433 echoDebug(DBG_CMDLINE_PATH,
434 gdt->gd_cmdline_path == NULL ? "" : gdt->gd_cmdline_path);
435
436 /* determine how file systems are layered in this zone */
437
438 if (calculateFileSystemConfig(gdt) != R_SUCCESS) {
439 log_msg(LOG_MSG_ERR, ERR_CANNOT_CALC_FS_CONFIG);
440 return (R_ERROR);
441 }
442
443 /* dump global data read in (only if debugging) */
444
445 dumpGlobalData(gdt);
446
447 /* search for specified subcommand and execute if found */
448
449 for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) {
450 if (ci_streq(argv[optind], cmds[cur_cmd].c_name)) {
451 int result;
452
453 /* make subcommand the first option */
454
455 newargc = argc - optind;
456 newargv = argv + optind;
457 opterr = optind = 1; optopt = 0;
458
459
460 /* call subcommand with its own argc/argv */
461
462 result = cmds[cur_cmd].c_func(newargc, newargv, gdt);
463
464 /* process result code and exit */
465
466 result = adjustResults(result);
467 log_msg(LOG_MSG_DEBUG, DBG_RESULTS, result);
468 return (result);
469 }
470 }
471
472 /* subcommand not found - output error message and exit with error */
473
474 log_msg(LOG_MSG_ERR, ERR_BAD_SUB, argv[optind]);
475 (void) usage(MSG_UNRECOGNIZED_CONDITION_SPECIFIED);
476 return (R_USAGE);
477 }
478
479 /*
480 * *****************************************************************************
481 * command implementation functions
482 * *****************************************************************************
483 */
484
485 /*
486 * Name: cmd_is_diskless_client
487 * Description: determine if target is a diskless client
488 * Scope: public
489 * Arguments: argc,argv:
490 * - optional path to target to test
491 * Returns: int
492 * == 0 - success
493 * != 0 - failure
494 * IMPLEMENTATION:
495 * - must not be initial installation to the install root
496 * - must not be installation of a zone
497 * - must not be a whole root non-global zone
498 * - must not be a non-global zone
499 * - must not be a mounted mini-root
500 * - must not be a netinstall image
501 * - must not be a boot environment
502 * - The package "SUNWdclnt" must be installed at "/"
503 * - The root path must not be "/"
504 * - The path "/export/exec/Solaris_\*\/usr" must exist at "/"
505 * - The directory "$ROOTDIR/../templates" must exist
506 */
507
508 static int
cmd_is_diskless_client(int argc,char ** argv,GLOBALDATA_T * a_gdt)509 cmd_is_diskless_client(int argc, char **argv, GLOBALDATA_T *a_gdt)
510 {
511 char *rootPath = NULL;
512 char cmd[MAXPATHLEN+1];
513 int c;
514 int r;
515 int rc;
516 static char *cmdName = "is_diskless_client";
517 static int recursion = 0;
518
519 /* process any command line options */
520
521 while ((c = getopt(argc, argv, ":")) != EOF) {
522 switch (c) {
523 case '\0': /* prevent end-of-loop not reached warning */
524 break;
525 case '?':
526 default:
527 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
528 return (R_USAGE);
529 }
530 }
531
532 /* prevent recursion */
533
534 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
535
536 /*
537 * a diskless client cannot be any of the following
538 */
539
540 /* cannot be non-global zone */
541
542 r = cmd_is_nonglobal_zone(argc, argv, a_gdt);
543
544 /* cannot be mounted miniroot */
545
546 if (r != R_SUCCESS) {
547 r = cmd_is_mounted_miniroot(argc, argv, a_gdt);
548 }
549
550 /* cannot be a netinstall image */
551
552 if (r != R_SUCCESS) {
553 r = cmd_is_netinstall_image(argc, argv, a_gdt);
554 }
555
556 /* cannot be a boot environment */
557
558 if (r != R_SUCCESS) {
559 r = cmd_is_boot_environment(argc, argv, a_gdt);
560 }
561
562 /* no need to guard against recursion any more */
563
564 recursion--;
565
566 /* return failure if any of the preceeding are true */
567
568 switch (r) {
569 case R_SUCCESS:
570 return (R_FAILURE);
571 case R_FAILURE:
572 break;
573 case R_USAGE:
574 case R_ERROR:
575 default:
576 return (r);
577 }
578 }
579
580 /* normalize argc/argv */
581
582 argc -= optind;
583 argv += optind;
584
585 /* error if more than one argument */
586
587 if (argc > 1) {
588 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
589 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
590 return (R_USAGE);
591 }
592
593 /* process root path if first argument present */
594
595 if (argc == 1) {
596 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
597 return (R_ERROR);
598 }
599 }
600
601 /* get current root path */
602
603 r = getRootPath(&rootPath);
604 if (r != R_SUCCESS) {
605 return (r);
606 }
607
608 /* start of command debugging information */
609
610 echoDebug(DBG_ROOTPATH_IS, rootPath);
611
612 /* SUNWdclnt must be installed */
613
614 if (pkgTestInstalled("SUNWdclnt", "/") != B_TRUE) {
615 log_msg(LOG_MSG_DEBUG, DBG_IDLC_PKG_NOT_INSTALLED,
616 rootPath, "SUNWdclnt", "/");
617 return (R_FAILURE);
618 }
619
620 /* - $ROOTDIR must not be "/" */
621
622 if (strcmp(rootPath, "/") == 0) {
623 log_msg(LOG_MSG_DEBUG, DBG_IDLC_ROOTPATH_BAD, rootPath, "/");
624 return (R_FAILURE);
625 }
626
627 /* - zone name must be global */
628
629 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) {
630 log_msg(LOG_MSG_DEBUG, DBG_IDLC_ZONE_BAD, rootPath,
631 GLOBAL_ZONENAME);
632 return (R_FAILURE);
633 }
634
635 /*
636 * /export/exec/Solaris_"*"/usr must exist;
637 * create ls command to test:
638 * /usr/bin/ls /export/exec/Solaris_"*"/usr
639 */
640
641 (void) snprintf(cmd, sizeof (cmd), "%s %s >/dev/null 2>&1",
642 LS_CMD, "/export/exec/Solaris_*/usr");
643
644 /* execute command */
645
646 rc = system(cmd);
647
648 /* return error if ls returns something other than "0" */
649
650 if (rc != 0) {
651 log_msg(LOG_MSG_DEBUG, DBG_IDLC_PATH_MISSING,
652 rootPath, "/export/exec/Solaris_*/usr");
653 return (R_FAILURE);
654 }
655
656 /*
657 * /usr must be empty on a diskless client:
658 * create ls command to test:
659 * /usr/bin/ls -d1 $ROOTDIR/usr/\*
660 */
661 (void) snprintf(cmd, sizeof (cmd), "%s %s %s/%s >/dev/null 2>&1",
662 LS_CMD, "-1d", rootPath, "usr/*");
663
664 /* execute command */
665
666 rc = system(cmd);
667
668 /* return error if ls returns "0" */
669
670 if (rc == 0) {
671 log_msg(LOG_MSG_DEBUG, DBG_IDLC_USR_IS_NOT_EMPTY,
672 rootPath);
673 return (R_FAILURE);
674 }
675
676 /* there must be a templates directory at ${ROOTPATH}/../templates */
677
678 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY,
679 "%s/%s", rootPath, "../templates");
680 if (r != R_SUCCESS) {
681 log_msg(LOG_MSG_DEBUG, DBG_IDLC_NO_TEMPLATES_PATH,
682 rootPath, rootPath, "../templates");
683 return (R_FAILURE);
684 }
685
686 /* must not be initial installation to the install root */
687
688 if ((a_gdt->gd_initialInstall == B_TRUE) &&
689 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
690 /* initial install: install root cannot be diskless client */
691 log_msg(LOG_MSG_DEBUG, DBG_IDLC_INITIAL_INSTALL, rootPath);
692 return (R_FAILURE);
693 }
694
695 /* must not be installation of a zone */
696
697 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
698 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
699 /* initial zone install: no path can be diskless client */
700 log_msg(LOG_MSG_DEBUG, DBG_IDLC_ZONE_INSTALL, rootPath);
701 return (R_FAILURE);
702 }
703
704 /* the path is a diskless client */
705
706 log_msg(LOG_MSG_DEBUG, DBG_IDLC_PATH_IS_DISKLESS_CLIENT, rootPath);
707
708 return (R_SUCCESS);
709 }
710
711 /*
712 * Name: cmd_is_global_zone
713 * Description: determine if target is a global zone
714 * Scope: public
715 * Arguments: argc,argv:
716 * - optional path to target to test
717 * Returns: int
718 * == 0 - success
719 * != 0 - failure
720 * IMPLEMENTATION:
721 * - must not be initial installation to the install root
722 * - must not be installation of a non-global zone
723 * - must not be a non-global zone
724 * - must not be a mounted mini-root
725 * - must not be a netinstall image
726 * - must not be a diskless client
727 * - if $ROOTDIR is "/":
728 * -- if zone name is "GLOBAL", then is a global zone;
729 * -- else not a global zone.
730 * - $ROOTDIR/etc/zones must exist and be a directory
731 * - $ROOTDIR/.tmp_proto must not exist
732 * - $ROOTDIR/var must exist and must not be a symbolic link
733 */
734
735 static int
cmd_is_global_zone(int argc,char ** argv,GLOBALDATA_T * a_gdt)736 cmd_is_global_zone(int argc, char **argv, GLOBALDATA_T *a_gdt)
737 {
738 char *rootPath = NULL;
739 int c;
740 int r;
741 static char *cmdName = "is_global_zone";
742 static int recursion = 0;
743
744 /* process any command line options */
745
746 while ((c = getopt(argc, argv, ":")) != EOF) {
747 switch (c) {
748 case '\0': /* prevent end-of-loop not reached warning */
749 break;
750 case '?':
751 default:
752 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
753 return (R_USAGE);
754 }
755 }
756
757 /* prevent recursion */
758
759 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
760
761 /*
762 * a global zone cannot be any of the following
763 */
764
765 /* cannot be a non-global zone */
766
767 r = cmd_is_nonglobal_zone(argc, argv, a_gdt);
768
769 /* cannot be a mounted miniroot */
770
771 if (r != R_SUCCESS) {
772 r = cmd_is_mounted_miniroot(argc, argv, a_gdt);
773 }
774
775 /* cannot be a netinstall image */
776
777 if (r != R_SUCCESS) {
778 r = cmd_is_netinstall_image(argc, argv, a_gdt);
779 }
780
781 /* cannot be a diskless client */
782
783 if (r != R_SUCCESS) {
784 r = cmd_is_diskless_client(argc, argv, a_gdt);
785 }
786
787 /* no need to guard against recursion any more */
788
789 recursion--;
790
791 /* return failure if any of the preceeding are true */
792
793 switch (r) {
794 case R_SUCCESS:
795 return (R_FAILURE);
796 case R_FAILURE:
797 break;
798 case R_USAGE:
799 case R_ERROR:
800 default:
801 return (r);
802 }
803 }
804
805 /* normalize argc/argv */
806
807 argc -= optind;
808 argv += optind;
809
810 /* error if more than one argument */
811
812 if (argc > 1) {
813 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
814 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
815 return (R_USAGE);
816 }
817
818 /* process root path if first argument present */
819
820 if (argc == 1) {
821 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
822 return (R_ERROR);
823 }
824 }
825
826 /* get current root path */
827
828 r = getRootPath(&rootPath);
829 if (r != R_SUCCESS) {
830 return (r);
831 }
832
833 /* start of command debugging information */
834
835 echoDebug(DBG_ROOTPATH_IS, rootPath);
836
837 /* must not be initial installation to the install root */
838
839 if ((a_gdt->gd_initialInstall == B_TRUE) &&
840 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
841 /* initial install: install root cannot be global zone */
842 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_INITIAL_INSTALL, rootPath);
843 return (R_FAILURE);
844 }
845
846 /* must not be installation of a non-global zone */
847
848 if (a_gdt->gd_nonglobalZoneInstall == B_TRUE) {
849 /* initial nonglobal zone install: no path can be global zone */
850 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_NGZ_ZONE_INSTALL, rootPath);
851 return (R_FAILURE);
852 }
853
854 /* handle if global zone installation to the install root */
855
856 if ((a_gdt->gd_globalZoneInstall == B_TRUE) &&
857 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
858 /* the path is a global zone */
859
860 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE,
861 rootPath);
862
863 return (R_SUCCESS);
864 }
865
866 /* true if current root is "/" and zone name is GLOBAL_ZONENAME */
867
868 if (strcmp(rootPath, "/") == 0) {
869 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) {
870 /* the path is a global zone */
871
872 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE,
873 rootPath);
874
875 return (R_SUCCESS);
876 }
877
878 /* inside a non-global zone */
879
880 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_ZONENAME_ISNT_GLOBAL,
881 rootPath, a_gdt->gd_zoneName);
882
883 return (R_FAILURE);
884 }
885
886 /*
887 * current root is not "/" - see if target looks like a global zone
888 *
889 * - rootpath is not "/"
890 * - and $ROOTDIR/etc/zones exists
891 * - and $ROOTDIR/.tmp_proto does not exist
892 * - and $ROOTDIR/var is not a symbolic link
893 */
894
895 /* not global zone if /etc/zones does not exist */
896
897 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY,
898 "%s/%s", rootPath, "/etc/zones");
899 if (r != R_SUCCESS) {
900 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_ISNT_DIRECTORY,
901 rootPath, "/etc/zones");
902 return (R_FAILURE);
903 }
904
905 /* .tmp_proto must not exist */
906
907 r = testPath(TEST_NOT_EXISTS,
908 "%s/%s", rootPath, ".tmp_proto");
909 if (r != R_SUCCESS) {
910 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_EXISTS,
911 rootPath, "/.tmp_proto");
912 return (R_FAILURE);
913 }
914
915 /* /var must not be a symbolic link */
916
917 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
918 "%s/%s", rootPath, "/var");
919 if (r != R_SUCCESS) {
920 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_SYMLINK,
921 rootPath, "/var");
922 return (R_FAILURE);
923 }
924
925 /* the path is a global zone */
926
927 log_msg(LOG_MSG_DEBUG, DBG_ISGZ_PATH_IS_GLOBAL_ZONE, rootPath);
928
929 return (R_SUCCESS);
930 }
931
932 /*
933 * Name: cmd_is_netinstall_image
934 * Description: determine if target is a net install image
935 * Scope: public
936 * Arguments: argc,argv:
937 * - optional path to target to test
938 * Returns: int
939 * == 0 - success
940 * != 0 - failure
941 * IMPLEMENTATION:
942 * - must not be initial installation to the install root
943 * - must not be installation of a zone
944 * - must not be a global zone
945 * - must not be a mounted mini-root
946 * - zone name must be "global"
947 * - $ROOTDIR/.tmp_proto must exist and must be a directory
948 * - $ROOTDIR/var must exist and must be a symbolic link
949 * - $ROOTDIR/tmp/kernel must exist and must be a directory
950 * - $ROOTDIR/.tmp_proto/kernel must exist and must be a symbolic link
951 */
952
953 static int
cmd_is_netinstall_image(int argc,char ** argv,GLOBALDATA_T * a_gdt)954 cmd_is_netinstall_image(int argc, char **argv, GLOBALDATA_T *a_gdt)
955 {
956 char *rootPath = NULL;
957 int c;
958 int r;
959 static char *cmdName = "is_netinstall_image";
960 static int recursion = 0;
961
962 /* process any command line options */
963
964 while ((c = getopt(argc, argv, ":")) != EOF) {
965 switch (c) {
966 case '\0': /* prevent end-of-loop not reached warning */
967 break;
968 case '?':
969 default:
970 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
971 return (R_USAGE);
972 }
973 }
974
975 /* prevent recursion */
976
977 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
978
979 /* a netinstall image cannot be a global zone */
980
981 r = cmd_is_global_zone(argc, argv, a_gdt);
982
983 /* no need to guard against recursion any more */
984
985 recursion--;
986
987 switch (r) {
988 case R_SUCCESS:
989 return (R_FAILURE);
990 case R_FAILURE:
991 break;
992 case R_USAGE:
993 case R_ERROR:
994 default:
995 return (r);
996 }
997 }
998
999 /* normalize argc/argv */
1000
1001 argc -= optind;
1002 argv += optind;
1003
1004 /* error if more than one argument */
1005
1006 if (argc > 1) {
1007 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
1008 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
1009 return (R_USAGE);
1010 }
1011
1012 /* process root path if first argument present */
1013
1014 if (argc == 1) {
1015 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
1016 return (R_ERROR);
1017 }
1018 }
1019
1020 /* get current root path */
1021
1022 r = getRootPath(&rootPath);
1023 if (r != R_SUCCESS) {
1024 return (r);
1025 }
1026
1027 /* start of command debugging information */
1028
1029 echoDebug(DBG_ROOTPATH_IS, rootPath);
1030
1031 /* current zone name must be "global" */
1032
1033 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) {
1034 log_msg(LOG_MSG_DEBUG, DBG_INIM_BAD_CURRENT_ZONE,
1035 rootPath, GLOBAL_ZONENAME);
1036 return (R_FAILURE);
1037 }
1038
1039 /* cannot be a mounted_miniroot */
1040
1041 if (cmd_is_mounted_miniroot(argc, argv, a_gdt) == R_SUCCESS) {
1042 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_IS_MOUNTED_MINIROOT,
1043 rootPath);
1044 return (R_FAILURE);
1045 }
1046
1047 /* $ROOTDIR/.tmp_proto exists */
1048
1049 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY,
1050 "%s/%s", rootPath, ".tmp_proto");
1051 if (r != R_SUCCESS) {
1052 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_DIRECTORY,
1053 rootPath, "/.tmp_proto");
1054 return (R_FAILURE);
1055 }
1056
1057 /* $ROOTDIR/var is a symbolic link */
1058
1059 r = testPath(TEST_IS_SYMBOLIC_LINK,
1060 "%s/%s", rootPath, "/var");
1061 if (r != R_SUCCESS) {
1062 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_SYMLINK,
1063 rootPath, "/var");
1064 return (R_FAILURE);
1065 }
1066
1067 /* $ROOTDIR/tmp/kernel does exist */
1068
1069 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY,
1070 "%s/%s", rootPath, "/tmp/kernel");
1071 if (r != R_SUCCESS) {
1072 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_DIRECTORY,
1073 rootPath, "/tmp/kernel");
1074 return (R_FAILURE);
1075 }
1076
1077 /* $ROOTDIR/.tmp_proto/kernel is a symbolic link */
1078
1079 r = testPath(TEST_IS_SYMBOLIC_LINK,
1080 "%s/%s", rootPath, "/.tmp_proto/kernel");
1081 if (r != R_SUCCESS) {
1082 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_ISNT_SYMLINK,
1083 rootPath, "/.tmp_proto/kernel");
1084 return (R_FAILURE);
1085 }
1086
1087 /* must not be initial installation to the install root */
1088
1089 if ((a_gdt->gd_initialInstall == B_TRUE) &&
1090 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
1091 /* initial install: install root cannot be netinstall image */
1092 log_msg(LOG_MSG_DEBUG, DBG_INIM_INITIAL_INSTALL, rootPath);
1093 return (R_FAILURE);
1094 }
1095
1096 /* must not be installation of a zone */
1097
1098 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
1099 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
1100 /* initial zone install: no path can be netinstall image */
1101 log_msg(LOG_MSG_DEBUG, DBG_INIM_ZONE_INSTALL, rootPath);
1102 return (R_FAILURE);
1103 }
1104
1105 /* target is a netinstall image */
1106
1107 log_msg(LOG_MSG_DEBUG, DBG_INIM_PATH_IS_NETINSTALL_IMAGE, rootPath);
1108
1109 return (R_SUCCESS);
1110 }
1111
1112 /*
1113 * Name: cmd_is_mounted_miniroot
1114 * Description: determine if target is a mounted miniroot image
1115 * Scope: public
1116 * Arguments: argc,argv:
1117 * - optional path to target to test
1118 * Returns: int
1119 * == 0 - success
1120 * != 0 - failure
1121 * IMPLEMENTATION:
1122 * - must not be initial installation to the install root
1123 * - must not be installation of a zone
1124 * - zone name must be "global"
1125 * - $ROOTDIR/tmp/kernel must exist and must be a symbolic link
1126 * - $ROOTDIR/tmp/root/kernel must exist and must be a directory
1127 */
1128
1129 static int
cmd_is_mounted_miniroot(int argc,char ** argv,GLOBALDATA_T * a_gdt)1130 cmd_is_mounted_miniroot(int argc, char **argv, GLOBALDATA_T *a_gdt)
1131 {
1132 char *rootPath = NULL;
1133 int c;
1134 int r;
1135 static char *cmdName = "is_mounted_miniroot";
1136 static int recursion = 0;
1137
1138 /* process any command line options */
1139
1140 while ((c = getopt(argc, argv, ":")) != EOF) {
1141 switch (c) {
1142 case '\0': /* prevent end-of-loop not reached warning */
1143 break;
1144 case '?':
1145 default:
1146 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
1147 return (R_USAGE);
1148 }
1149 }
1150
1151 /* prevent recursion */
1152
1153 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
1154 recursion--;
1155 }
1156
1157 /* normalize argc/argv */
1158
1159 argc -= optind;
1160 argv += optind;
1161
1162 /* error if more than one argument */
1163
1164 if (argc > 1) {
1165 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
1166 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
1167 return (R_USAGE);
1168 }
1169
1170 /* process root path if first argument present */
1171
1172 if (argc == 1) {
1173 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
1174 return (R_ERROR);
1175 }
1176 }
1177
1178 /* get current root path */
1179
1180 r = getRootPath(&rootPath);
1181 if (r != R_SUCCESS) {
1182 return (r);
1183 }
1184
1185 /* start of command debugging information */
1186
1187 echoDebug(DBG_ROOTPATH_IS, rootPath);
1188
1189 /* current zone name must be "global" */
1190
1191 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) {
1192 log_msg(LOG_MSG_DEBUG, DBG_IMRT_BAD_CURRENT_ZONE,
1193 rootPath, GLOBAL_ZONENAME);
1194 return (R_FAILURE);
1195 }
1196
1197 /* $ROOTDIR/tmp/kernel is a symbolic link */
1198
1199 r = testPath(TEST_IS_SYMBOLIC_LINK,
1200 "%s/%s", rootPath, "/tmp/kernel");
1201 if (r != R_SUCCESS) {
1202 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_ISNT_SYMLINK,
1203 rootPath, "/tmp/kernel");
1204 return (R_FAILURE);
1205 }
1206
1207 /* $ROOTDIR/tmp/root/kernel is a directory */
1208
1209 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY,
1210 "%s/%s", rootPath, "/tmp/root/kernel");
1211 if (r != R_SUCCESS) {
1212 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_ISNT_DIRECTORY,
1213 rootPath, "/tmp/root/kernel");
1214 return (R_FAILURE);
1215 }
1216
1217 /* must not be initial installation to the install root */
1218
1219 if ((a_gdt->gd_initialInstall == B_TRUE) &&
1220 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
1221 /* initial install: install root cannot be mounted miniroot */
1222 log_msg(LOG_MSG_DEBUG, DBG_IMRT_INITIAL_INSTALL, rootPath);
1223 return (R_FAILURE);
1224 }
1225
1226 /* must not be installation of a zone */
1227
1228 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
1229 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
1230 /* initial zone install: no path can be mounted miniroot */
1231 log_msg(LOG_MSG_DEBUG, DBG_IMRT_ZONE_INSTALL, rootPath);
1232 return (R_FAILURE);
1233 }
1234
1235 /* target is a mounted miniroot */
1236
1237 log_msg(LOG_MSG_DEBUG, DBG_IMRT_PATH_IS_MOUNTED_MINIROOT, rootPath);
1238
1239 return (R_SUCCESS);
1240 }
1241
1242 /*
1243 * Name: cmd_is_nonglobal_zone
1244 * Description: determine if target is a global zone
1245 * Scope: public
1246 * Arguments: argc,argv:
1247 * - optional path to target to test
1248 * Returns: int
1249 * == 0 - success
1250 * != 0 - failure
1251 * - must not be initial installation to the install root
1252 * - must not be installation of a global zone
1253 * - success if installation of a non-global zone
1254 */
1255
1256 static int
cmd_is_nonglobal_zone(int argc,char ** argv,GLOBALDATA_T * a_gdt)1257 cmd_is_nonglobal_zone(int argc, char **argv, GLOBALDATA_T *a_gdt)
1258 {
1259 char *rootPath = NULL;
1260 int c;
1261 int r;
1262 static char *cmdName = "is_nonglobal_zone";
1263 static int recursion = 0;
1264
1265 /* process any command line options */
1266
1267 while ((c = getopt(argc, argv, ":")) != EOF) {
1268 switch (c) {
1269 case '\0': /* prevent end-of-loop not reached warning */
1270 break;
1271 case '?':
1272 default:
1273 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
1274 return (R_USAGE);
1275 }
1276 }
1277
1278 /* prevent recursion */
1279
1280 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
1281 recursion--;
1282 }
1283
1284 /* normalize argc/argv */
1285
1286 argc -= optind;
1287 argv += optind;
1288
1289 /* error if more than one argument */
1290
1291 if (argc > 1) {
1292 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
1293 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
1294 return (R_USAGE);
1295 }
1296
1297 /* process root path if first argument present */
1298
1299 if (argc == 1) {
1300 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
1301 return (R_ERROR);
1302 }
1303 }
1304
1305 /* get current root path */
1306
1307 r = getRootPath(&rootPath);
1308 if (r != R_SUCCESS) {
1309 return (r);
1310 }
1311
1312 /* start of command debugging information */
1313
1314 echoDebug(DBG_ROOTPATH_IS, rootPath);
1315
1316 /* handle if non-global zone installation to the install root */
1317
1318 if ((a_gdt->gd_nonglobalZoneInstall == B_TRUE) &&
1319 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
1320 log_msg(LOG_MSG_DEBUG, DBG_NGZN_INSTALL_ZONENAME_IS_NGZ,
1321 rootPath, a_gdt->gd_zoneName);
1322 return (R_SUCCESS);
1323 }
1324
1325 /* must not be initial installation to the install root */
1326
1327 if ((a_gdt->gd_initialInstall == B_TRUE) &&
1328 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
1329 /* initial install: install root cannot be non-global zone */
1330 log_msg(LOG_MSG_DEBUG, DBG_NGZN_INITIAL_INSTALL, rootPath);
1331 return (R_FAILURE);
1332 }
1333
1334 /* must not be installation of a global zone */
1335
1336 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
1337 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
1338 /* initial global zone install: no path can be nonglobal zone */
1339 log_msg(LOG_MSG_DEBUG, DBG_NGZN_GLOBAL_ZONE_INSTALL, rootPath);
1340 return (R_FAILURE);
1341 }
1342
1343 /*
1344 * *********************************************************************
1345 * if root directory is "/" then the only thing that needs to be done is
1346 * to test the zone name directly - if the zone name is "global" then
1347 * the target is not a non-global zone; otherwise if the zone name is
1348 * not "global" then the target IS a non-global zone.
1349 * *********************************************************************
1350 */
1351
1352 if (strcmp(rootPath, "/") == 0) {
1353 /* target is current running root */
1354 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) {
1355 /* in the global zone */
1356 log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_ISNT_NGZ,
1357 rootPath, a_gdt->gd_zoneName);
1358 return (R_FAILURE);
1359 }
1360 /* in a non-global zone */
1361 log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_IS_NGZ,
1362 rootPath, a_gdt->gd_zoneName);
1363 return (R_SUCCESS);
1364 }
1365
1366 /*
1367 * $ROOTDIR/etc/zones/index must exist in a global zone. It also
1368 * exists in a non-global zone after s10u4 but we can't check that
1369 * since it is undeterministic for all releases so we only check
1370 * for the global zone here.
1371 */
1372
1373 r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/etc/zones/index");
1374 if (r == R_SUCCESS) {
1375
1376 /* See if "global" exists in .../etc/zones/index */
1377
1378 if (testPath(TEST_GLOBAL_TOKEN_IN_FILE, "%s/%s", rootPath,
1379 "/etc/zones/index") != R_SUCCESS) {
1380 log_msg(LOG_MSG_DEBUG, DBG_NGZN_ZONENAME_ISNT_NGZ,
1381 rootPath, GLOBAL_ZONENAME);
1382 return (R_FAILURE);
1383 }
1384 }
1385
1386 /*
1387 * *********************************************************************
1388 * If the root directory is "/" then you can use only the zone
1389 * name to determine if the zone is non-global or not since the
1390 * package is being installed or removed to the current "zone".
1391 *
1392 * Since the root directory being tested is not "/" then you have to
1393 * look into the target to try and infer zone type using means other
1394 * than the zone name only.
1395 * *********************************************************************
1396 */
1397
1398 /* reject if any items found that cannot be in a non-global zone */
1399
1400 /* .tmp_proto must not exist */
1401
1402 r = testPath(TEST_NOT_EXISTS, "%s/%s", rootPath, ".tmp_proto");
1403 if (r != R_SUCCESS) {
1404 /* $R/.tmp_proto cannot exist in a non-global zone */
1405 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_EXISTS,
1406 rootPath, "/.tmp_proto");
1407 return (R_FAILURE);
1408 }
1409
1410 /* /var must not be a symbolic link */
1411
1412 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1413 "%s/%s", rootPath, "/var");
1414 if (r != R_SUCCESS) {
1415 /* $R/var cannot be a symbolic link in a non-global zone */
1416 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_DOES_NOT_EXIST,
1417 rootPath, "/var");
1418 return (R_FAILURE);
1419 }
1420
1421 /* $ROOTDIR/tmp/root/kernel must not exist */
1422
1423 r = testPath(TEST_NOT_EXISTS,
1424 "%s/%s", rootPath, "/tmp/root/kernel");
1425 if (r != R_SUCCESS) {
1426 /* $R/tmp/root/kernel cannot exist in a non-global zone */
1427 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PATH_EXISTS,
1428 rootPath, "/tmp/root/kernel");
1429 return (R_FAILURE);
1430 }
1431
1432 /*
1433 * *********************************************************************
1434 * no items exist in $ROOTDIR that identify something other than
1435 * a non-global zone.
1436 *
1437 * if in global zone no more tests possible: is a non-global zone
1438 * *********************************************************************
1439 */
1440
1441 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) == 0) {
1442 /* in the global zone */
1443 log_msg(LOG_MSG_DEBUG, DBG_NGZN_IN_GZ_IS_NONGLOBAL_ZONE,
1444 rootPath);
1445 return (R_SUCCESS);
1446 }
1447
1448 /*
1449 * *********************************************************************
1450 * In non-global zone: interrogate zone name and type.
1451 *
1452 * The parent zone is the zone that the "pkgadd" or "pkgrm" command was
1453 * run in. The child zone is the zone that the "pkginstall" or
1454 * "pkgremove" command was run in.
1455 * *********************************************************************
1456 */
1457
1458 /*
1459 * If parent zone name and current zone name defined, and
1460 * both zone names are the same, since pkgcond is running
1461 * inside of a non-global zone, this is how the scratch
1462 * zone is implemented, so target is a non-global zone
1463 */
1464
1465 if ((a_gdt->gd_parentZoneName != NULL) &&
1466 (a_gdt->gd_currentZoneName != NULL) &&
1467 (strcmp(a_gdt->gd_parentZoneName,
1468 a_gdt->gd_currentZoneName) == 0)) {
1469 /* parent and current zone name identical: non-gz */
1470 log_msg(LOG_MSG_DEBUG, DBG_NGZN_PARENT_CHILD_SAMEZONE,
1471 rootPath, a_gdt->gd_parentZoneName);
1472 return (R_SUCCESS);
1473 }
1474
1475 /*
1476 * In non-global zone if zone specific read only FS's exist
1477 * or it is in a mounted state.
1478 */
1479
1480 if (a_gdt->inMountedState) {
1481 log_msg(LOG_MSG_DEBUG, DBG_NGZN_IS_NONGLOBAL_ZONE, rootPath);
1482 return (R_SUCCESS);
1483 }
1484
1485 /*
1486 * the parent and current zone name are not the same;
1487 * interrogate the zone types: the parent must be global
1488 * and the current must be non-global, which would be set
1489 * when a package command is run in the global zone that in
1490 * turn runs a package command within the non-global zone.
1491 */
1492
1493 /* if defined, parent zone type must be "global" */
1494
1495 if ((a_gdt->gd_parentZoneType != NULL) &&
1496 (strcmp(a_gdt->gd_parentZoneType, "nonglobal") == 0)) {
1497 log_msg(LOG_MSG_DEBUG, DBG_NGZN_BAD_PARENT_ZONETYPE,
1498 rootPath, "nonglobal");
1499 return (R_FAILURE);
1500 }
1501
1502 /* if defined, current zone type must be "nonglobal" */
1503
1504 if ((a_gdt->gd_currentZoneType != NULL) &&
1505 (strcmp(a_gdt->gd_currentZoneType, GLOBAL_ZONENAME) == 0)) {
1506 log_msg(LOG_MSG_DEBUG, DBG_NGZN_BAD_CURRENT_ZONETYPE,
1507 rootPath, GLOBAL_ZONENAME);
1508 return (R_FAILURE);
1509 }
1510
1511 /*
1512 * *********************************************************************
1513 * no other tests possible: target is a non-global zone
1514 * *********************************************************************
1515 */
1516
1517 log_msg(LOG_MSG_DEBUG, DBG_NGZN_IS_NONGLOBAL_ZONE, rootPath);
1518
1519 return (R_SUCCESS);
1520 }
1521
1522 /*
1523 * Name: cmd_is_running_system
1524 * Description: determine if target is a global zone
1525 * Scope: public
1526 * Arguments: argc,argv:
1527 * - optional path to target to test
1528 * Returns: int
1529 * == 0 - success
1530 * != 0 - failure
1531 * IMPLEMENTATION:
1532 * - must not be initial installation to the install root
1533 * - must not be installation of a zone
1534 * - must not be a diskless client
1535 * - $ROOTDIR must be "/"
1536 * - zone name must be "global"
1537 */
1538
1539 static int
cmd_is_running_system(int argc,char ** argv,GLOBALDATA_T * a_gdt)1540 cmd_is_running_system(int argc, char **argv, GLOBALDATA_T *a_gdt)
1541 {
1542 char *rootPath = NULL;
1543 int c;
1544 int r;
1545 static char *cmdName = "is_running_system";
1546 static int recursion = 0;
1547
1548 /* process any command line options */
1549
1550 while ((c = getopt(argc, argv, ":")) != EOF) {
1551 switch (c) {
1552 case '\0': /* prevent end-of-loop not reached warning */
1553 break;
1554 case '?':
1555 default:
1556 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
1557 return (R_USAGE);
1558 }
1559 }
1560
1561 /* prevent recursion */
1562
1563 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
1564
1565 /* a running system cannot be a diskless client */
1566
1567 r = cmd_is_diskless_client(argc, argv, a_gdt);
1568
1569 /* no need to guard against recursion any more */
1570
1571 recursion--;
1572
1573 switch (r) {
1574 case R_SUCCESS:
1575 return (R_FAILURE);
1576 case R_FAILURE:
1577 break;
1578 case R_USAGE:
1579 case R_ERROR:
1580 default:
1581 return (r);
1582 }
1583 }
1584
1585 /* normalize argc/argv */
1586
1587 argc -= optind;
1588 argv += optind;
1589
1590 /* error if more than one argument */
1591
1592 if (argc > 1) {
1593 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
1594 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
1595 return (R_USAGE);
1596 }
1597
1598 /* process root path if first argument present */
1599
1600 if (argc == 1) {
1601 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
1602 return (R_ERROR);
1603 }
1604 }
1605
1606 /* get current root path */
1607
1608 r = getRootPath(&rootPath);
1609 if (r != R_SUCCESS) {
1610 return (r);
1611 }
1612
1613 /* start of command debugging information */
1614
1615 echoDebug(DBG_ROOTPATH_IS, rootPath);
1616
1617 /* if root path is "/" then check zone name */
1618
1619 if (strcmp(rootPath, "/") != 0) {
1620 log_msg(LOG_MSG_DEBUG, DBG_IRST_ROOTPATH_BAD, rootPath, "/");
1621 return (R_FAILURE);
1622 }
1623
1624 /* zone name must be global */
1625
1626 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) {
1627 log_msg(LOG_MSG_DEBUG, DBG_IRST_ZONE_BAD, rootPath,
1628 GLOBAL_ZONENAME);
1629 return (R_FAILURE);
1630 }
1631
1632 /* must not be initial installation to the install root */
1633
1634 if ((a_gdt->gd_initialInstall == B_TRUE) &&
1635 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
1636 /* initial install: install root cannot be the running system */
1637 log_msg(LOG_MSG_DEBUG, DBG_IRST_INITIAL_INSTALL, rootPath);
1638 return (R_FAILURE);
1639 }
1640
1641 /* must not be installation of a zone */
1642
1643 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
1644 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
1645 /* initial zone install: no path can be running system */
1646 log_msg(LOG_MSG_DEBUG, DBG_IRST_ZONE_INSTALL, rootPath);
1647 return (R_FAILURE);
1648 }
1649
1650 /* target is a running system */
1651
1652 log_msg(LOG_MSG_DEBUG, DBG_IRST_PATH_IS_RUNNING_SYSTEM, rootPath);
1653
1654 return (R_SUCCESS);
1655 }
1656
1657 /*
1658 * Name: cmd_can_add_driver
1659 * Description: determine if target is a global zone
1660 * Scope: public
1661 * Arguments: argc,argv:
1662 * - optional path to target to test
1663 * Returns: int
1664 * == 0 - success
1665 * != 0 - failure
1666 * Implementation:
1667 * A driver can be added to the system if the components of a Solaris
1668 * instance capable of loading drivers is present and it is not the
1669 * currently running system.
1670 */
1671
1672 static int
cmd_can_add_driver(int argc,char ** argv,GLOBALDATA_T * a_gdt)1673 cmd_can_add_driver(int argc, char **argv, GLOBALDATA_T *a_gdt)
1674 {
1675 char *rootPath = NULL;
1676 int c;
1677 int r;
1678 static char *cmdName = "can_add_driver";
1679 static int recursion = 0;
1680
1681 /* process any command line options */
1682
1683 while ((c = getopt(argc, argv, ":")) != EOF) {
1684 switch (c) {
1685 case '\0': /* prevent end-of-loop not reached warning */
1686 break;
1687 case '?':
1688 default:
1689 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
1690 return (R_USAGE);
1691 }
1692 }
1693
1694 /* prevent recursion */
1695
1696 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
1697
1698 /* see if this is the current running system */
1699
1700 r = cmd_is_running_system(argc, argv, a_gdt);
1701
1702 /* cannot be a diskless client */
1703
1704 if (r != R_SUCCESS) {
1705 r = cmd_is_diskless_client(argc, argv, a_gdt);
1706 }
1707
1708 /* no need to guard against recursion any more */
1709
1710 recursion--;
1711
1712 switch (r) {
1713 case R_SUCCESS:
1714 /* is a running system */
1715 return (R_FAILURE);
1716 case R_FAILURE:
1717 /* not a running syste */
1718 break;
1719 case R_USAGE:
1720 case R_ERROR:
1721 default:
1722 /* cannot determine if is a running system */
1723 return (r);
1724 }
1725 }
1726
1727 /* normalize argc/argv */
1728
1729 argc -= optind;
1730 argv += optind;
1731
1732 /* error if more than one argument */
1733
1734 if (argc > 1) {
1735 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
1736 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
1737 return (R_USAGE);
1738 }
1739
1740 /* process root path if first argument present */
1741
1742 if (argc == 1) {
1743 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
1744 return (R_ERROR);
1745 }
1746 }
1747
1748 /* get current root path */
1749
1750 r = getRootPath(&rootPath);
1751 if (r != R_SUCCESS) {
1752 return (r);
1753 }
1754
1755 /* start of command debugging information */
1756
1757 echoDebug(DBG_ROOTPATH_IS, rootPath);
1758
1759 /* /etc must exist and must not be a symbolic link */
1760
1761 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1762 "%s/%s", rootPath, "/etc");
1763 if (r != R_SUCCESS) {
1764 log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK,
1765 rootPath, "/etc");
1766 return (R_FAILURE);
1767 }
1768
1769 /* /platform must exist and must not be a symbolic link */
1770
1771 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1772 "%s/%s", rootPath, "/platform");
1773 if (r != R_SUCCESS) {
1774 log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK,
1775 rootPath, "/platform");
1776 return (R_FAILURE);
1777 }
1778
1779 /* /kernel must exist and must not be a symbolic link */
1780
1781 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1782 "%s/%s", rootPath, "/kernel");
1783 if (r != R_SUCCESS) {
1784 log_msg(LOG_MSG_DEBUG, DBG_ADDV_PATH_IS_SYMLINK,
1785 rootPath, "/kernel");
1786 return (R_FAILURE);
1787 }
1788
1789 /* can add a driver */
1790
1791 log_msg(LOG_MSG_DEBUG, DBG_ADDV_YES, rootPath);
1792
1793 return (R_SUCCESS);
1794 }
1795
1796 /*
1797 * Name: cmd_can_update_driver
1798 * Description: determine if target is a global zone
1799 * Scope: public
1800 * Arguments: argc,argv:
1801 * - optional path to target to test
1802 * Returns: int
1803 * == 0 - success
1804 * != 0 - failure
1805 * Implementation:
1806 * A driver can be added to the system if the components of a Solaris
1807 * instance capable of loading drivers is present and it is not the
1808 * currently running system.
1809 */
1810
1811 static int
cmd_can_update_driver(int argc,char ** argv,GLOBALDATA_T * a_gdt)1812 cmd_can_update_driver(int argc, char **argv, GLOBALDATA_T *a_gdt)
1813 {
1814 char *rootPath = NULL;
1815 int c;
1816 int r;
1817 static char *cmdName = "can_update_driver";
1818 static int recursion = 0;
1819
1820 /* process any command line options */
1821
1822 while ((c = getopt(argc, argv, ":")) != EOF) {
1823 switch (c) {
1824 case '\0': /* prevent end-of-loop not reached warning */
1825 break;
1826 case '?':
1827 default:
1828 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
1829 return (R_USAGE);
1830 }
1831 }
1832
1833 /* prevent recursion */
1834
1835 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
1836
1837 /* see if this is the current running system */
1838
1839 r = cmd_is_running_system(argc, argv, a_gdt);
1840
1841 /* cannot be a diskless client */
1842
1843 if (r != R_SUCCESS) {
1844 r = cmd_is_diskless_client(argc, argv, a_gdt);
1845 }
1846
1847 /* no need to guard against recursion any more */
1848
1849 recursion--;
1850
1851 switch (r) {
1852 case R_SUCCESS:
1853 /* is a running system */
1854 return (R_FAILURE);
1855 case R_FAILURE:
1856 /* not a running syste */
1857 break;
1858 case R_USAGE:
1859 case R_ERROR:
1860 default:
1861 /* cannot determine if is a running system */
1862 return (r);
1863 }
1864 }
1865
1866 /* normalize argc/argv */
1867
1868 argc -= optind;
1869 argv += optind;
1870
1871 /* error if more than one argument */
1872
1873 if (argc > 1) {
1874 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
1875 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
1876 return (R_USAGE);
1877 }
1878
1879 /* process root path if first argument present */
1880
1881 if (argc == 1) {
1882 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
1883 return (R_ERROR);
1884 }
1885 }
1886
1887 /* get current root path */
1888
1889 r = getRootPath(&rootPath);
1890 if (r != R_SUCCESS) {
1891 return (r);
1892 }
1893
1894 /* start of command debugging information */
1895
1896 echoDebug(DBG_ROOTPATH_IS, rootPath);
1897
1898 /* /etc must exist and must not be a symbolic link */
1899
1900 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1901 "%s/%s", rootPath, "/etc");
1902 if (r != R_SUCCESS) {
1903 log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK,
1904 rootPath, "/etc");
1905 return (R_FAILURE);
1906 }
1907
1908 /* /platform must exist and must not be a symbolic link */
1909
1910 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1911 "%s/%s", rootPath, "/platform");
1912 if (r != R_SUCCESS) {
1913 log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK,
1914 rootPath, "/platform");
1915 return (R_FAILURE);
1916 }
1917
1918 /* /kernel must exist and must not be a symbolic link */
1919
1920 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
1921 "%s/%s", rootPath, "/kernel");
1922 if (r != R_SUCCESS) {
1923 log_msg(LOG_MSG_DEBUG, DBG_UPDV_PATH_IS_SYMLINK,
1924 rootPath, "/kernel");
1925 return (R_FAILURE);
1926 }
1927
1928 /* can update driver */
1929
1930 log_msg(LOG_MSG_DEBUG, DBG_UPDV_YES, rootPath);
1931
1932 return (R_SUCCESS);
1933 }
1934
1935 /*
1936 * Name: cmd_can_remove_driver
1937 * Description: determine if target is a global zone
1938 * Scope: public
1939 * Arguments: argc,argv:
1940 * - optional path to target to test
1941 * Returns: int
1942 * == 0 - success
1943 * != 0 - failure
1944 * Implementation:
1945 * A driver can be added to the system if the components of a Solaris
1946 * instance capable of loading drivers is present and it is not the
1947 * currently running system.
1948 */
1949
1950 static int
cmd_can_remove_driver(int argc,char ** argv,GLOBALDATA_T * a_gdt)1951 cmd_can_remove_driver(int argc, char **argv, GLOBALDATA_T *a_gdt)
1952 {
1953 char *rootPath = NULL;
1954 int c;
1955 int r;
1956 static char *cmdName = "can_remove_driver";
1957 static int recursion = 0;
1958
1959 /* process any command line options */
1960
1961 while ((c = getopt(argc, argv, ":")) != EOF) {
1962 switch (c) {
1963 case '\0': /* prevent end-of-loop not reached warning */
1964 break;
1965 case '?':
1966 default:
1967 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
1968 return (R_USAGE);
1969 }
1970 }
1971
1972 /* prevent recursion */
1973
1974 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
1975
1976 /* see if this is the current running system */
1977
1978 r = cmd_is_running_system(argc, argv, a_gdt);
1979
1980 /* cannot be a diskless client */
1981
1982 if (r != R_SUCCESS) {
1983 r = cmd_is_diskless_client(argc, argv, a_gdt);
1984 }
1985
1986 /* no need to guard against recursion any more */
1987
1988 recursion--;
1989
1990 switch (r) {
1991 case R_SUCCESS:
1992 /* is a running system */
1993 return (R_FAILURE);
1994 case R_FAILURE:
1995 /* not a running syste */
1996 break;
1997 case R_USAGE:
1998 case R_ERROR:
1999 default:
2000 /* cannot determine if is a running system */
2001 return (r);
2002 }
2003 }
2004
2005 /* normalize argc/argv */
2006
2007 argc -= optind;
2008 argv += optind;
2009
2010 /* error if more than one argument */
2011
2012 if (argc > 1) {
2013 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
2014 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
2015 return (R_USAGE);
2016 }
2017
2018 /* process root path if first argument present */
2019
2020 if (argc == 1) {
2021 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
2022 return (R_ERROR);
2023 }
2024 }
2025
2026 /* get current root path */
2027
2028 r = getRootPath(&rootPath);
2029 if (r != R_SUCCESS) {
2030 return (r);
2031 }
2032
2033 /* start of command debugging information */
2034
2035 echoDebug(DBG_ROOTPATH_IS, rootPath);
2036
2037 /* /etc must exist and must not be a symbolic link */
2038
2039 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
2040 "%s/%s", rootPath, "/etc");
2041 if (r != R_SUCCESS) {
2042 log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK,
2043 rootPath, "/etc");
2044 return (R_FAILURE);
2045 }
2046
2047 /* /platform must exist and must not be a symbolic link */
2048
2049 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
2050 "%s/%s", rootPath, "/platform");
2051 if (r != R_SUCCESS) {
2052 log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK,
2053 rootPath, "/platform");
2054 return (R_FAILURE);
2055 }
2056
2057 /* /kernel must exist and must not be a symbolic link */
2058
2059 r = testPath(TEST_EXISTS|TEST_NOT_SYMBOLIC_LINK,
2060 "%s/%s", rootPath, "/kernel");
2061 if (r != R_SUCCESS) {
2062 log_msg(LOG_MSG_DEBUG, DBG_RMDV_PATH_IS_SYMLINK,
2063 rootPath, "/kernel");
2064 return (R_FAILURE);
2065 }
2066
2067 /* can remove driver */
2068
2069 log_msg(LOG_MSG_DEBUG, DBG_RMDV_YES, rootPath);
2070
2071 return (R_SUCCESS);
2072 }
2073
2074 /*
2075 * Name: cmd_is_path_writable
2076 * Description: determine if target path is writable
2077 * Scope: public
2078 * Arguments: argc,argv:
2079 * - optional path to target to test
2080 * Returns: int
2081 * == 0 - success
2082 * != 0 - failure
2083 * IMPLEMENTATION:
2084 * - path must be found in the file systems configured
2085 * - mount options must not include "read only"
2086 */
2087
2088 static int
cmd_is_path_writable(int argc,char ** argv,GLOBALDATA_T * a_gdt)2089 cmd_is_path_writable(int argc, char **argv, GLOBALDATA_T *a_gdt)
2090 {
2091 FSI_T *list;
2092 char *rootPath = NULL;
2093 int c;
2094 int n;
2095 int nn;
2096 int r;
2097 long listSize;
2098 long rootPathLen;
2099 static char *cmdName = "is_path_writable";
2100 static int recursion = 0;
2101
2102 /* process any command line options */
2103
2104 while ((c = getopt(argc, argv, ":")) != EOF) {
2105 switch (c) {
2106 case '\0': /* prevent end-of-loop not reached warning */
2107 break;
2108 case '?':
2109 default:
2110 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
2111 return (R_USAGE);
2112 }
2113 }
2114
2115 /* prevent recursion */
2116
2117 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
2118 recursion--;
2119 }
2120
2121 /* normalize argc/argv */
2122
2123 argc -= optind;
2124 argv += optind;
2125
2126 /* error if more than one argument */
2127
2128 if (argc > 1) {
2129 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
2130 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
2131 return (R_USAGE);
2132 }
2133
2134 /* process root path if first argument present */
2135
2136 if (argc != 1) {
2137 (void) usage(ERR_REQUIRED_ROOTPATH_MISSING, cmdName);
2138 return (R_USAGE);
2139 }
2140
2141 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
2142 return (R_ERROR);
2143 }
2144
2145 /* get current root path */
2146
2147 r = getRootPath(&rootPath);
2148 if (r != R_SUCCESS) {
2149 return (r);
2150 }
2151
2152 /* start of command debugging information */
2153
2154 echoDebug(DBG_ROOTPATH_IS, rootPath);
2155
2156 /* search file system conf for this path */
2157
2158 rootPathLen = strlen(rootPath);
2159 list = a_gdt->gd_fileSystemConfig;
2160 listSize = a_gdt->gd_fileSystemConfigLen;
2161 for (nn = 0, n = 0; n < listSize; n++) {
2162 long mplen = strlen(list[n].fsi_mntPoint);
2163 if (rootPathLen < mplen) {
2164 /* root path is longer than target, ignore */
2165 continue;
2166 }
2167 if (strncmp(rootPath, list[n].fsi_mntPoint, mplen) == 0) {
2168 /* remember last partial match */
2169 nn = n;
2170 }
2171 }
2172
2173 log_msg(LOG_MSG_DEBUG, DBG_PWRT_INFO,
2174 rootPath, list[nn].fsi_mntPoint, list[nn].fsi_fsType,
2175 list[nn].fsi_mntOptions);
2176
2177 /*
2178 * need to determine if the mount point is writeable:
2179 */
2180
2181 /* see if the file system is mounted with the "read only" option */
2182
2183 r = mountOptionPresent(list[nn].fsi_mntOptions, MNTOPT_RO);
2184 if (r == R_SUCCESS) {
2185 log_msg(LOG_MSG_DEBUG, DBG_PWRT_READONLY,
2186 rootPath, list[nn].fsi_mntOptions);
2187 return (R_FAILURE);
2188 }
2189
2190 /* target path is writable */
2191
2192 log_msg(LOG_MSG_DEBUG, DBG_PWRT_IS, rootPath);
2193
2194 return (R_SUCCESS);
2195 }
2196
2197 /*
2198 * Name: cmd_is_alternative_root
2199 * Description: determine if target is an alternative root
2200 * Scope: public
2201 * Arguments: argc,argv:
2202 * - optional path to target to test
2203 * Returns: int
2204 * == 0 - success
2205 * != 0 - failure
2206 * Implementation:
2207 * - success if an initial installation to the install root
2208 * (an initial install to $PKG_INSTALL_ROOT means that $PKG_INSTALL_ROOT
2209 * points to an alternative root that is under construction)
2210 * - must not be installation of a zone
2211 * - must not be a boot environment
2212 * - must not be a diskless client
2213 * - must not be a mounted miniroot
2214 * - must not be a netinstall image
2215 * - must not be a nonglobal zone
2216 * - must not be a running system
2217 * - $ROOTDIR must not be "/"
2218 * - $ROOTDIR/var must exist
2219 */
2220
2221 static int
cmd_is_alternative_root(int argc,char ** argv,GLOBALDATA_T * a_gdt)2222 cmd_is_alternative_root(int argc, char **argv, GLOBALDATA_T *a_gdt)
2223 {
2224 char *rootPath = NULL;
2225 int c;
2226 int r;
2227 static char *cmdName = "is_alternative_root";
2228 static int recursion = 0;
2229
2230 /* process any command line options */
2231
2232 while ((c = getopt(argc, argv, ":")) != EOF) {
2233 switch (c) {
2234 case '\0': /* prevent end-of-loop not reached warning */
2235 break;
2236 case '?':
2237 default:
2238 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
2239 return (R_USAGE);
2240 }
2241 }
2242
2243 /* prevent recursion */
2244
2245 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
2246
2247 /*
2248 * an alternative root cannot be any of the following
2249 */
2250
2251 /* cannot be a boot_environment */
2252
2253 r = cmd_is_boot_environment(argc, argv, a_gdt);
2254
2255 /* cannot be a diskless_client */
2256
2257 if (r != R_SUCCESS) {
2258 r = cmd_is_diskless_client(argc, argv, a_gdt);
2259 }
2260
2261 /* cannot be a mounted_miniroot */
2262
2263 if (r != R_SUCCESS) {
2264 r = cmd_is_mounted_miniroot(argc, argv, a_gdt);
2265 }
2266
2267 /* cannot be a netinstall_image */
2268
2269 if (r != R_SUCCESS) {
2270 r = cmd_is_netinstall_image(argc, argv, a_gdt);
2271 }
2272
2273 /* cannot be a nonglobal_zone */
2274
2275 if (r != R_SUCCESS) {
2276 r = cmd_is_nonglobal_zone(argc, argv, a_gdt);
2277 }
2278
2279 /* cannot be a running_system */
2280
2281 if (r != R_SUCCESS) {
2282 r = cmd_is_running_system(argc, argv, a_gdt);
2283 }
2284
2285 /* no need to guard against recursion any more */
2286
2287 recursion--;
2288
2289 /* return failure if any of the preceeding are true */
2290
2291 switch (r) {
2292 case R_SUCCESS:
2293 return (R_FAILURE);
2294 case R_FAILURE:
2295 break;
2296 case R_USAGE:
2297 case R_ERROR:
2298 default:
2299 return (r);
2300 }
2301 }
2302
2303 /* normalize argc/argv */
2304
2305 argc -= optind;
2306 argv += optind;
2307
2308 /* error if more than one argument */
2309
2310 if (argc > 1) {
2311 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
2312 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
2313 return (R_USAGE);
2314 }
2315
2316 /* process root path if first argument present */
2317
2318 if (argc == 1) {
2319 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
2320 return (R_ERROR);
2321 }
2322 }
2323
2324 /* get current root path */
2325
2326 r = getRootPath(&rootPath);
2327 if (r != R_SUCCESS) {
2328 return (r);
2329 }
2330
2331 /* start of command debugging information */
2332
2333 echoDebug(DBG_ROOTPATH_IS, rootPath);
2334
2335 /* return success if initial installation */
2336
2337 if ((a_gdt->gd_initialInstall == B_TRUE) &&
2338 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
2339 log_msg(LOG_MSG_DEBUG, DBG_IALR_INITIAL_INSTALL, rootPath);
2340 return (R_SUCCESS);
2341 }
2342
2343 /* root path must not be "/" */
2344
2345 if (strcmp(rootPath, "/") == 0) {
2346 log_msg(LOG_MSG_DEBUG, DBG_IALR_BAD_ROOTPATH, rootPath, "/");
2347 return (R_FAILURE);
2348 }
2349
2350 /* /var must exist */
2351
2352 r = testPath(TEST_EXISTS,
2353 "%s/%s", rootPath, "/var");
2354 if (r != R_SUCCESS) {
2355 log_msg(LOG_MSG_DEBUG, DBG_IALR_PATH_DOES_NOT_EXIST,
2356 rootPath, "/var");
2357 return (R_FAILURE);
2358 }
2359
2360 /* must not be installation of a zone */
2361
2362 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
2363 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
2364 /* initial zone install: no path can be alternative root */
2365 log_msg(LOG_MSG_DEBUG, DBG_IALR_ZONE_INSTALL, rootPath);
2366 return (R_FAILURE);
2367 }
2368
2369 /* target is an alternative root */
2370
2371 log_msg(LOG_MSG_DEBUG, DBG_IALR_IS, rootPath);
2372
2373 return (R_SUCCESS);
2374 }
2375
2376 /*
2377 * Name: cmd_is_boot_environment
2378 * Description: determine if target is an alternative, inactive boot environment
2379 * Scope: public
2380 * Arguments: argc,argv:
2381 * - optional path to target to test
2382 * Returns: int
2383 * == 0 - success
2384 * != 0 - failure
2385 * IMPLEMENTATION:
2386 * - must not be initial installation to the install root
2387 * - must not be installation of a zone
2388 * - must not be a diskless client
2389 * - must not be a netinstall image
2390 * - must not be a mounted miniroot
2391 * - $ROOTDIR must not be "/"
2392 * - $ROOTDIR/etc/lutab must exist
2393 * - $ROOTDIR/etc/lu must exist and must be a directory
2394 */
2395
2396 static int
cmd_is_boot_environment(int argc,char ** argv,GLOBALDATA_T * a_gdt)2397 cmd_is_boot_environment(int argc, char **argv, GLOBALDATA_T *a_gdt)
2398 {
2399 char *rootPath = NULL;
2400 int c;
2401 int r;
2402 static char *cmdName = "is_boot_environment";
2403 static int recursion = 0;
2404
2405 /* process any command line options */
2406
2407 while ((c = getopt(argc, argv, ":")) != EOF) {
2408 switch (c) {
2409 case '\0': /* prevent end-of-loop not reached warning */
2410 break;
2411 case '?':
2412 default:
2413 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
2414 return (R_USAGE);
2415 }
2416 }
2417
2418 /* prevent recursion */
2419
2420 if (recursionCheck(&recursion, cmdName) == B_FALSE) {
2421 /*
2422 * a boot environment cannot be any of the following
2423 */
2424
2425 /* cannot be a diskless client */
2426
2427 r = cmd_is_diskless_client(argc, argv, a_gdt);
2428
2429 /* cannot be a netinstall_image */
2430
2431 if (r != R_SUCCESS) {
2432 r = cmd_is_netinstall_image(argc, argv, a_gdt);
2433 }
2434
2435 /* cannot be a mounted_miniroot */
2436
2437 if (r != R_SUCCESS) {
2438 r = cmd_is_mounted_miniroot(argc, argv, a_gdt);
2439 }
2440
2441 /* no need to guard against recursion any more */
2442
2443 recursion--;
2444
2445 /* return failure if any of the preceeding are true */
2446
2447 switch (r) {
2448 case R_SUCCESS:
2449 return (R_FAILURE);
2450 case R_FAILURE:
2451 break;
2452 case R_USAGE:
2453 case R_ERROR:
2454 default:
2455 return (r);
2456 }
2457 }
2458
2459 /* normalize argc/argv */
2460
2461 argc -= optind;
2462 argv += optind;
2463
2464 /* error if more than one argument */
2465
2466 if (argc > 1) {
2467 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
2468 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
2469 return (R_USAGE);
2470 }
2471
2472 /* process root path if first argument present */
2473
2474 if (argc == 1) {
2475 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
2476 return (R_ERROR);
2477 }
2478 }
2479
2480 /* get current root path */
2481
2482 r = getRootPath(&rootPath);
2483 if (r != R_SUCCESS) {
2484 return (r);
2485 }
2486
2487 /* start of command debugging information */
2488
2489 echoDebug(DBG_ROOTPATH_IS, rootPath);
2490
2491 /* root path must not be "/" */
2492
2493 if (strcmp(rootPath, "/") == 0) {
2494 log_msg(LOG_MSG_DEBUG, DBG_BENV_BAD_ROOTPATH, rootPath, "/");
2495 return (R_FAILURE);
2496 }
2497
2498 /* zone name must be global */
2499
2500 if (strcmp(a_gdt->gd_zoneName, GLOBAL_ZONENAME) != 0) {
2501 log_msg(LOG_MSG_DEBUG, DBG_BENV_BAD_ZONE, rootPath,
2502 GLOBAL_ZONENAME);
2503 return (R_FAILURE);
2504 }
2505
2506 /* $ROOTDIR/etc/lutab must exist */
2507
2508 r = testPath(TEST_EXISTS, "%s/%s", rootPath, "/etc/lutab");
2509 if (r != R_SUCCESS) {
2510 log_msg(LOG_MSG_DEBUG, DBG_BENV_NO_ETCLUTAB, rootPath,
2511 "/etc/lutab");
2512 return (R_FAILURE);
2513 }
2514
2515 /* $ROOTDIR/etc/lu must exist */
2516
2517 r = testPath(TEST_EXISTS|TEST_IS_DIRECTORY,
2518 "%s/%s", rootPath, "/etc/lu");
2519 if (r != R_SUCCESS) {
2520 log_msg(LOG_MSG_DEBUG, DBG_BENV_NO_ETCLU, rootPath, "/etc/lu");
2521 return (R_FAILURE);
2522 }
2523
2524 /* must not be initial installation */
2525
2526 if ((a_gdt->gd_initialInstall == B_TRUE) &&
2527 (strcmp(a_gdt->gd_installRoot, rootPath) == 0)) {
2528 log_msg(LOG_MSG_DEBUG, DBG_BENV_INITIAL_INSTALL, rootPath);
2529 return (R_FAILURE);
2530 }
2531
2532 /* must not be installation of a zone */
2533
2534 if ((a_gdt->gd_globalZoneInstall == B_TRUE) ||
2535 (a_gdt->gd_nonglobalZoneInstall == B_TRUE)) {
2536 /* initial zone install: no path can be boot environment */
2537 log_msg(LOG_MSG_DEBUG, DBG_BENV_ZONE_INSTALL, rootPath);
2538 return (R_FAILURE);
2539 }
2540
2541 /* target is a boot environment */
2542
2543 log_msg(LOG_MSG_DEBUG, DBG_BENV_IS, rootPath);
2544
2545 return (R_SUCCESS);
2546 }
2547
2548 /*
2549 * Name: cmd_is_what
2550 * Description: determine what the target is
2551 * Scope: public
2552 * Arguments: argc,argv:
2553 * - optional path to target to test
2554 * Returns: int
2555 * == 0 - success
2556 * != 0 - failure
2557 */
2558
2559 static int
cmd_is_what(int argc,char ** argv,GLOBALDATA_T * a_gdt)2560 cmd_is_what(int argc, char **argv, GLOBALDATA_T *a_gdt)
2561 {
2562 char *rootPath = NULL;
2563 int c;
2564 int cur_cmd;
2565 int r;
2566 static char *cmdName = "is_what";
2567
2568 /* process any command line options */
2569
2570 while ((c = getopt(argc, argv, ":")) != EOF) {
2571 switch (c) {
2572 case '\0': /* prevent end-of-loop not reached warning */
2573 break;
2574 case '?':
2575 default:
2576 (void) usage(MSG_IS_INVALID_OPTION, optopt, cmdName);
2577 return (R_USAGE);
2578 }
2579 }
2580
2581 /* normalize argc/argv */
2582
2583 argc -= optind;
2584 argv += optind;
2585
2586 /* error if more than one argument */
2587
2588 if (argc > 1) {
2589 log_msg(LOG_MSG_ERR, ERR_UNRECOGNIZED_OPTION, argv[1]);
2590 (void) usage(MSG_IS_INVALID_OPTION, argv[1]);
2591 return (R_USAGE);
2592 }
2593
2594 /* process root path if first argument present */
2595
2596 if (argc == 1) {
2597 if (setRootPath(argv[0], "argv[0]", B_TRUE) != R_SUCCESS) {
2598 return (R_ERROR);
2599 }
2600 }
2601
2602 /* get current root path */
2603
2604 r = getRootPath(&rootPath);
2605 if (r != R_SUCCESS) {
2606 return (r);
2607 }
2608
2609 /*
2610 * construct the command line for all of the packages
2611 */
2612
2613 argc = 0;
2614 argv[argc++] = strdup(get_prog_name());
2615 argv[argc++] = strdup(rootPath);
2616
2617 /* start of command debugging information */
2618
2619 echoDebug(DBG_ROOTPATH_IS, rootPath);
2620
2621 /* search for specified subcommand and execute if found */
2622
2623 for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) {
2624 int result;
2625
2626 /* do not recursively call this function */
2627
2628 if (cmds[cur_cmd].c_func == cmd_is_what) {
2629 continue;
2630 }
2631
2632 /* call subcommand with its own argc/argv */
2633
2634 result = cmds[cur_cmd].c_func(argc, argv, a_gdt);
2635
2636 /* process result code and exit */
2637
2638 result = adjustResults(result);
2639 log_msg(LOG_MSG_INFO, MSG_IS_WHAT_RESULT,
2640 cmds[cur_cmd].c_name, result);
2641 }
2642 return (R_SUCCESS);
2643 }
2644
2645 /*
2646 * *****************************************************************************
2647 * utility support functions
2648 * *****************************************************************************
2649 */
2650
2651 /*
2652 * Name: getMountOption
2653 * Description: return next mount option in a string
2654 * Arguments: p - pointer to string containing mount options
2655 * Output: none
2656 * Returns: char * - pointer to next option in string "p"
2657 * Side Effects: advances input "p" and inserts \0 in place of the
2658 * option separator found.
2659 */
2660
2661 static char *
getMountOption(char ** p)2662 getMountOption(char **p)
2663 {
2664 char *cp = *p;
2665 char *retstr;
2666
2667 /* advance past all white space */
2668
2669 while (*cp && isspace(*cp))
2670 cp++;
2671
2672 /* remember start of next option */
2673
2674 retstr = cp;
2675
2676 /* advance to end of string or option separator */
2677
2678 while (*cp && *cp != ',')
2679 cp++;
2680
2681 /* replace separator with '\0' if not at end of string */
2682 if (*cp) {
2683 *cp = '\0';
2684 cp++;
2685 }
2686
2687 /* reset caller's pointer and return pointer to option */
2688
2689 *p = cp;
2690 return (retstr);
2691 }
2692
2693 /*
2694 * Name: mountOptionPresent
2695 * Description: determine if specified mount option is present in list
2696 * of mount point options
2697 * Arguments: a_mntOptions - pointer to string containing list of mount
2698 * point options to search
2699 * a_opt - pointer to string containing option to search for
2700 * Output: none
2701 * Returns: R_SUCCESS - option is present in list of mount point options
2702 * R_FAILURE - options is not present
2703 * R_ERROR - unable to determine if option is present or not
2704 */
2705
2706 static int
mountOptionPresent(char * a_mntOptions,char * a_opt)2707 mountOptionPresent(char *a_mntOptions, char *a_opt)
2708 {
2709 char tmpopts[MNT_LINE_MAX];
2710 char *f, *opts = tmpopts;
2711
2712 /* return false if no mount options present */
2713
2714 if ((a_opt == NULL) || (*a_opt == '\0')) {
2715 return (R_FAILURE);
2716 }
2717
2718 /* return not present if no list of options to search */
2719
2720 if (a_mntOptions == NULL) {
2721 return (R_FAILURE);
2722 }
2723
2724 /* return not present if list of options to search is empty */
2725
2726 if (*a_mntOptions == '\0') {
2727 return (R_FAILURE);
2728 }
2729
2730 /* make local copy of option list to search */
2731
2732 (void) strcpy(opts, a_mntOptions);
2733
2734 /* scan each option looking for the specified option */
2735
2736 f = getMountOption(&opts);
2737 for (; *f; f = getMountOption(&opts)) {
2738 /* return success if option matches target */
2739 if (strncmp(a_opt, f, strlen(a_opt)) == 0) {
2740 return (R_SUCCESS);
2741 }
2742 }
2743
2744 /* option not found */
2745
2746 return (R_FAILURE);
2747 }
2748
2749 /*
2750 * Name: sortedInsert
2751 * Description: perform an alphabetical sorted insert into a list
2752 * Arguments: r_list - pointer to list to insert next entry into
2753 * a_listSize - pointer to current list size
2754 * a_mntPoint - mount point to insert (is sort key)
2755 * a_fsType - file system type for mount point
2756 * a_mntOptions - file syste mount options for mount point
2757 * Output: None
2758 * Returns: None
2759 */
2760
2761 static void
sortedInsert(FSI_T ** r_list,long * a_listSize,char * a_mntPoint,char * a_fsType,char * a_mntOptions)2762 sortedInsert(FSI_T **r_list, long *a_listSize, char *a_mntPoint,
2763 char *a_fsType, char *a_mntOptions)
2764 {
2765 int listSize;
2766 FSI_T *list;
2767 int n;
2768
2769 /* entry assertions */
2770
2771 assert(a_listSize != (long *)NULL);
2772 assert(a_mntPoint != NULL);
2773 assert(a_fsType != NULL);
2774 assert(a_mntOptions != NULL);
2775
2776 /* entry debugging info */
2777
2778 echoDebug(DBG_SINS_ENTRY, a_mntPoint, a_fsType, a_mntOptions);
2779
2780 /* localize references to the list and list size */
2781
2782 listSize = *a_listSize;
2783 list = *r_list;
2784
2785 /*
2786 * if list empty insert this entry as the first one in the list
2787 */
2788
2789 if (listSize == 0) {
2790 /* allocate new entry for list */
2791 listSize++;
2792 list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1));
2793
2794 /* first entry is data passed to this function */
2795 list[0].fsi_mntPoint = strdup(a_mntPoint);
2796 list[0].fsi_fsType = strdup(a_fsType);
2797 list[0].fsi_mntOptions = strdup(a_mntOptions);
2798
2799 /* second entry is all NULL - end of entry marker */
2800 list[1].fsi_mntPoint = NULL;
2801 list[1].fsi_fsType = NULL;
2802 list[1].fsi_mntOptions = NULL;
2803
2804 /* restore list and list size references to caller */
2805 *a_listSize = listSize;
2806 *r_list = list;
2807
2808 return;
2809 }
2810
2811 /*
2812 * list not empty - scan looking for largest match
2813 */
2814
2815 for (n = 0; n < listSize; n++) {
2816 int c;
2817
2818 /* compare target with current list entry */
2819
2820 c = strcmp(list[n].fsi_mntPoint, a_mntPoint);
2821
2822 if (c == 0) {
2823 char *me;
2824 long len;
2825
2826 /* entry already in list -- merge entries */
2827
2828 len = strlen(list[n].fsi_mntOptions) +
2829 strlen(a_mntOptions) + 2;
2830 me = (char *)calloc(1, len);
2831
2832 /* merge two mount options lists into one */
2833
2834 (void) strlcat(me, list[n].fsi_mntOptions, len);
2835 (void) strlcat(me, ",", len);
2836 (void) strlcat(me, a_mntOptions, len);
2837
2838 /* free old list, replace with merged one */
2839
2840 free(list[n].fsi_mntOptions);
2841 list[n].fsi_mntOptions = me;
2842
2843 echoDebug(DBG_SORTEDINS_SKIPPED,
2844 n, list[n].fsi_mntPoint, a_fsType,
2845 list[n].fsi_fsType, a_mntOptions,
2846 list[n].fsi_mntOptions);
2847
2848 continue;
2849 } else if (c < 0) {
2850 /* entry before this one - skip */
2851 continue;
2852 }
2853
2854 /*
2855 * entry after this one - insert new entry
2856 */
2857
2858 /* allocate one more entry and make space for new entry */
2859 listSize++;
2860 list = (FSI_T *)realloc(list,
2861 sizeof (FSI_T)*(listSize+1));
2862 (void) memmove(&(list[n+1]), &(list[n]),
2863 sizeof (FSI_T)*(listSize-n));
2864
2865 /* insert this entry into list */
2866 list[n].fsi_mntPoint = strdup(a_mntPoint);
2867 list[n].fsi_fsType = strdup(a_fsType);
2868 list[n].fsi_mntOptions = strdup(a_mntOptions);
2869
2870 /* restore list and list size references to caller */
2871 *a_listSize = listSize;
2872 *r_list = list;
2873
2874 return;
2875 }
2876
2877 /*
2878 * all entries are before this one - append to end of list
2879 */
2880
2881 /* allocate new entry at end of list */
2882 listSize++;
2883 list = (FSI_T *)realloc(list, sizeof (FSI_T)*(listSize+1));
2884
2885 /* append this entry to the end of the list */
2886 list[listSize-1].fsi_mntPoint = strdup(a_mntPoint);
2887 list[listSize-1].fsi_fsType = strdup(a_fsType);
2888 list[listSize-1].fsi_mntOptions = strdup(a_mntOptions);
2889
2890 /* restore list and list size references to caller */
2891 *a_listSize = listSize;
2892 *r_list = list;
2893 }
2894
2895 /*
2896 * Name: calculateFileSystemConfig
2897 * Description: generate sorted list of all mounted file systems
2898 * Arguments: a_gdt - global data structure to place sorted entries into
2899 * Output: None
2900 * Returns: R_SUCCESS - successfully generated mounted file systems list
2901 * R_FAILURE - options is not present
2902 * R_ERROR - unable to determine if option is present or not
2903 */
2904
2905 static int
calculateFileSystemConfig(GLOBALDATA_T * a_gdt)2906 calculateFileSystemConfig(GLOBALDATA_T *a_gdt)
2907 {
2908 FILE *fp;
2909 struct mnttab mntbuf;
2910 FSI_T *list;
2911 long listSize;
2912
2913 /* entry assetions */
2914
2915 assert(a_gdt != (GLOBALDATA_T *)NULL);
2916
2917 /* allocate a list that has one termination entry */
2918
2919 list = (FSI_T *)calloc(1, sizeof (FSI_T));
2920 list[0].fsi_mntPoint = NULL;
2921 list[0].fsi_fsType = NULL;
2922 list[0].fsi_mntOptions = NULL;
2923 listSize = 0;
2924
2925 /* open the mount table for reading */
2926
2927 fp = fopen(MNTTAB, "r");
2928 if (fp == (FILE *)NULL) {
2929 return (R_ERROR);
2930 }
2931
2932 /* debugging info */
2933
2934 echoDebug(DBG_CALCSCFG_MOUNTED);
2935
2936 /* go through all the specials looking for the device */
2937
2938 while (getmntent(fp, &mntbuf) == 0) {
2939 if (mntbuf.mnt_mountp[0] == '/') {
2940 sortedInsert(&list, &listSize,
2941 strdup(mntbuf.mnt_mountp),
2942 strdup(mntbuf.mnt_fstype),
2943 strdup(mntbuf.mnt_mntopts ? mntbuf.mnt_mntopts : ""));
2944 }
2945
2946 /*
2947 * Set flag if we are in a non-global zone and it is in
2948 * the mounted state.
2949 */
2950
2951 if (strcmp(mntbuf.mnt_mountp, "/a") == 0 &&
2952 strcmp(mntbuf.mnt_special, "/a") == 0 &&
2953 strcmp(mntbuf.mnt_fstype, "lofs") == 0) {
2954 a_gdt->inMountedState = B_TRUE;
2955 }
2956
2957 }
2958
2959 /* close mount table file */
2960
2961 (void) fclose(fp);
2962
2963 /* store list pointers in global data structure */
2964
2965 a_gdt->gd_fileSystemConfig = list;
2966 a_gdt->gd_fileSystemConfigLen = listSize;
2967
2968 return (R_SUCCESS);
2969 }
2970
2971 /*
2972 * Name: adjustResults
2973 * Description: adjust output result code before existing
2974 * Arguments: a_result - result code to adjust
2975 * Returns: int - adjusted result code
2976 */
2977
2978 static int
adjustResults(int a_result)2979 adjustResults(int a_result)
2980 {
2981 boolean_t negate = getNegateResults();
2982 int realResult;
2983
2984 /* adjust code as appropriate */
2985
2986 switch (a_result) {
2987 case R_SUCCESS: /* condition satisfied */
2988 realResult = ((negate == B_TRUE) ? 1 : 0);
2989 break;
2990 case R_FAILURE: /* condition not satisfied */
2991 realResult = ((negate == B_TRUE) ? 0 : 1);
2992 break;
2993 case R_USAGE: /* usage errors */
2994 realResult = 2;
2995 break;
2996 case R_ERROR: /* condition could not be determined */
2997 default:
2998 realResult = 3;
2999 break;
3000 }
3001
3002 /* debugging output */
3003
3004 log_msg(LOG_MSG_DEBUG, DBG_ADJUST_RESULTS, a_result, negate,
3005 realResult);
3006
3007 /* return results */
3008
3009 return (realResult);
3010 }
3011
3012 /*
3013 * Name: setCmdLinePath
3014 * Description: set global command line path
3015 * Arguments: path - path to set from the command line
3016 * args - command line args
3017 * num_args - number of command line args
3018 * Returns: R_SUCCESS - root path successfully set
3019 * R_FAILURE - root path could not be set
3020 * R_ERROR - fatal error attempting to set root path
3021 */
3022
3023 static void
setCmdLinePath(char ** path,char ** args,int num_args)3024 setCmdLinePath(char **path, char **args, int num_args)
3025 {
3026 char rp[PATH_MAX] = { '\0' };
3027 struct stat statbuf;
3028
3029 if (*path != NULL) {
3030 return;
3031 }
3032
3033 /*
3034 * If a path "pkgcond is_global_zone [path]" is provided on the
3035 * command line it must be the last argument.
3036 */
3037
3038 if (realpath(args[num_args - 1], rp) != NULL) {
3039 if (stat(rp, &statbuf) == 0) {
3040 /* make sure the target is a directory */
3041 if ((statbuf.st_mode & S_IFDIR)) {
3042 *path = strdup(rp);
3043 } else {
3044 *path = NULL;
3045 }
3046 }
3047 }
3048 }
3049
3050 /*
3051 * Name: setRootPath
3052 * Description: set global root path returned by getRootPath
3053 * Arguments: a_path - root path to set
3054 * a_mustExist - B_TRUE if path must exist (else error)
3055 * - B_FALSE if path may not exist
3056 * Returns: R_SUCCESS - root path successfully set
3057 * R_FAILURE - root path could not be set
3058 * R_ERROR - fatal error attempting to set root path
3059 */
3060
3061 static int
setRootPath(char * a_path,char * a_envVar,boolean_t a_mustExist)3062 setRootPath(char *a_path, char *a_envVar, boolean_t a_mustExist)
3063 {
3064 char rp[PATH_MAX] = { '\0' };
3065 struct stat statbuf;
3066
3067 /* if no data then issue warning and return success */
3068
3069 if ((a_path == NULL) || (*a_path == '\0')) {
3070 echoDebug(DBG_NO_DEFAULT_ROOT_PATH_SET);
3071 return (R_SUCCESS);
3072 }
3073
3074 /* path present - resolve to absolute path */
3075
3076 if (realpath(a_path, rp) == NULL) {
3077 if (a_mustExist == B_TRUE) {
3078 /* must exist ... error */
3079 log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_INVALID,
3080 a_path, strerror(errno));
3081 return (R_ERROR);
3082 } else {
3083 /* may not exist - use path as specified */
3084 (void) strcpy(rp, a_path);
3085 }
3086 }
3087
3088 /* debugging output */
3089
3090 echoDebug(DBG_DEFAULT_ROOT_PATH_SET, rp, a_envVar ? a_envVar : "");
3091
3092 /* validate path existence if it must exist */
3093
3094 if (a_mustExist == B_TRUE) {
3095
3096 /* get node status */
3097
3098 if (stat(rp, &statbuf) != 0) {
3099 log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_INVALID,
3100 rp, strerror(errno));
3101 return (R_ERROR);
3102 }
3103
3104 /* make sure the target is a directory */
3105
3106 if (!(statbuf.st_mode & S_IFDIR)) {
3107 log_msg(LOG_MSG_ERR, ERR_DEFAULT_ROOT_NOT_DIR, rp);
3108 return (R_ERROR);
3109 }
3110 }
3111
3112 /* target exists and is a directory - set */
3113
3114 echoDebug(DBG_SET_ROOT_PATH_TO, rp);
3115
3116 /* store copy of resolved root path */
3117
3118 _rootPath = strdup(rp);
3119
3120 /* success! */
3121
3122 return (R_SUCCESS);
3123 }
3124
3125 /*
3126 * Name: testPath
3127 * Description: determine if a path meets the specified conditions
3128 * Arguments: a_tt - conditions to test path against
3129 * a_format - format to use to generate path
3130 * arguments following a_format - as needed for a_format
3131 * Returns: R_SUCCESS - the path meets all of the specified conditions
3132 * R_FAILURE - the path does not meet all of the conditions
3133 * R_ERROR - error attempting to test path
3134 */
3135
3136 /*PRINTFLIKE2*/
3137 static int
testPath(TEST_TYPES a_tt,char * a_format,...)3138 testPath(TEST_TYPES a_tt, char *a_format, ...)
3139 {
3140 char *mbPath; /* copy for the path to be returned */
3141 char bfr[1];
3142 int r;
3143 size_t vres = 0;
3144 struct stat statbuf;
3145 va_list ap;
3146 int fd;
3147
3148 /* entry assertions */
3149
3150 assert(a_format != NULL);
3151 assert(*a_format != '\0');
3152
3153 /* determine size of the message in bytes */
3154
3155 va_start(ap, a_format);
3156 vres = vsnprintf(bfr, 1, a_format, ap);
3157 va_end(ap);
3158
3159 assert(vres > 0);
3160
3161 /* allocate storage to hold the message */
3162
3163 mbPath = (char *)calloc(1, vres+2);
3164 assert(mbPath != NULL);
3165
3166 /* generate the results of the printf conversion */
3167
3168 va_start(ap, a_format);
3169 vres = vsnprintf(mbPath, vres+1, a_format, ap);
3170 va_end(ap);
3171
3172 assert(vres > 0);
3173
3174 echoDebug(DBG_TEST_PATH, mbPath, (unsigned long)a_tt);
3175
3176 /*
3177 * When a path given to open(2) contains symbolic links, the
3178 * open system call first resolves all symbolic links and then
3179 * opens that final "resolved" path. As a result, it is not
3180 * possible to check the result of an fstat(2) against the
3181 * file descriptor returned by open(2) for S_IFLNK (a symbolic
3182 * link) since all symbolic links are resolved before the
3183 * target is opened.
3184 *
3185 * When testing the target as being (or not being) a symbolic
3186 * link, first use lstat(2) against the target to determine
3187 * whether or not the specified target itself is (or is not) a
3188 * symbolic link.
3189 */
3190
3191 if (a_tt & (TEST_IS_SYMBOLIC_LINK|TEST_NOT_SYMBOLIC_LINK)) {
3192 /*
3193 * testing target is/is not a symbolic link; use lstat
3194 * to determine the status of the target itself rather
3195 * than what the target might finally address.
3196 */
3197
3198 if (lstat(mbPath, &statbuf) != 0) {
3199 echoDebug(DBG_CANNOT_LSTAT_PATH, mbPath,
3200 strerror(errno));
3201 free(mbPath);
3202 return (R_FAILURE);
3203 }
3204
3205 /* Is the target required to be a symbolic link? */
3206
3207 if (a_tt & TEST_IS_SYMBOLIC_LINK) {
3208 /* target must be a symbolic link */
3209 if (!(statbuf.st_mode & S_IFLNK)) {
3210 /* failure: target is not a symbolic link */
3211 echoDebug(DBG_IS_NOT_A_SYMLINK, mbPath);
3212 free(mbPath);
3213 return (R_FAILURE);
3214 }
3215 /* success: target is a symbolic link */
3216 echoDebug(DBG_SYMLINK_IS, mbPath);
3217 }
3218
3219 /* Is the target required to not be a symbolic link? */
3220
3221 if (a_tt & TEST_NOT_SYMBOLIC_LINK) {
3222 /* target must not be a symbolic link */
3223 if (statbuf.st_mode & S_IFLNK) {
3224 /* failure: target is a symbolic link */
3225 echoDebug(DBG_IS_A_SYMLINK, mbPath);
3226 free(mbPath);
3227 return (R_FAILURE);
3228 }
3229 /* success: target is not a symbolic link */
3230 echoDebug(DBG_SYMLINK_NOT, mbPath);
3231 }
3232
3233 /*
3234 * if only testing is/is not a symbolic link, then
3235 * no need to open the target: return success.
3236 */
3237
3238 if (!(a_tt &
3239 (~(TEST_IS_SYMBOLIC_LINK|TEST_NOT_SYMBOLIC_LINK)))) {
3240 free(mbPath);
3241 return (R_SUCCESS);
3242 }
3243 }
3244
3245 /* resolve path and remove any whitespace */
3246
3247 r = resolvePath(&mbPath);
3248 if (r != R_SUCCESS) {
3249 echoDebug(DBG_TEST_PATH_NO_RESOLVE, mbPath);
3250 free(mbPath);
3251 if (a_tt & TEST_NOT_EXISTS) {
3252 return (R_SUCCESS);
3253 }
3254 return (r);
3255 }
3256
3257 echoDebug(DBG_TEST_PATH_RESOLVE, mbPath);
3258
3259 /* open the file - this is the basic existence test */
3260
3261 fd = open(mbPath, O_RDONLY|O_LARGEFILE, 0);
3262
3263 /* existence test failed if file cannot be opened */
3264
3265 if (fd < 0) {
3266 /*
3267 * target could not be opened - if testing for non-existence,
3268 * return success, otherwise return failure
3269 */
3270 if (a_tt & TEST_NOT_EXISTS) {
3271 echoDebug(DBG_CANNOT_ACCESS_PATH_OK, mbPath);
3272 free(mbPath);
3273 return (R_SUCCESS);
3274 }
3275
3276 echoDebug(DBG_CANNOT_ACCESS_PATH_BUT_SHOULD,
3277 mbPath, strerror(errno));
3278 free(mbPath);
3279
3280 return (R_FAILURE);
3281 }
3282
3283 /*
3284 * target successfully opened - if testing for non-existence,
3285 * return failure, otherwise continue with specified tests
3286 */
3287
3288 if (a_tt & TEST_NOT_EXISTS) {
3289 /* testing for non-existence: return failure */
3290 echoDebug(DBG_TEST_EXISTS_SHOULD_NOT, mbPath);
3291 free(mbPath);
3292 (void) close(fd);
3293 return (R_FAILURE);
3294 }
3295
3296 /* get the file status */
3297
3298 r = fstat(fd, &statbuf);
3299 if (r != 0) {
3300 echoDebug(DBG_PATH_DOES_NOT_EXIST, mbPath, strerror(errno));
3301 (void) close(fd);
3302 free(mbPath);
3303 return (R_FAILURE);
3304 }
3305
3306 /* required to be a directory? */
3307
3308 if (a_tt & TEST_IS_DIRECTORY) {
3309 if (!(statbuf.st_mode & S_IFDIR)) {
3310 /* is not a directory */
3311 echoDebug(DBG_IS_NOT_A_DIRECTORY, mbPath);
3312 free(mbPath);
3313 return (R_FAILURE);
3314 }
3315 /* a directory */
3316 echoDebug(DBG_DIRECTORY_IS, mbPath);
3317 }
3318
3319 /* required to not be a directory? */
3320
3321 if (a_tt & TEST_NOT_DIRECTORY) {
3322 if (statbuf.st_mode & S_IFDIR) {
3323 /* is a directory */
3324 echoDebug(DBG_IS_A_DIRECTORY, mbPath);
3325 free(mbPath);
3326 return (R_FAILURE);
3327 }
3328 /* not a directory */
3329 echoDebug(DBG_DIRECTORY_NOT, mbPath);
3330 }
3331
3332 /* required to be a file? */
3333
3334 if (a_tt & TEST_IS_FILE) {
3335 if (!(statbuf.st_mode & S_IFREG)) {
3336 /* is not a regular file */
3337 echoDebug(DBG_IS_NOT_A_FILE, mbPath);
3338 free(mbPath);
3339 return (R_FAILURE);
3340 }
3341 /* a regular file */
3342 echoDebug(DBG_FILE_IS, mbPath);
3343 }
3344
3345 /* required to not be a file? */
3346
3347 if (a_tt & TEST_NOT_FILE) {
3348 if (statbuf.st_mode & S_IFREG) {
3349 /* is a regular file */
3350 echoDebug(DBG_IS_A_FILE, mbPath);
3351 free(mbPath);
3352 return (R_FAILURE);
3353 }
3354 /* not a regular file */
3355 echoDebug(DBG_FILE_NOT, mbPath);
3356 }
3357
3358 /*
3359 * Find token (global) in file pointed to by mbPath.
3360 * token is only compared to first word in mbPath.
3361 */
3362
3363 if (a_tt & TEST_GLOBAL_TOKEN_IN_FILE) {
3364 if (!(statbuf.st_mode & S_IFREG)) {
3365 /* is not a regular file */
3366 echoDebug(DBG_IS_NOT_A_FILE, mbPath);
3367 free(mbPath);
3368 return (R_FAILURE);
3369 }
3370 /* If global exists then we're not in a non-global zone */
3371 if (findToken(mbPath, GLOBAL_ZONENAME) == R_SUCCESS) {
3372 echoDebug(DBG_TOKEN__EXISTS, GLOBAL_ZONENAME, mbPath);
3373 free(mbPath);
3374 return (R_FAILURE);
3375 }
3376 }
3377
3378 (void) close(fd);
3379
3380 /* success! */
3381
3382 echoDebug(DBG_TESTPATH_OK, mbPath);
3383
3384 /* free up temp storage used to hold path to test */
3385
3386 free(mbPath);
3387
3388 return (R_SUCCESS);
3389 }
3390
3391 /*
3392 * Name: findToken
3393 * Description: Find first token in file.
3394 * Arguments:
3395 * path - file to search for token
3396 * token - string to search for
3397 * Returns:
3398 * R_SUCCESS - the token exists
3399 * R_FAILURE - the token does not exist
3400 * R_ERROR - fatal error attempting to find token
3401 */
3402
3403 static int
findToken(char * path,char * token)3404 findToken(char *path, char *token)
3405 {
3406 FILE *fp;
3407 char *cp;
3408 char line[MAXPATHLEN];
3409
3410 if (path == NULL || token == NULL) {
3411 return (R_ERROR);
3412 }
3413 if ((fp = fopen(path, "r")) == NULL) {
3414 return (R_ERROR);
3415 }
3416
3417 while (fgets(line, sizeof (line), fp) != NULL) {
3418 for (cp = line; *cp && isspace(*cp); cp++);
3419 /* skip comments */
3420 if (*cp == '#') {
3421 continue;
3422 }
3423 if (pkgstrContainsToken(cp, token, ":")) {
3424 (void) fclose(fp);
3425 return (R_SUCCESS);
3426 }
3427 }
3428 (void) fclose(fp);
3429 return (R_FAILURE);
3430 }
3431
3432
3433 /*
3434 * Name: resolvePath
3435 * Description: fully resolve a path to an absolute real path
3436 * Arguments: r_path - pointer to pointer to malloc()ed storage containing
3437 * the path to resolve - this path may be reallocated
3438 * as necessary to hold the fully resolved path
3439 * Output: r_path - is realloc()ed as necessary
3440 * Returns: R_SUCCESS - the path is fully resolved
3441 * R_FAILURE - the path could not be resolved
3442 * R_ERROR - fatal error attempting to resolve path
3443 */
3444
3445 static int
resolvePath(char ** r_path)3446 resolvePath(char **r_path)
3447 {
3448 int i;
3449 char resolvedPath[MAXPATHLEN+1] = {'\0'};
3450 size_t mbPathlen; /* length of multi-byte path */
3451 size_t wcPathlen; /* length of wide-character path */
3452 wchar_t *wcPath; /* wide-character version of the path */
3453 wchar_t *wptr; /* scratch pointer */
3454
3455 /* entry assertions */
3456
3457 assert(r_path != (char **)NULL);
3458
3459 /* return error if the path is completely empty */
3460
3461 if (*r_path == '\0') {
3462 return (R_FAILURE);
3463 }
3464
3465 /* remove all leading whitespace */
3466
3467 removeLeadingWhitespace(r_path);
3468
3469 /*
3470 * convert to real path: an absolute pathname that names the same file,
3471 * whose resolution does not involve ".", "..", or symbolic links.
3472 */
3473
3474 if (realpath(*r_path, resolvedPath) != NULL) {
3475 free(*r_path);
3476 *r_path = strdup(resolvedPath);
3477 }
3478
3479 /*
3480 * convert the multi-byte version of the path to a
3481 * wide-character rendering, for doing our figuring.
3482 */
3483
3484 mbPathlen = strlen(*r_path);
3485
3486 if ((wcPath = (wchar_t *)
3487 calloc(1, sizeof (wchar_t)*(mbPathlen+1))) == NULL) {
3488 return (R_FAILURE);
3489 }
3490
3491 /*LINTED*/
3492 if ((wcPathlen = mbstowcs(wcPath, *r_path, mbPathlen)) == -1) {
3493 free(wcPath);
3494 return (R_FAILURE);
3495 }
3496
3497 /*
3498 * remove duplicate slashes first ("//../" -> "/")
3499 */
3500
3501 for (wptr = wcPath, i = 0; i < wcPathlen; i++) {
3502 *wptr++ = wcPath[i];
3503
3504 if (wcPath[i] == '/') {
3505 i++;
3506
3507 while (wcPath[i] == '/') {
3508 i++;
3509 }
3510
3511 i--;
3512 }
3513 }
3514
3515 *wptr = '\0';
3516
3517 /*
3518 * now convert back to the multi-byte format.
3519 */
3520
3521 /*LINTED*/
3522 if (wcstombs(*r_path, wcPath, mbPathlen) == -1) {
3523 free(wcPath);
3524 return (R_FAILURE);
3525 }
3526
3527 /* at this point have a path */
3528
3529 /* free up temporary storage */
3530
3531 free(wcPath);
3532
3533 return (R_SUCCESS);
3534 }
3535
3536 /*
3537 * Name: removeLeadingWhitespace
3538 * Synopsis: Remove leading whitespace from string
3539 * Description: Remove all leading whitespace characters from a string
3540 * Arguments: a_str - [RO, *RW] - (char **)
3541 * Pointer to handle to string (in allocated storage) to
3542 * remove all leading whitespace from
3543 * Returns: void
3544 * The input string is modified as follows:
3545 * == NULL:
3546 * - input string was NULL
3547 * - input string is all whitespace
3548 * != NULL:
3549 * - copy of input string with leading
3550 * whitespace removed
3551 * CAUTION: The input string must be allocated space (via malloc() or
3552 * strdup()) - it must not be a static or inline character string
3553 * NOTE: The input string a_str will be freed with 'free'
3554 * if it is all whitespace, or if it contains any leading
3555 * whitespace characters
3556 * NOTE: Any string returned is placed in new storage for the
3557 * calling method. The caller must use 'free' to dispose
3558 * of the storage once the string is no longer needed.
3559 * Errors: If the string cannot be created, the process exits
3560 */
3561
3562 static void
removeLeadingWhitespace(char ** a_str)3563 removeLeadingWhitespace(char **a_str)
3564 {
3565 char *o_str;
3566
3567 /* entry assertions */
3568
3569 assert(a_str != (char **)NULL);
3570
3571 /* if string is null, just return */
3572
3573 if (*a_str == NULL) {
3574 return;
3575 }
3576 o_str = *a_str;
3577
3578 /* if string is empty, deallocate and return NULL */
3579
3580 if (*o_str == '\0') {
3581 /* free string */
3582 free(*a_str);
3583 *a_str = NULL;
3584 return;
3585 }
3586
3587 /* if first character is not a space, just return */
3588
3589 if (!isspace(*o_str)) {
3590 return;
3591 }
3592
3593 /* advance past all space characters */
3594
3595 while ((*o_str != '\0') && (isspace(*o_str))) {
3596 o_str++;
3597 }
3598
3599 /* if string was all space characters, deallocate and return NULL */
3600
3601 if (*o_str == '\0') {
3602 /* free string */
3603 free(*a_str);
3604 *a_str = NULL;
3605 return;
3606 }
3607
3608 /* have non-space/null byte, return dup, deallocate original */
3609
3610 o_str = strdup(o_str);
3611 free(*a_str);
3612 *a_str = o_str;
3613 }
3614
3615 /*
3616 * Name: getZoneName
3617 * Description: get the name of the zone this process is running in
3618 * Arguments: r_zoneName - pointer to pointer to receive zone name
3619 * Output: r_zoneName - a pointer to malloc()ed storage containing
3620 * the zone name this process is running in is stored
3621 * in the location pointed to by r_zoneName
3622 * Returns: R_SUCCESS - the zone name is successfully returned
3623 * R_FAILURE - the zone name is not successfully returned
3624 * R_ERROR - error attempting to get the zone name
3625 */
3626
3627 static int
getZoneName(char ** r_zoneName)3628 getZoneName(char **r_zoneName)
3629 {
3630 static char zoneName[ZONENAME_MAX] = { '\0' };
3631
3632 /* if zone name not already present, retrieve and cache name */
3633
3634 if (zoneName[0] == '\0') {
3635 if (getzonenamebyid(getzoneid(), zoneName,
3636 sizeof (zoneName)) < 0) {
3637 log_msg(LOG_MSG_ERR, ERR_CANNOT_GET_ZONENAME);
3638 return (R_ERROR);
3639 }
3640 }
3641
3642 /* return cached zone name */
3643
3644 *r_zoneName = zoneName;
3645 return (R_SUCCESS);
3646 }
3647
3648 /*
3649 * Name: getRootPath
3650 * Description: get the root path being tested by this process
3651 * Arguments: r_rootPath - pointer to pointer to receive root path
3652 * Output: r_rootPath - a pointer to malloc()ed storage containing
3653 * the root path name this process is testing
3654 * Returns: R_SUCCESS - the root path is successfully returned
3655 * R_FAILURE - the root path is not successfully returned
3656 * R_ERROR - error attempting to get the root path
3657 */
3658
3659 static int
getRootPath(char ** r_rootPath)3660 getRootPath(char **r_rootPath)
3661 {
3662 *r_rootPath = _rootPath;
3663 return (R_SUCCESS);
3664 }
3665
3666 /*
3667 * Name: setVerbose
3668 * Description: Turns on verbose output
3669 * Scope: public
3670 * Arguments: verbose = B_TRUE indicates verbose mode
3671 * Returns: none
3672 */
3673
3674 static void
setVerbose(boolean_t setting)3675 setVerbose(boolean_t setting)
3676 {
3677 /* set log verbose messages */
3678
3679 log_set_verbose(setting);
3680
3681 /* set interactive messages */
3682
3683 echoSetFlag(setting);
3684 }
3685
3686 /*
3687 * Name: negate_results
3688 * Description: control negation of results
3689 * Scope: public
3690 * Arguments: setting
3691 * == B_TRUE indicates negated results mode
3692 * == B_FALSE indicates non-negated results mode
3693 * Returns: none
3694 */
3695
3696 static void
setNegateResults(boolean_t setting)3697 setNegateResults(boolean_t setting)
3698 {
3699 log_msg(LOG_MSG_DEBUG, DBG_SET_NEGATE_RESULTS,
3700 _negateResults, setting);
3701
3702 _negateResults = setting;
3703 }
3704
3705 /*
3706 * Name: getNegateResults
3707 * Description: Returns whether or not to results are negated
3708 * Scope: public
3709 * Arguments: none
3710 * Returns: B_TRUE - results are negated
3711 * B_FALSE - results are not negated
3712 */
3713
3714 static boolean_t
getNegateResults(void)3715 getNegateResults(void)
3716 {
3717 return (_negateResults);
3718 }
3719
3720 /*
3721 * Name: usage
3722 * Description: output usage string
3723 * Arguments: a_format - format to use to generate message
3724 * arguments following a_format - as needed for a_format
3725 * Output: Outputs the usage string to stderr.
3726 * Returns: R_ERROR
3727 */
3728
3729 static int
usage(char * a_format,...)3730 usage(char *a_format, ...)
3731 {
3732 int cur_cmd;
3733 char cmdlst[LINE_MAX+1] = { '\0' };
3734 char *message;
3735 char bfr[1];
3736 char *p = get_prog_name();
3737 size_t vres = 0;
3738 va_list ap;
3739
3740 /* entry assertions */
3741
3742 assert(a_format != NULL);
3743 assert(*a_format != '\0');
3744
3745 /* determine size of the message in bytes */
3746
3747 va_start(ap, a_format);
3748 /* LINTED warning: variable format specifier to vsnprintf(); */
3749 vres = vsnprintf(bfr, 1, a_format, ap);
3750 va_end(ap);
3751
3752 assert(vres > 0);
3753
3754 /* allocate storage to hold the message */
3755
3756 message = (char *)calloc(1, vres+2);
3757 assert(message != NULL);
3758
3759 /* generate the results of the printf conversion */
3760
3761 va_start(ap, a_format);
3762 /* LINTED warning: variable format specifier to vsnprintf(); */
3763 vres = vsnprintf(message, vres+1, a_format, ap);
3764 va_end(ap);
3765
3766 assert(vres > 0);
3767
3768 /* generate list of all defined conditions */
3769
3770 for (cur_cmd = 0; cmds[cur_cmd].c_name != NULL; cur_cmd++) {
3771 (void) strlcat(cmdlst, "\t", sizeof (cmdlst));
3772 (void) strlcat(cmdlst, cmds[cur_cmd].c_name, sizeof (cmdlst));
3773 if (cmds[cur_cmd].c_args != NULL) {
3774 (void) strlcat(cmdlst, cmds[cur_cmd].c_args,
3775 sizeof (cmdlst));
3776 }
3777 (void) strlcat(cmdlst, "\n", sizeof (cmdlst));
3778 }
3779
3780 /* output usage with conditions */
3781
3782 log_msg(LOG_MSG_INFO, MSG_USAGE, message, p ? p : "pkgcond", cmdlst);
3783
3784 return (R_ERROR);
3785 }
3786
3787 /*
3788 * Name: parseGlobalData
3789 * Description: parse environment global data and store in global data structure
3790 * Arguments: a_envVar - pointer to string representing the name of the
3791 * environment variable to get and parse
3792 * r_gdt - pointer to pointer to global data structure to fill in
3793 * using the parsed data from a_envVar
3794 * Output: none
3795 * Returns: R_SUCCESS - the global data is successfully parsed
3796 * R_FAILURE - problem parsing global data
3797 * R_ERROR - fatal error attempting to parse global data
3798 */
3799
3800 static int
parseGlobalData(char * a_envVar,GLOBALDATA_T ** r_gdt)3801 parseGlobalData(char *a_envVar, GLOBALDATA_T **r_gdt)
3802 {
3803 int r;
3804 int n;
3805 char *a;
3806 SML_TAG *tag;
3807 SML_TAG *ntag;
3808
3809 assert(r_gdt != (GLOBALDATA_T **)NULL);
3810
3811 /*
3812 * allocate space for global data structure if needed
3813 */
3814
3815 if (*r_gdt == (GLOBALDATA_T *)NULL) {
3816 *r_gdt = (GLOBALDATA_T *)calloc(1, sizeof (GLOBALDATA_T));
3817 }
3818
3819 /*
3820 * get initial installation indication:
3821 * If the initial install variable is set to "true", then an initial
3822 * installation of Solaris is underway. When this condition is true:
3823 * - if the path being checked is the package install root, then
3824 * the path is considered to be an 'alternative root' which is
3825 * currently being installed.
3826 * - if the path being checked is not the package install root, then
3827 * the path needs to be further analyzed to determine what it may
3828 * be referring to.
3829 */
3830
3831 a = getenv(ENV_VAR_INITIAL_INSTALL);
3832 if ((a != NULL) && (strcasecmp(a, "true") == 0)) {
3833 (*r_gdt)->gd_initialInstall = B_TRUE;
3834 }
3835
3836 /* get current zone name */
3837
3838 r = getZoneName(&(*r_gdt)->gd_zoneName);
3839 if (r != R_SUCCESS) {
3840 (*r_gdt)->gd_zoneName = "";
3841 }
3842
3843 /*
3844 * get zone installation status:
3845 * - If the package install zone name is not set, then an installation
3846 * of a global zone, or of a non-global zone, is not underway.
3847 * - If the package install zone name is set to "global", then an
3848 * installation of a global zone is underway. In this case, no path
3849 * can be a netinstall image, diskless client, mounted miniroot,
3850 * non-global zone, the current running system, alternative root,
3851 * or alternative boot environment.
3852 * - If the package install zone name is set to a value other than
3853 * "global", then an installation of a non-global zone with that name
3854 * is underway. In this case, no path can be a netinstall image,
3855 * diskless client, mounted miniroot, global zone, the current
3856 * running system, alternative root, or alternative boot environment.
3857 */
3858
3859 a = getenv(ENV_VAR_PKGZONENAME);
3860 if ((a == NULL) || (*a == '\0')) {
3861 /* not installing a zone */
3862 (*r_gdt)->gd_globalZoneInstall = B_FALSE;
3863 (*r_gdt)->gd_nonglobalZoneInstall = B_FALSE;
3864 } else if (strcmp(a, GLOBAL_ZONENAME) == 0) {
3865 /* installing a global zone */
3866 (*r_gdt)->gd_globalZoneInstall = B_TRUE;
3867 (*r_gdt)->gd_nonglobalZoneInstall = B_FALSE;
3868 (*r_gdt)->gd_zoneName = a;
3869 } else {
3870 /* installing a non-global zone by that name */
3871 (*r_gdt)->gd_globalZoneInstall = B_FALSE;
3872 (*r_gdt)->gd_nonglobalZoneInstall = B_TRUE;
3873 (*r_gdt)->gd_zoneName = a;
3874 }
3875
3876 /*
3877 * get package install root. If it doesn't exist check for
3878 * patch install root (ROOTDIR)
3879 */
3880
3881 a = getenv(ENV_VAR_PKGROOT);
3882 if ((a != NULL) && (*a != '\0')) {
3883 (*r_gdt)->gd_installRoot = a;
3884 } else {
3885 a = getenv(ENV_VAR_PATCHROOT);
3886 if ((a != NULL) && (*a != '\0')) {
3887 (*r_gdt)->gd_installRoot = a;
3888 } else {
3889 (*r_gdt)->gd_installRoot = "/";
3890 }
3891 }
3892
3893 /*
3894 * get patch client version: always set if $ROOTDIR != / and
3895 * the $ROOTDIR/var/sadm/softinfo/INST_RELEASE file exists.
3896 */
3897
3898 a = getenv(ENV_VAR_PATCH_CLIENTVER);
3899 (*r_gdt)->gd_patchClientVersion = (a ? a : "");
3900
3901 /* get the global data environment variable */
3902
3903 a = getenv(a_envVar);
3904
3905 /* if no data then issue warning and return success */
3906
3907 if ((a == NULL) || (*a_envVar == '\0')) {
3908 log_msg(LOG_MSG_DEBUG, DBG_NO_GLOBAL_DATA_AVAILABLE, a_envVar);
3909 return (R_SUCCESS);
3910 }
3911
3912 /* data present - parse into SML structure */
3913
3914 log_msg(LOG_MSG_DEBUG, DBG_PARSE_GLOBAL, a);
3915
3916 r = smlConvertStringToTag(&tag, a);
3917 if (r != R_SUCCESS) {
3918 log_msg(LOG_MSG_ERR, ERR_CANNOT_PARSE_GLOBAL_DATA, a);
3919 return (R_FAILURE);
3920 }
3921
3922 smlDbgPrintTag(tag, DBG_PARSED_ENVIRONMENT, a_envVar);
3923
3924 /* fill in global data structure */
3925
3926 /* find the environment condition information structure */
3927
3928 ntag = smlGetTagByName(tag, 0, TAG_COND_TOPLEVEL);
3929 if (ntag == SML_TAG__NULL) {
3930 log_msg(LOG_MSG_WRN, WRN_PARSED_DATA_MISSING,
3931 TAG_COND_TOPLEVEL);
3932 return (R_FAILURE);
3933 }
3934
3935 /*
3936 * data found - extract what we know about
3937 */
3938
3939 /* parent zone name */
3940
3941 a = smlGetParamByTag(ntag, 0, TAG_COND_PARENT_ZONE, TAG_COND_ZONE_NAME);
3942 (*r_gdt)->gd_parentZoneName = a;
3943
3944 /* parent zone type */
3945
3946 a = smlGetParamByTag(ntag, 0, TAG_COND_PARENT_ZONE, TAG_COND_ZONE_TYPE);
3947 (*r_gdt)->gd_parentZoneType = a;
3948
3949 /* current zone name */
3950
3951 a = smlGetParamByTag(ntag, 0, TAG_COND_CURRENT_ZONE,
3952 TAG_COND_ZONE_NAME);
3953 (*r_gdt)->gd_currentZoneName = a;
3954
3955 /* current zone type */
3956
3957 a = smlGetParamByTag(ntag, 0, TAG_COND_CURRENT_ZONE,
3958 TAG_COND_ZONE_TYPE);
3959 (*r_gdt)->gd_currentZoneType = a;
3960
3961 return (R_SUCCESS);
3962 }
3963
3964 /*
3965 * Name: dumpGlobalData
3966 * Description: dump global data structure using echoDebug
3967 * Arguments: a_gdt - pointer to global data structure to dump
3968 * Outputs: echoDebug is called to output global data strucutre information
3969 * Returns: void
3970 */
3971
3972 static void
dumpGlobalData(GLOBALDATA_T * a_gdt)3973 dumpGlobalData(GLOBALDATA_T *a_gdt)
3974 {
3975 /* entry assertions */
3976
3977 assert(a_gdt != (GLOBALDATA_T *)NULL);
3978
3979 /* debugging enabled, dump the global data structure */
3980
3981 echoDebug(DBG_DUMP_GLOBAL_ENTRY);
3982 echoDebug(DBG_DUMP_GLOBAL_PARENT_ZONE,
3983 a_gdt->gd_parentZoneName ? a_gdt->gd_parentZoneName : "",
3984 a_gdt->gd_parentZoneType ? a_gdt->gd_parentZoneType : "");
3985 echoDebug(DBG_DUMP_GLOBAL_CURRENT_ZONE,
3986 a_gdt->gd_currentZoneName ? a_gdt->gd_currentZoneName : "",
3987 a_gdt->gd_currentZoneType ? a_gdt->gd_currentZoneType : "");
3988
3989 }
3990
3991 /*
3992 * Name: recursionCheck
3993 * Description: prevent recursive calling of functions
3994 * Arguments: r_recursion - pointer to int recursion counter
3995 * a_function - pointer to name of function
3996 * Returns: B_TRUE - function is recursively called
3997 * B_FALSE - function not recursively called
3998 */
3999
4000 static boolean_t
recursionCheck(int * r_recursion,char * a_function)4001 recursionCheck(int *r_recursion, char *a_function)
4002 {
4003 /* prevent recursion */
4004
4005 (*r_recursion)++;
4006 if (*r_recursion > 1) {
4007 echoDebug(DBG_RECURSION, a_function, *r_recursion);
4008 (*r_recursion)--;
4009 return (B_TRUE);
4010 }
4011
4012 echoDebug(DBG_NO_RECURSION, a_function);
4013 return (B_FALSE);
4014 }
4015
4016 /*
4017 * Name: quit
4018 * Description: cleanup and exit
4019 * Arguments: a_retcode - the code to use to determine final exit status;
4020 * if this is NOT "99" and if a "ckreturnFunc" is
4021 * set, then that function is called with a_retcode
4022 * to set the final exit status.
4023 * Valid values are:
4024 * 0 - success
4025 * 1 - package operation failed (fatal error)
4026 * 2 - non-fatal error (warning)
4027 * 3 - user selected quit (operation interrupted)
4028 * 4 - admin settings prevented operation
4029 * 5 - interaction required and -n (non-interactive) specified
4030 * "10" is added to indicate "immediate reboot required"
4031 * "20" is be added to indicate "reboot after install required"
4032 * 99 - do not interpret the code - just exit "99"
4033 * Returns: <<this function does not return - calls exit()>>
4034 * NOTE: This is needed because libinst functions can call "quit(99)"
4035 * to force an error exit.
4036 */
4037
4038 void
quit(int a_retcode)4039 quit(int a_retcode)
4040 {
4041 /* process return code if not quit(99) */
4042
4043 if (a_retcode == 99) {
4044 exit(0x7f); /* processing error (127) */
4045 }
4046
4047 exit(R_FAILURE);
4048 }
4049