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