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