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
54 struct cfent **eptlist;
55 extern int eptnum;
56
57 extern char *pkgdir;
58 extern char **environ;
59
60 /* quit.c */
61 extern sighdlrFunc_t *quitGetTrapHandler(void);
62 extern void quitSetSilentExit(boolean_t a_silentExit);
63 extern void quitSetZoneName(char *a_zoneName);
64
65
66
67 /* check.c */
68 extern void rcksetPreremoveCheck(boolean_t);
69 extern void rcksetZoneName(char *);
70 extern int rckpriv(void);
71 extern int rckdepend(void);
72 extern int rckrunlevel(void);
73
74 /* predepend.c */
75 extern void predepend(char *oldpkg);
76
77 /* delmap.c */
78 extern 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
101 struct admin adm; /* holds info about installation admin */
102 int dreboot; /* non-zero if reboot required after installation */
103 int ireboot; /* non-zero if immediate reboot required */
104 int failflag; /* non-zero if fatal error has occurred */
105 int warnflag; /* non-zero if non-fatal error has occurred */
106 int pkgverbose; /* non-zero if verbose mode is selected */
107 int started;
108 int nocnflct = 0; /* pkgdbmerg needs this defined */
109 int nosetuid = 0; /* pkgdbmerg needs this defined */
110
111 char *pkginst; /* current package (source) instance to process */
112
113 int dbchg;
114 char *msgtext;
115 char 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 */
124 static char *script_in = PROC_STDIN; /* assume ABI compliance */
125
126 static char *client_mntdir; /* mount point for client's basedir */
127 static char pkgbin[PATH_MAX],
128 rlockfile[PATH_MAX],
129 *admnfile, /* file to use for installation admin */
130 *tmpdir; /* location to place temporary files */
131
132 static boolean_t path_valid(char *path);
133 static void ckreturn(int retcode, char *msg);
134 static void rmclass(char *aclass, int rm_remote, char *a_zoneName);
135 static void usage(void);
136
137 /*
138 * Set by -O debug: debug output is enabled?
139 */
140 static boolean_t debugFlag = B_FALSE;
141
142 /*
143 * Set by -O preremovecheck: do remove dependency checking only
144 */
145 static boolean_t preremoveCheck = B_FALSE;
146
147 /* Set by -O parent-zone-name= */
148
149 static char *parentZoneName = (char *)NULL;
150
151 /* Set by -O parent-zone-type= */
152
153 static char *parentZoneType = (char *)NULL;
154
155 static int nointeract; /* != 0 no interaction with user should occur */
156
157
158
159 int
main(int argc,char * argv[])160 main(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
1129 int
issymlink(char * path)1130 issymlink(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
1157 static void
rmclass(char * aclass,int rm_remote,char * a_zoneName)1158 rmclass(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
1337 static void
ckreturn(int retcode,char * msg)1338 ckreturn(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
1386 static void
usage(void)1387 usage(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 */
1404 static boolean_t
path_valid(char * path)1405 path_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