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