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