main.c revision 12734:76969fc28795
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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27/* All Rights Reserved */
28
29
30#include <stdio.h>
31#include <limits.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include <signal.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <pkgstrct.h>
41#include <pkginfo.h>
42#include <pkglocs.h>
43#include <locale.h>
44#include <libintl.h>
45#include <assert.h>
46#include <cfext.h>
47#include <instzones_api.h>
48#include <pkglib.h>
49#include <install.h>
50#include <libinst.h>
51#include <libadm.h>
52#include <messages.h>
53
54struct cfent **eptlist;
55extern int	eptnum;
56
57extern char	*pkgdir;
58extern char	**environ;
59
60/* quit.c */
61extern sighdlrFunc_t	*quitGetTrapHandler(void);
62extern void		quitSetSilentExit(boolean_t a_silentExit);
63extern void		quitSetZoneName(char *a_zoneName);
64
65
66
67/* check.c */
68extern void	rcksetPreremoveCheck(boolean_t);
69extern void	rcksetZoneName(char *);
70extern int	rckpriv(void);
71extern int	rckdepend(void);
72extern int	rckrunlevel(void);
73
74/* predepend.c */
75extern void	predepend(char *oldpkg);
76
77/* delmap.c */
78extern int delmap(int flag, char *pkginst, PKGserver *server, VFP_T **tfp);
79
80#define	DEFPATH		"/sbin:/usr/sbin:/usr/bin"
81
82#ifdef	ALLOW_EXCEPTION_PKG_LIST
83#define	SCRIPT	0	/* Tells exception_pkg() which pkg list to use */
84#define	LINK	1
85#endif
86
87#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
88#define	TEXT_DOMAIN "SYS_TEST"
89#endif
90
91/* This is the text for the "-O parent-zone-name=" option */
92
93#define	PARENTZONENAME	"parent-zone-name="
94#define	PARENTZONENAME_LEN	((sizeof (PARENTZONENAME))-1)
95
96/* This is the text for the "-O parent-zone-type=" option */
97
98#define	PARENTZONETYPE	"parent-zone-type="
99#define	PARENTZONETYPE_LEN	((sizeof (PARENTZONETYPE))-1)
100
101struct	admin adm; 	/* holds info about installation admin */
102int	dreboot; 	/* non-zero if reboot required after installation */
103int	ireboot;	/* non-zero if immediate reboot required */
104int	failflag;	/* non-zero if fatal error has occurred */
105int	warnflag;	/* non-zero if non-fatal error has occurred */
106int	pkgverbose;	/* non-zero if verbose mode is selected */
107int	started;
108int	nocnflct = 0; 	/* pkgdbmerg needs this defined */
109int	nosetuid = 0; 	/* pkgdbmerg needs this defined */
110
111char	*pkginst; 	/* current package (source) instance to process */
112
113int	dbchg;
114char	*msgtext;
115char	pkgloc[PATH_MAX];
116
117/*
118 * The following variable is the name of the device to which stdin
119 * is connected during execution of a procedure script. /dev/null is
120 * correct for all ABI compliant packages. For non-ABI-compliant
121 * packages, the '-o' command line switch changes this to /dev/tty
122 * to allow user interaction during these scripts. -- JST
123 */
124static char 	*script_in = PROC_STDIN;	/* assume ABI compliance */
125
126static char	*client_mntdir; 	/* mount point for client's basedir */
127static char	pkgbin[PATH_MAX],
128		rlockfile[PATH_MAX],
129		*admnfile, 		/* file to use for installation admin */
130		*tmpdir; 		/* location to place temporary files */
131
132static boolean_t	path_valid(char *path);
133static void		ckreturn(int retcode, char *msg);
134static void		rmclass(char *aclass, int rm_remote, char *a_zoneName);
135static void		usage(void);
136
137/*
138 * Set by -O debug: debug output is enabled?
139 */
140static boolean_t	debugFlag = B_FALSE;
141
142/*
143 * Set by -O preremovecheck: do remove dependency checking only
144 */
145static boolean_t	preremoveCheck = B_FALSE;
146
147/* Set by -O parent-zone-name= */
148
149static char		*parentZoneName = (char *)NULL;
150
151/* Set by -O parent-zone-type= */
152
153static char		*parentZoneType = (char *)NULL;
154
155static int	nointeract;	/* != 0 no interaction with user should occur */
156
157
158
159int
160main(int argc, char *argv[])
161{
162	FILE		*fp;
163	char		*abi_comp_ptr;
164	char		*abi_sym_ptr;
165	char		*p;
166	char		*prog_full_name = NULL;
167	char		*pt;
168	char		*value;
169	char		*vfstab_file = NULL;
170	char		*zoneName = (char *)NULL;
171	char		cmdbin[PATH_MAX];
172	char		param[MAX_PKG_PARAM_LENGTH];
173	char		path[PATH_MAX];
174	char		script[PATH_MAX];
175	int		c;
176	int		err;
177	int		fd;
178	int		i;
179	int		map_client = 1;
180	int		n;
181	int		nodelete = 0; 	/* do not delete file or run scripts */
182	int		pkgrmremote = 0;	/* dont remove remote objects */
183	struct sigaction	nact;
184	struct sigaction	oact;
185	PKGserver	pkgserver = NULL;
186	VFP_T		*tmpfp;
187
188	/* reset contents of all default paths */
189
190	(void) memset(cmdbin, '\0', sizeof (cmdbin));
191
192	/* initialize locale environment */
193
194	(void) setlocale(LC_ALL, "");
195	(void) textdomain(TEXT_DOMAIN);
196
197	/* initialize program name */
198
199	prog_full_name = argv[0];
200	(void) set_prog_name(argv[0]);
201
202	/* tell spmi zones interface how to access package output functions */
203
204	z_set_output_functions(echo, echoDebug, progerr);
205
206	/* exit if not root */
207
208	if (getuid()) {
209		progerr(ERR_NOT_ROOT, get_prog_name());
210		exit(1);
211		/* NOTREACHED */
212	}
213
214	/* Read PKG_INSTALL_ROOT from the environment, if it's there. */
215
216	if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
217		progerr(ERR_ROOT_SET);
218		exit(1);
219	}
220
221	pkgserversetmode(DEFAULTMODE);
222
223	/* parse command line options */
224
225	while ((c = getopt(argc, argv, "?Aa:b:FMN:nO:oR:V:vy")) != EOF) {
226		switch (c) {
227		/*
228		 * Same as pkgrm: Allow admin to remove package objects from
229		 * a shared area from a reference client.
230		 */
231		case 'A':
232		    pkgrmremote++;
233		    break;
234
235		/*
236		 * Same as pkgrm: Use the installation
237		 * administration file, admin, in place of the
238		 * default admin file. pkgrm first looks in the
239		 * current working directory for the administration
240		 * file.  If the specified administration file is not
241		 * in the current working directory, pkgrm looks in
242		 * the /var/sadm/install/admin directory for the
243		 * administration file.
244		 */
245		case 'a':
246		    admnfile = flex_device(optarg, 0);
247		    break;
248
249		/*
250		 * Same as pkgrm: location where package executables
251		 * can be found - default is /usr/sadm/install/bin.
252		 */
253		case 'b':
254			if (!path_valid(optarg)) {
255				progerr(ERR_PATH, optarg);
256				exit(1);
257			}
258			if (isdir(optarg) != 0) {
259				char *p = strerror(errno);
260				progerr(ERR_CANNOT_USE_DIR, optarg, p);
261				exit(1);
262			}
263			(void) strlcpy(cmdbin, optarg, sizeof (cmdbin));
264			break;
265
266		/*
267		 * Same as pkgrm: suppresses the removal of any
268		 * files and any class action scripts, and suppresses
269		 * the running of any class action scripts.  The
270		 * package files remain but the package looks like it
271		 * is not installed. This is mainly for use by the
272		 * upgrade process.
273		 */
274		case 'F':
275		    nodelete++;
276		    break;
277
278		/*
279		 * Same as pkgrm: Instruct pkgrm not to use the
280		 * $root_path/etc/vfstab file for determining the
281		 * client's mount points. This option assumes the
282		 * mount points are correct on the server and it
283		 * behaves consistently with Solaris 2.5 and earlier
284		 * releases.
285		 */
286		case 'M':
287		    map_client = 0;
288		    break;
289
290		/*
291		 * Different from pkgrm: specify program name to use
292		 * for messages.
293		 */
294		case 'N':
295		    (void) set_prog_name(optarg);
296		    break;
297
298		/*
299		 * Same as pkgrm: package removal occurs in
300		 * non-interactive mode.  Suppress output of the list of
301		 * removed files. The default mode is interactive.
302		 */
303		case 'n':
304		    nointeract++;
305		    (void) echoSetFlag(B_FALSE);
306		    break;
307
308		/*
309		 * Almost same as pkgrm: the -O option allows the behavior
310		 * of the package tools to be modified. Recognized options:
311		 * -> debug
312		 * ---> enable debugging output
313		 * -> preremovecheck
314		 * ---> perform a "pre removal" check of the specified
315		 * ---> package - suppress all regular output and cause a
316		 * ---> series of one or more "name=value" pair format lines
317		 * ---> to be output that describes the "removability" of
318		 * ---> the specified package
319		 * -> enable-hollow-package-support
320		 * --> Enable hollow package support. When specified, for any
321		 * --> package that has SUNW_PKG_HOLLOW=true:
322		 * --> Do not calculate and verify package size against target
323		 * --> Do not run any package procedure or class action scripts
324		 * --> Do not create or remove any target directories
325		 * --> Do not perform any script locking
326		 * --> Do not install or uninstall any components of any package
327		 * --> Do not output any status or database update messages
328		 */
329		case 'O':
330			for (p = strtok(optarg, ","); p != (char *)NULL;
331				p = strtok(NULL, ",")) {
332
333				/* process debug option */
334
335				if (strcmp(p, "debug") == 0) {
336					/* set debug flag/enable debug output */
337					debugFlag = B_TRUE;
338					(void) echoDebugSetFlag(debugFlag);
339
340					/* debug info on arguments to pkgadd */
341					for (n = 0; n < argc && argv[n]; n++) {
342						echoDebug(DBG_ARG, n, argv[n]);
343					}
344
345					continue;
346				}
347
348				/* process enable-hollow-package-support opt */
349
350				if (strcmp(p,
351					"enable-hollow-package-support") == 0) {
352					set_depend_pkginfo_DB(B_TRUE);
353					continue;
354				}
355
356				/* process preremovecheck option */
357
358				if (strcmp(p, "preremovecheck") == 0) {
359					preremoveCheck = B_TRUE;
360					nointeract++;	/* -n */
361					nodelete++;	/* -F */
362					quitSetSilentExit(B_TRUE);
363					continue;
364				}
365
366				/* process addzonename option */
367
368				if (strcmp(p, "addzonename") == 0) {
369					zoneName = z_get_zonename();
370					quitSetZoneName(zoneName);
371					continue;
372				}
373
374				/* process parent-zone-name option */
375
376				if (strncmp(p, PARENTZONENAME,
377						PARENTZONENAME_LEN) == 0) {
378					parentZoneName = p+PARENTZONENAME_LEN;
379					continue;
380				}
381
382				/* process parent-zone-type option */
383
384				if (strncmp(p, PARENTZONETYPE,
385						PARENTZONETYPE_LEN) == 0) {
386					parentZoneType = p+PARENTZONETYPE_LEN;
387					continue;
388				}
389
390				if (strncmp(p, PKGSERV_MODE,
391				    PKGSERV_MODE_LEN) == 0) {
392					pkgserversetmode(pkgparsemode(p +
393					    PKGSERV_MODE_LEN));
394					continue;
395				}
396				/* option not recognized - issue warning */
397
398				progerr(ERR_INVALID_O_OPTION, p);
399				continue;
400			}
401			break;
402
403		/*
404		 * Different from pkgrm: This is an old non-ABI package
405		 */
406
407		case 'o':
408		    script_in = PROC_XSTDIN;
409		    break;
410
411		/*
412		 * Same as pkgrm: defines the full path name of a
413		 * directory to use as the root_path.  All files,
414		 * including package system information files, are
415		 * relocated to a directory tree starting in the
416		 * specified root_path.
417		 */
418		case 'R':
419		    if (!set_inst_root(optarg)) {
420			    progerr(ERR_ROOT_CMD);
421			    exit(1);
422		    }
423		    break;
424
425		/*
426		 * Same as pkgrm: allow admin to establish the client
427		 * filesystem using a vfstab-like file of stable format.
428		 */
429		case 'V':
430		    vfstab_file = flex_device(optarg, 2);
431		    map_client = 1;
432		    break;
433
434		/*
435		 * Same as pkgrm: trace all of the scripts that
436		 * get executed by pkgrm, located in the
437		 * pkginst/install directory. This option is used for
438		 * debugging the procedural and non-procedural
439		 * scripts.
440		 */
441		case 'v':
442		    pkgverbose++;
443		    break;
444
445		/*
446		 * Different from pkgrm: process this package using
447		 * old non-ABI symlinks
448		 */
449		case 'y':
450		    set_nonABI_symlinks();
451		    break;
452
453		default:
454		    usage();
455		    /*NOTREACHED*/
456		    /*
457		     * Although usage() calls a noreturn function,
458		     * needed to add return (1);  so that main() would
459		     * pass compilation checks. The statement below
460   		     * should never be executed.
461		     */
462		    return (1);
463		}
464	}
465
466	/*
467	 * ********************************************************************
468	 * validate command line options
469	 * ********************************************************************
470	 */
471
472	(void) echoDebugSetFlag(debugFlag);
473	(void) log_set_verbose(debugFlag);
474
475	if (z_running_in_global_zone()) {
476		echoDebug(DBG_ENTRY_IN_GZ, prog_full_name);
477	} else {
478		echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(),
479			z_get_zonename());
480	}
481
482	/* establish cmdbin path */
483
484	if (cmdbin[0] == '\0') {
485		(void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin));
486	}
487
488	/* Read the mount table */
489
490	if (get_mntinfo(map_client, vfstab_file)) {
491		quit(99);
492	}
493
494	/*
495	 * This function defines the standard /var/... directories used later
496	 * to construct the paths to the various databases.
497	 */
498
499	set_PKGpaths(get_inst_root());
500
501	/*
502	 * If this is being removed from a client whose /var filesystem is
503	 * mounted in some odd way, remap the administrative paths to the
504	 * real filesystem. This could be avoided by simply mounting up the
505	 * client now; but we aren't yet to the point in the process where
506	 * modification of the filesystem is permitted.
507	 */
508	if (is_an_inst_root()) {
509		int fsys_value;
510
511		fsys_value = fsys(get_PKGLOC());
512		if (use_srvr_map_n(fsys_value))
513			set_PKGLOC(server_map(get_PKGLOC(), fsys_value));
514
515		fsys_value = fsys(get_PKGADM());
516		if (use_srvr_map_n(fsys_value))
517			set_PKGADM(server_map(get_PKGADM(), fsys_value));
518	} else {
519		pkgrmremote = 0;	/* Makes no sense on local host. */
520	}
521
522	/*
523	 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler
524	 */
525
526	/* hold SIGINT/SIGHUP interrupts */
527
528	(void) sighold(SIGHUP);
529	(void) sighold(SIGINT);
530
531	/* connect quit.c:trap() to SIGINT */
532
533	nact.sa_handler = quitGetTrapHandler();
534	nact.sa_flags = SA_RESTART;
535	(void) sigemptyset(&nact.sa_mask);
536
537	(void) sigaction(SIGINT, &nact, &oact);
538
539	/* connect quit.c:trap() to SIGHUP */
540
541	nact.sa_handler = quitGetTrapHandler();
542	nact.sa_flags = SA_RESTART;
543	(void) sigemptyset(&nact.sa_mask);
544
545	(void) sigaction(SIGHUP, &nact, &oact);
546
547	/* release hold on signals */
548
549	(void) sigrelse(SIGHUP);
550	(void) sigrelse(SIGINT);
551
552	pkginst = argv[optind++];
553	if (optind != argc) {
554		usage();
555	}
556
557	/* validate package software database (contents) file */
558
559	if (vcfile() == 0) {
560		quit(99);
561	}
562
563	/*
564	 * Acquire the package lock - currently at "remove initialization"
565	 */
566
567	if (!lockinst(get_prog_name(), pkginst, "remove-initial")) {
568		quit(99);
569	}
570
571	/* establish temporary directory to use */
572
573	tmpdir = getenv("TMPDIR");
574	if (tmpdir == NULL) {
575		tmpdir = P_tmpdir;
576	}
577
578	echoDebug(DBG_PKGREMOVE_TMPDIR, tmpdir);
579
580	/*
581	 * Initialize installation admin parameters by reading
582	 * the adminfile.
583	 */
584
585	echoDebug(DBG_PKGREMOVE_ADMINFILE, admnfile ? admnfile : "");
586	setadminFile(admnfile);
587
588	/*
589	 * about to perform first operation that could be modified by the
590	 * preremove check option - if preremove check is selected (that is,
591	 * only gathering dependencies), then output a debug message to
592	 * indicate that the check is beginning. Also turn echo() output
593	 * off and set various other flags.
594	 */
595
596	if (preremoveCheck == B_TRUE) {
597		(void) echoSetFlag(B_FALSE);
598		echoDebug(DBG_PKGREMOVE_PRERMCHK, pkginst ? pkginst : "",
599			zoneName ? zoneName : "global");
600		rcksetPreremoveCheck(B_TRUE);
601		rcksetZoneName(zoneName);
602	}
603
604	(void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s", get_PKGLOC(),
605			pkginst);
606	(void) snprintf(pkgbin, sizeof (pkgbin), "%s/install", pkgloc);
607	(void) snprintf(rlockfile, sizeof (rlockfile), "%s/!R-Lock!", pkgloc);
608
609	if (chdir(pkgbin)) {
610		progerr(ERR_CHDIR, pkgbin);
611		quit(99);
612	}
613
614	echo(MSG_PREREMOVE_REMINST, pkginst);
615
616	/*
617	 * if a lock file is present, then a previous attempt to remove this
618	 * package may have been unsuccessful.
619	 */
620
621	if (access(rlockfile, F_OK) == 0) {
622		echo(ERR_UNSUCC);
623		echoDebug(DBG_PKGINSTALL_HAS_LOCKFILE, pkginst, rlockfile,
624			zoneName ? zoneName : "global");
625	}
626
627	/*
628	 * Process all parameters from the pkginfo file
629	 * and place them in the execution environment
630	 */
631
632	/* Add DB retreival of the pkginfo parameters here */
633	(void) snprintf(path, sizeof (path), "%s/pkginfo", pkgloc);
634	if ((fp = fopen(path, "r")) == NULL) {
635		progerr(ERR_PKGINFO, path);
636		quit(99);
637	}
638
639	/* Mount up the client if necessary. */
640	if (map_client && !mount_client()) {
641		logerr(MSG_MANMOUNT);
642	}
643
644	/* Get mount point of client */
645	client_mntdir = getenv("CLIENT_MNTDIR");
646
647	getuserlocale();
648
649	/*
650	 * current environment has been read; clear environment out
651	 * so putparam() can be used to populate the new environment
652	 * to be passed to any executables/scripts.
653	 */
654
655	environ = NULL;
656
657	if (nonABI_symlinks()) {
658		putparam("PKG_NONABI_SYMLINKS", "TRUE");
659	}
660
661	/*
662	 * read the pkginfo file and fix any PKGSAV path - the correct
663	 * install_root will be prepended to the existing path.
664	 */
665
666	param[0] = '\0';
667	while (value = fpkgparam(fp, param)) {
668		int validx = 0;
669		char *newvalue;
670
671		/* strip out any setting of PATH */
672
673		if (strcmp(param, "PATH") == 0) {
674			free(value);
675			param[0] = '\0';
676			continue;
677		}
678
679		/* if not PKGSAV then write out unchanged */
680
681		if (strcmp(param, "PKGSAV") != 0) {
682			putparam(param, value);
683			free(value);
684			param[0] = '\0';
685			continue;
686		}
687
688		/*
689		 * PKGSAV parameter found - interpret the directory:
690		 * If in host:path format or marked with the leading "//",
691		 * then there is no client-relative translation - take it
692		 * literally later rather than use fixpath().
693		 */
694
695		if (strstr(value, ":/")) {
696			/* no modification needed */
697			validx = 0;
698		} else if (strstr(value, "//") == value) {
699			validx = 1;
700		} else if (is_an_inst_root()) {
701			/* This PKGSAV needs to be made client-relative. */
702			newvalue = fixpath(value);
703			free(value);
704			value = newvalue;
705		}
706		putparam(param, value+validx);
707		free(value);
708		param[0] = '\0';
709	}
710
711	(void) fclose(fp);
712
713	/* write parent condition information to environment */
714
715	putConditionInfo(parentZoneName, parentZoneType);
716
717	putuserlocale();
718
719	/*
720	 * Now do all the various setups based on ABI compliance
721	 */
722
723	/* Read the environment provided by the pkginfo file */
724	abi_comp_ptr = getenv("NONABI_SCRIPTS");
725
726	/* if not ABI compliant set global flag */
727	abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
728	if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) {
729		set_nonABI_symlinks();
730	}
731
732	/*
733	 * If pkginfo says it's not compliant then set non_abi_scripts.
734	 * Oh, for two releases, set it from exception package names as
735	 * well.
736	 */
737	/*
738	 * *********************************************************************
739	 * this feature is removed starting with Solaris 10 - there is no built
740	 * in list of packages that should be run "the old way"
741	 * *********************************************************************
742	 */
743
744#ifdef	ALLOW_EXCEPTION_PKG_LIST
745	if (exception_pkg(pkginst, SCRIPT) ||
746	    (abi_comp_ptr && strncmp(abi_comp_ptr, "TRUE", 4) == 0))
747		script_in = PROC_XSTDIN;
748#else
749	if (abi_comp_ptr && strncmp(abi_comp_ptr, "TRUE", 4) == 0) {
750		script_in = PROC_XSTDIN;
751	}
752#endif
753	/*
754	 * *********************************************************************
755	 * this feature is removed starting with Solaris 10 - there is no built
756	 * in list of packages that should be run "the old way"
757	 * *********************************************************************
758	 */
759
760#ifdef	ALLOW_EXCEPTION_PKG_LIST
761	/* Until 2.9, set it from the execption list */
762	if (exception_pkg(pkginst, LINK)) {
763		set_nonABI_symlinks();
764	}
765#endif
766
767	/*
768	 * Since this is a removal, we can tell whether it's absolute or
769	 * not from the resident pkginfo file read above.
770	 */
771	if ((err = set_basedirs((getenv("BASEDIR") != NULL), adm.basedir,
772	    pkginst, nointeract)) != 0) {
773		quit(err);
774	}
775
776	/*
777	 * See if were are removing a package that only wants to update
778	 * the database or only remove files associated with CAS's. We
779	 * only check the PKG_HOLLOW_VARIABLE variable if told to do so by
780	 * the caller.
781	 */
782
783	if (is_depend_pkginfo_DB()) {
784		pt = getenv(PKG_HOLLOW_VARIABLE);
785
786		if ((pt != NULL) && (strncasecmp(pt, "true", 4) == 0)) {
787			echoDebug(DBG_PKGREMOVE_HOLLOW_ENABLED);
788
789			/*
790			 * this is a hollow package and hollow package support
791			 * is enabled -- override admin settings to suppress
792			 * checks that do not make sense since no scripts will
793			 * be executed and no files will be removed.
794			 */
795
796			setadminSetting("conflict", "nocheck");
797			setadminSetting("setuid", "nocheck");
798			setadminSetting("action", "nocheck");
799			setadminSetting("partial", "nocheck");
800			setadminSetting("space", "nocheck");
801			setadminSetting("authentication", "nocheck");
802		} else {
803			echoDebug(DBG_PKGREMOVE_HOLLOW_DISABLED);
804			set_depend_pkginfo_DB(B_FALSE);
805		}
806	}
807
808	put_path_params();
809
810	/* If client mount point, add it to pkgremove environment */
811
812	if (client_mntdir != NULL) {
813		putparam("CLIENT_MNTDIR", client_mntdir);
814	}
815
816	/* Establish the class list and the class attributes. */
817
818	if ((value = getenv("CLASSES")) != NULL) {
819		cl_sets(qstrdup(value));
820	} else {
821		progerr(ERR_CLASSES, path);
822		quit(99);
823	}
824
825	/* establish path and tmpdir */
826
827	if (cmdbin[0] == '\0') {
828		(void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin));
829	}
830
831	(void) snprintf(path, sizeof (path), "%s:%s", DEFPATH, cmdbin);
832	putparam("PATH", path);
833
834	putparam("TMPDIR", tmpdir);
835
836	/*
837	 * Check ulimit requirement (provided in pkginfo). The purpose of
838	 * this limit is to terminate pathological file growth resulting from
839	 * file edits in scripts. It does not apply to files in the pkgmap
840	 * and it does not apply to any database files manipulated by the
841	 * installation service.
842	 */
843	if (value = getenv("ULIMIT")) {
844		if (assign_ulimit(value) == -1) {
845			progerr(ERR_BADULIMIT, value);
846			warnflag++;
847		}
848		putparam("PKG_ULIMIT", "TRUE");
849	}
850
851	/*
852	 * If only gathering dependencies, check and output status of all
853	 * remaining dependencies and exit.
854	 */
855
856	if (preremoveCheck == B_TRUE) {
857		/*
858		 * make sure current runlevel is appropriate
859		 */
860
861		(void) fprintf(stdout, "rckrunlevel=%d\n", rckrunlevel());
862
863		/*
864		 * determine if any packaging scripts provided with
865		 * this package will execute as a priviledged user
866		 */
867
868		(void) fprintf(stdout, "rckpriv=%d\n", rckpriv());
869
870		/*
871		 * verify package dependencies
872		 */
873
874		(void) fprintf(stdout, "rckdepend=%d\n", rckdepend());
875
876		/*
877		 * ****** preremove check done - exit ******
878		 */
879
880		echoDebug(DBG_PKGREMOVE_PRERMCHK_OK);
881		quit(0);
882		/*NOTREACHED*/
883	}
884
885	/*
886	 * Not gathering dependencies only, proceed to check dependencies
887	 * and continue with the package removal operation.
888	 */
889
890	/*
891	 * make sure current runlevel is appropriate
892	 */
893
894	n = rckrunlevel();
895
896	if (n != 0) {
897		quit(n);
898		/* NOTREACHED */
899	}
900
901	/*
902	 * determine if any packaging scripts provided with
903	 * this package will execute as a priviledged user
904	 */
905
906	n = rckpriv();
907
908	if (n != 0) {
909		quit(n);
910		/* NOTREACHED */
911	}
912
913	/*
914	 * verify package dependencies
915	 */
916	n = rckdepend();
917
918	if (n != 0) {
919		quit(n);
920		/* NOTREACHED */
921	}
922
923	/*
924	 * *********************************************************************
925	 * the actual removal of the package begins here
926	 * *********************************************************************
927	 */
928
929	/*
930	 * create lockfile to indicate start of removal
931	 */
932	started++;
933	if ((fd = open(rlockfile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
934		progerr(ERR_LOCKFILE, rlockfile);
935		quit(99);
936	} else {
937		(void) close(fd);
938	}
939
940	if (zoneName == (char *)NULL) {
941		echo(MSG_PKGREMOVE_PROCPKG_GZ);
942		echoDebug(DBG_PKGREMOVE_PROCPKG_GZ, pkginst, rlockfile);
943	} else {
944		echo(MSG_PKGREMOVE_PROCPKG_LZ, zoneName);
945		echoDebug(DBG_PKGREMOVE_PROCPKG_LZ, pkginst, rlockfile,
946			zoneName);
947	}
948	if (delmap(0, pkginst, &pkgserver, &tmpfp) != 0) {
949		progerr(ERR_DB_QUERY, pkginst);
950		quit(99);
951	}
952
953	/*
954	 * Run a preremove script if one is provided by the package.
955	 * Don't execute preremove script if only updating the DB.
956	 * Don't execute preremove script if files are not being deleted.
957	 */
958
959	/* update the lock - at the preremove script */
960	lockupd("preremove");
961
962	/* execute preremove script if one is provided */
963	(void) snprintf(script, sizeof (script), "%s/preremove", pkgbin);
964	if (access(script, F_OK) != 0) {
965		/* no script present */
966		echoDebug(DBG_PKGREMOVE_POC_NONE, pkginst,
967			zoneName ? zoneName : "global");
968	} else if (nodelete) {
969		/* not deleting files: skip preremove script */
970		echoDebug(DBG_PKGREMOVE_POC_NODEL, pkginst, script,
971			zoneName ? zoneName : "global");
972	} else if (is_depend_pkginfo_DB()) {
973		/* updating db only: skip preremove script */
974		echoDebug(DBG_PKGREMOVE_POC_DBUPD, pkginst, script,
975			zoneName ? zoneName : "global");
976	} else {
977		/* script present and ok to run: run the script */
978		set_ulimit("preremove", ERR_PREREMOVE);
979		if (zoneName == (char *)NULL) {
980			echo(MSG_PKGREMOVE_EXEPOC_GZ);
981			echoDebug(DBG_PKGREMOVE_EXEPOC_GZ, pkginst, script);
982		} else {
983			echo(MSG_PKGREMOVE_EXEPOC_LZ, zoneName);
984			echoDebug(DBG_PKGREMOVE_EXEPOC_LZ, pkginst, script,
985				zoneName);
986		}
987		putparam("PKG_PROC_SCRIPT", "preremove");
988		if (pkgverbose) {
989			ckreturn(pkgexecl(script_in, PROC_STDOUT,
990				PROC_USER, PROC_GRP, SHELL, "-x",
991				script, NULL), ERR_PREREMOVE);
992		} else {
993			ckreturn(pkgexecl(script_in, PROC_STDOUT,
994				PROC_USER, PROC_GRP, SHELL, script,
995				NULL), ERR_PREREMOVE);
996		}
997		clr_ulimit();
998	}
999
1000	/* update the lock - doing removal */
1001
1002	lockupd("remove");
1003
1004	/*
1005	 * Ensure that the contents file is updated even if the db has
1006	 * been upgraded, in the case that there are relevant entries
1007	 * in a special_contents file.  The return value is ignored
1008	 * since we do not want special_contents operation to prevent
1009	 * pkgremove from succeeding.  We do report errors to stderr.
1010	 */
1011
1012	/*
1013	 * Remove all components belonging to this package.
1014	 * Don't remove components if only updating the DB.
1015	 * Don't remove components if files are not being deleted.
1016	 */
1017
1018	if (nodelete) {
1019		echoDebug(DBG_PKGREMOVE_REM_NODEL, pkginst,
1020			zoneName ? zoneName : "global");
1021	} else if (is_depend_pkginfo_DB()) {
1022		echoDebug(DBG_PKGREMOVE_REM_DBUPD, pkginst,
1023			zoneName ? zoneName : "global");
1024	} else {
1025		echoDebug(DBG_PKGREMOVE_REM, pkginst,
1026			zoneName ? zoneName : "global");
1027		/*
1028		 * remove package one class at a time
1029		 */
1030
1031		/* reverse order of classes */
1032		for (i = cl_getn() - 1; i >= 0; i--) {
1033			rmclass(cl_nam(i), pkgrmremote, zoneName);
1034		}
1035
1036		rmclass(NULL, pkgrmremote, zoneName);
1037	}
1038
1039	z_destroyMountTable();
1040
1041	/*
1042	 * Execute postremove script, if any
1043	 * Don't execute postremove script if only updating the DB.
1044	 * Don't execute postremove script if files are not being deleted.
1045	 */
1046
1047	/* update the lock - at the postremove script */
1048	lockupd("postremove");
1049
1050	/* execute postremove script if one is provided */
1051	(void) snprintf(script, sizeof (script), "%s/postremove", pkgbin);
1052	if (access(script, F_OK) != 0) {
1053		/* no script present */
1054		echoDebug(DBG_PKGREMOVE_PIC_NONE, pkginst,
1055			zoneName ? zoneName : "global");
1056	} else if (nodelete) {
1057		/* not deleting files: skip postremove script */
1058		echoDebug(DBG_PKGREMOVE_PIC_NODEL, pkginst, script,
1059			zoneName ? zoneName : "global");
1060	} else if (is_depend_pkginfo_DB()) {
1061		/* updating db only: skip postremove script */
1062		echoDebug(DBG_PKGREMOVE_PIC_DBUPD, pkginst, script,
1063			zoneName ? zoneName : "global");
1064	} else {
1065		/* script present and ok to run: run the script */
1066		set_ulimit("postremove", ERR_POSTREMOVE);
1067		if (zoneName == (char *)NULL) {
1068			echo(MSG_PKGREMOVE_EXEPIC_GZ);
1069			echoDebug(DBG_PKGREMOVE_EXEPIC_GZ, pkginst, script);
1070		} else {
1071			echo(MSG_PKGREMOVE_EXEPIC_LZ, zoneName);
1072			echoDebug(DBG_PKGREMOVE_EXEPIC_LZ, pkginst, script,
1073				zoneName);
1074		}
1075		putparam("PKG_PROC_SCRIPT", "postremove");
1076		putparam("TMPDIR", tmpdir);
1077		if (pkgverbose) {
1078			ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER,
1079			    PROC_GRP, SHELL, "-x", script, NULL),
1080			    ERR_POSTREMOVE);
1081		} else {
1082			ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER,
1083			    PROC_GRP, SHELL, script, NULL),
1084			    ERR_POSTREMOVE);
1085		}
1086		clr_ulimit();
1087	}
1088
1089	if (zoneName == (char *)NULL) {
1090		echo(MSG_PKGREMOVE_UPDINF_GZ);
1091	} else {
1092		echo(MSG_PKGREMOVE_UPDINF_LZ, zoneName);
1093	}
1094
1095	if (delmap(1, pkginst, &pkgserver, &tmpfp) != 0) {
1096		progerr(ERR_DB_QUERY, pkginst);
1097		quit(99);
1098	}
1099
1100	if (!warnflag && !failflag) {
1101		if (pt = getenv("PREDEPEND"))
1102			predepend(pt);
1103		(void) chdir("/");
1104		if (rrmdir(pkgloc))
1105			warnflag++;
1106	}
1107
1108	if ((z_running_in_global_zone() == B_TRUE) &&
1109		(pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE)) {
1110		boolean_t	b;
1111
1112		b = pkgRemovePackageFromGzonlyList(get_inst_root(), pkginst);
1113		if (b == B_FALSE) {
1114			progerr(ERR_PKGREMOVE_GZONLY_REMOVE, pkginst);
1115			ckreturn(1, NULL);
1116		}
1117	}
1118
1119	/* release the generic package lock */
1120
1121	(void) unlockinst();
1122
1123	pkgcloseserver(pkgserver);
1124
1125	quit(0);
1126	/* LINTED: no return */
1127}
1128
1129int
1130issymlink(char *path)
1131{
1132	struct stat statbuf;
1133
1134	/*
1135	 * Obtain status of path; if symbolic link get link's status
1136	 */
1137
1138	if (lstat(path, &statbuf) != 0) {
1139		return (1);	/* not symlink */
1140	}
1141
1142	/*
1143	 * Status obtained - if symbolic link, return 0
1144	 */
1145
1146	if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
1147		return (0);	/* is a symlink */
1148	}
1149
1150	/*
1151	 * Not a symbolic link - return 1
1152	 */
1153
1154	return (1);		/* not symlink */
1155}
1156
1157static void
1158rmclass(char *aclass, int rm_remote, char *a_zoneName)
1159{
1160	struct cfent	*ept;
1161	FILE	*fp;
1162	char	tmpfile[PATH_MAX];
1163	char	script[PATH_MAX];
1164	int	i;
1165	char	*tmp_path;
1166	char	*save_path = NULL;
1167	struct stat st;
1168
1169	if (aclass == NULL) {
1170		for (i = 0; i < eptnum; i++) {
1171			if (eptlist[i] != NULL) {
1172				rmclass(eptlist[i]->pkg_class,
1173					rm_remote, a_zoneName);
1174			}
1175		}
1176		return;
1177	}
1178
1179	/* locate class action script to execute */
1180	(void) snprintf(script, sizeof (script), "%s/r.%s", pkgbin, aclass);
1181	if (access(script, F_OK) != 0) {
1182		(void) snprintf(script, sizeof (script), "%s/r.%s",
1183		    PKGSCR, aclass);
1184		if (access(script, F_OK) != 0)
1185			script[0] = '\0';
1186	}
1187	if (script[0] != '\0') {
1188		int td;
1189
1190		(void) snprintf(tmpfile, sizeof (tmpfile), "%s/RMLISTXXXXXX",
1191		    tmpdir);
1192		td = mkstemp(tmpfile);
1193		if (td == -1) {
1194			progerr(ERR_TMPFILE);
1195			quit(99);
1196		}
1197		if ((fp = fdopen(td, "w")) == NULL) {
1198			progerr(ERR_WTMPFILE, tmpfile);
1199			quit(99);
1200		}
1201	}
1202
1203	if (a_zoneName == (char *)NULL) {
1204		echo(MSG_PKGREMOVE_REMPATHCLASS_GZ, aclass);
1205	} else {
1206		echo(MSG_PKGREMOVE_REMPATHCLASS_LZ, aclass, a_zoneName);
1207	}
1208
1209	/* process paths in reverse order */
1210	i = eptnum;
1211	while (--i >= 0) {
1212		ept = eptlist[i];
1213
1214		if ((ept == NULL) || strcmp(aclass, ept->pkg_class)) {
1215			continue;
1216		}
1217
1218		/* save the path, and prepend the ir */
1219		if (is_an_inst_root()) {
1220			save_path = ept->path;
1221			tmp_path = fixpath(ept->path);
1222			ept->path = tmp_path;
1223		}
1224
1225		if (!ept->ftype || (ept->ftype == '^' && !script[0])) {
1226			/*
1227			 * A path owned by more than one package is marked with
1228			 * a NULL ftype (seems odd, but that's how it's
1229			 * done). Such files are sacro sanct. Shared editable
1230			 * files are a special case, and are marked with an
1231			 * ftype of '^'. These files should only be ignored if
1232			 * no class action script is present. It is the CAS's
1233			 * responsibility to not remove the editable object.
1234			 */
1235			echo(MSG_SHARED, ept->path);
1236		} else if (ept->pinfo->status == SERVED_FILE && !rm_remote) {
1237			/*
1238			 * If the path is provided to the client from a
1239			 * server, don't remove anything unless explicitly
1240			 * requested through the "-f" option.
1241			 */
1242			echo(MSG_SERVER, ept->path);
1243		} else if (script[0]) {
1244			/*
1245			 * If there's a class action script, just put the
1246			 * path name into the list.
1247			 */
1248			(void) fprintf(fp, "%s\n", ept->path);
1249		} else if (strchr("dx", ept->ftype) != NULL ||
1250		    (lstat(ept->path, &st) == 0 && S_ISDIR(st.st_mode))) {
1251			/* Directories are rmdir()'d. */
1252
1253			if (rmdir(ept->path)) {
1254				if (errno == EBUSY) {
1255					echo(MSG_DIRBUSY, ept->path);
1256				} else if (errno == EEXIST) {
1257					echo(MSG_NOTEMPTY, ept->path);
1258				} else if (errno != ENOENT) {
1259					progerr(ERR_RMDIR, ept->path);
1260					warnflag++;
1261				}
1262			} else {
1263				if (ept->pinfo->status == SERVED_FILE) {
1264					echo(MSG_RMSRVR, ept->path);
1265				} else {
1266					echo("%s", ept->path);
1267				}
1268			}
1269
1270		} else {
1271			/*
1272			 * Before removing this object one more
1273			 * check should be done to assure that a
1274			 * shared object is not removed.
1275			 * This can happen if the original object
1276			 * was incorrectly updated with the
1277			 * incorrect class identifier.
1278			 * This handles pathologcal cases that
1279			 * weren't handled above.
1280			 */
1281			if (ept->npkgs > 1) {
1282				echo(MSG_SHARED, ept->path);
1283				continue;
1284			}
1285
1286			/* Regular files are unlink()'d. */
1287
1288			if (unlink(ept->path)) {
1289				if (errno != ENOENT) {
1290					progerr(ERR_RMPATH, ept->path);
1291					warnflag++;
1292				}
1293			} else {
1294				if (ept->pinfo->status == SERVED_FILE) {
1295					echo(MSG_RMSRVR, ept->path);
1296				} else {
1297					echo("%s", ept->path);
1298				}
1299			}
1300		}
1301
1302		/* restore the original path */
1303
1304		if (is_an_inst_root()) {
1305			ept->path = save_path;
1306		}
1307
1308		/*
1309		 * free memory allocated for this entry memory used for
1310		 * pathnames will be freed later by a call to pathdup()
1311		 */
1312
1313		if (eptlist[i]) {
1314			free(eptlist[i]);
1315		}
1316		eptlist[i] = NULL;
1317	}
1318	if (script[0]) {
1319		(void) fclose(fp);
1320		set_ulimit(script, ERR_CASFAIL);
1321		if (pkgverbose)
1322			ckreturn(pkgexecl(tmpfile, CAS_STDOUT, CAS_USER,
1323			    CAS_GRP, SHELL, "-x", script, NULL),
1324			    ERR_CASFAIL);
1325		else
1326			ckreturn(pkgexecl(tmpfile, CAS_STDOUT, CAS_USER,
1327			    CAS_GRP, SHELL, script, NULL),
1328			    ERR_CASFAIL);
1329		clr_ulimit();
1330		if (isfile(NULL, tmpfile) == 0) {
1331			if (unlink(tmpfile) == -1)
1332				progerr(ERR_RMPATH, tmpfile);
1333		}
1334	}
1335}
1336
1337static void
1338ckreturn(int retcode, char *msg)
1339{
1340	switch (retcode) {
1341	    case 2:
1342	    case 12:
1343	    case 22:
1344		warnflag++;
1345		/*FALLTHRU*/
1346		if (msg)
1347			progerr(msg);
1348	    case 10:
1349	    case 20:
1350		if (retcode >= 10)
1351			dreboot++;
1352		if (retcode >= 20)
1353			ireboot++;
1354		/*FALLTHRU*/
1355	    case 0:
1356		break; /* okay */
1357
1358	    case -1:
1359		retcode = 99;
1360		/*FALLTHRU*/
1361	    case 99:
1362	    case 1:
1363	    case 11:
1364	    case 21:
1365	    case 4:
1366	    case 14:
1367	    case 24:
1368	    case 5:
1369	    case 15:
1370	    case 25:
1371		if (msg)
1372			progerr(msg);
1373		/*FALLTHRU*/
1374	    case 3:
1375	    case 13:
1376	    case 23:
1377		quit(retcode);
1378		/* NOT REACHED */
1379	    default:
1380		if (msg)
1381			progerr(msg);
1382		quit(1);
1383	}
1384}
1385
1386static void
1387usage(void)
1388{
1389	(void) fprintf(stderr, ERR_USAGE_PKGREMOVE);
1390
1391	exit(1);
1392}
1393
1394/*
1395 * Name:		path_valid
1396 * Description:	Checks a string for being a valid path
1397 *
1398 * Arguments:	path - path to validate
1399 *
1400 * Returns :	B_TRUE - success, B_FALSE otherwise.
1401 *		B_FALSE means path was null, too long (>PATH_MAX),
1402 *		or too short (<1)
1403 */
1404static boolean_t
1405path_valid(char *path)
1406{
1407	if (path == NULL) {
1408		return (B_FALSE);
1409	} else if (strlen(path) > PATH_MAX) {
1410		return (B_FALSE);
1411	} else if (strlen(path) >= 1) {
1412		return (B_TRUE);
1413	} else {
1414		/* path < 1 */
1415		return (B_FALSE);
1416	}
1417}
1418