420 remove patch (sparse package) support from svr4 pkg
[illumos-gate.git] / usr / src / cmd / svr4pkg / pkginstall / quit.c
blob664de9512671e5f84c29bb254201a79984c9a547
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #include <stdio.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/utsname.h>
35 #include <limits.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <pkgdev.h>
39 #include <pkglocs.h>
40 #include <locale.h>
41 #include <libintl.h>
42 #include <errno.h>
43 #include <pkglib.h>
44 #include "install.h"
45 #include "dryrun.h"
46 #include "libadm.h"
47 #include "libinst.h"
48 #include "pkginstall.h"
49 #include "messages.h"
51 /* main.c */
52 extern char *pkgdrtarg;
53 extern struct cfextra **extlist;
55 extern struct admin adm;
56 extern struct pkgdev pkgdev; /* holds info about the installation device */
58 extern int dparts;
59 extern int dreboot; /* != 0 if reboot required after installation */
60 extern int failflag; /* != 0 if fatal error has occurred (1) */
61 extern int ireboot; /* != 0 if immediate reboot required */
62 extern int warnflag; /* != 0 if non-fatal error has occurred (2) */
64 extern char tmpdir[];
65 extern char pkgloc[];
66 extern char pkgloc_sav[];
67 extern char *msgtext;
68 extern char *pkginst;
69 extern char *pkgname;
72 * exported functions
75 void quit(int retcode);
76 void quitSetZoneName(char *a_zoneName);
77 sighdlrFunc_t *quitGetTrapHandler(void);
80 * forward declarations
83 static void trap(int signo);
84 static void mailmsg(int retcode);
85 static void quitmsg(int retcode);
87 static boolean_t silentExit = B_FALSE;
88 static boolean_t pkgaskFlag = B_FALSE;
89 static boolean_t installStarted = B_FALSE;
90 static boolean_t updatingExistingPackage = B_FALSE;
92 static char *dstreamTempDir = (char *)NULL;
93 static char *zoneName = (char *)NULL;
94 static int includeZonename = 0;
95 static int trapEntered = 0;
98 * *****************************************************************************
99 * global external (public) functions
100 * *****************************************************************************
104 * Name: quitGetTrapHandler
105 * Description: return address of this modules "signal trap" handler
106 * Arguments: void
107 * Returns: sighdlrFunc_t
108 * The address of the trap handler that can be passed to
109 * the signal() type system calls
112 sighdlrFunc_t *
113 quitGetTrapHandler(void)
115 return (&trap);
119 * Name: quitSetZoneName
120 * Description: set the zone name the program is running in
121 * Arguments: a_zoneName - pointer to string representing the name of the zone
122 * that the program is running in
123 * Returns: void
126 void
127 quitSetZoneName(char *a_zoneName)
129 zoneName = a_zoneName;
130 if ((zoneName == (char *)NULL || *zoneName == '\0')) {
131 includeZonename = 0;
132 } else {
133 includeZonename = 1;
138 * Name: quitSetDstreamTmpdir
139 * Description: set the name of a temporary directory that contains package
140 * streams to be removed when quit() is called
141 * Arguments: a_dstreamTempDir - pointer to string representing the path
142 * to the temporary directory to remove when quit()
143 * is called
144 * Returns: void
147 void
148 quitSetDstreamTmpdir(char *a_dstreamTempDir)
150 dstreamTempDir = a_dstreamTempDir;
154 * Name: quitSetUpdatingExisting
155 * Description: set the "updating existing" flag - used in conjunction
156 * with the "install started" flag to determine the type
157 * of cleanup to be done when quit() is called
158 * Arguments: a_updatingExistingPackage - indicates whether or not existing
159 * packages are being updated (B_TRUE) or new packages
160 * are being installed (B_FALSE)
161 * Returns: void
164 void
165 quitSetUpdatingExisting(boolean_t a_updatingExistingPackage)
167 updatingExistingPackage = a_updatingExistingPackage;
171 * Name: quitSetInstallStarted
172 * Description: set the "install started" flag - used in conjunction
173 * with the "updating existing" flag to determine the type
174 * of cleanup to be done when quit() is called, and the
175 * type of message to be output for the "reason" why quit()
176 * was called
177 * Arguments: a_installStarted - indicates whether or not installation
178 * has started
179 * Returns: void
182 void
183 quitSetInstallStarted(boolean_t a_installStarted)
185 installStarted = a_installStarted;
189 * Name: quitSetPkgask
190 * Description: set the "pkgask is being run" flag - used to determine
191 * the type of message to be output for the "reason" why
192 * quit() was called
193 * Arguments: a_pkgaskflag - indicates whether or not pkgask is being run
194 * Returns: void
197 void
198 quitSetPkgask(boolean_t a_pkgaskFlag)
200 pkgaskFlag = a_pkgaskFlag;
204 * Name: quitSetSilentExit
205 * Description: set the "silent exit" flag - if silent exit is TRUE, then
206 * no messages are output by quit() when it is called
207 * Arguments: a_silentExit - indicates whether or not silent exit is set
208 * Returns: void
211 void
212 quitSetSilentExit(boolean_t a_silentExit)
214 silentExit = a_silentExit;
218 * Name: quit
219 * Description: cleanup and exit
220 * Arguments: a_retcode - the code to use to determine final exit status;
221 * if this is NOT "99" and if a "ckreturnFunc" is
222 * set, then that function is called with a_retcode
223 * to set the final exit status.
224 * Valid values are:
225 * 0 - success
226 * 1 - package operation failed (fatal error)
227 * 2 - non-fatal error (warning)
228 * 3 - user selected quit (operation interrupted)
229 * 4 - admin settings prevented operation
230 * 5 - interaction required and -n (non-interactive) specified
231 * "10" is added to indicate "immediate reboot required"
232 * "20" is be added to indicate "reboot after install required"
233 * 99 - do not interpret the code - just exit "99"
234 * Returns: <<this function does not return - calls exit()>>
237 void
238 quit(int retcode)
240 /* disable interrupts */
242 (void) signal(SIGINT, SIG_IGN);
243 (void) signal(SIGHUP, SIG_IGN);
245 /* process return code if not quit(99) */
247 if (retcode != 99) {
248 if ((retcode % 10) == 0) {
249 if (failflag) {
250 retcode += 1;
251 } else if (warnflag) {
252 retcode += 2;
256 if (ireboot) {
257 retcode = (retcode % 10) + 20;
259 if (dreboot) {
260 retcode = (retcode % 10) + 10;
264 /* if set remove dstream temporary directory */
266 if (dstreamTempDir != (char *)NULL) {
267 echoDebug(DBG_REMOVING_DSTREAM_TMPDIR, dstreamTempDir);
268 (void) rrmdir(dstreamTempDir);
269 dstreamTempDir = (char *)NULL;
272 /* If we're in dryrun mode, write out the dryrun file(s). */
273 if (in_dryrun_mode()) {
274 char exit_msg[200];
275 set_dr_info(EXITCODE, retcode);
276 if (failflag || warnflag) {
277 set_dr_exitmsg(msgtext);
278 } else {
279 /* LINTED variable format specified */
280 (void) snprintf(exit_msg, sizeof (exit_msg),
281 qreason(1, retcode, installStarted,
282 includeZonename),
283 (pkginst ? pkginst : "unknown"),
284 zoneName);
285 set_dr_exitmsg(exit_msg);
288 write_dryrun_file(extlist);
289 ptext(stderr, MSG_DRYRUN_DONE);
290 ptext(stderr, MSG_NOCHANGE);
292 if (tmpdir[0] != NULL)
293 (void) rrmdir(tmpdir);
295 } else {
296 /* fix bug #1082589 that deletes root file */
297 if (tmpdir[0] != NULL) {
298 (void) rrmdir(tmpdir);
301 /* send mail to appropriate user list */
302 mailmsg(retcode);
304 /* display message about this installation */
305 quitmsg(retcode);
309 * In the event that this quit() was called prior to completion of
310 * the task, do an unlockinst() just in case.
312 unlockinst();
314 /* Unmount anything that's our responsibility. */
315 (void) unmount_client();
318 * No need to umount device since calling process
319 * was responsible for original mount
322 if (!updatingExistingPackage) {
323 if (!installStarted && pkgloc[0]) {
325 * install not yet started; if package install
326 * location is defined, remove the package.
328 echoDebug(DBG_QUIT_REMOVING_PKGDIR, pkgloc);
330 (void) chdir("/");
331 if (pkgloc[0]) {
332 (void) rrmdir(pkgloc);
335 } else {
336 if (!installStarted) {
338 * If we haven't started, but have already done
339 * the <PKGINST>/install directory rename, then
340 * remove the new <PKGINST>/install directory
341 * and rename <PKGINST>/install.save back to
342 * <PKGINST>/install.
344 if (pkgloc_sav[0] && !access(pkgloc_sav, F_OK)) {
345 if (pkgloc[0] && !access(pkgloc, F_OK))
346 (void) rrmdir(pkgloc);
347 if (rename(pkgloc_sav, pkgloc) == -1) {
348 progerr(ERR_PACKAGEBINREN,
349 pkgloc_sav, pkgloc);
352 } else {
353 if (pkgloc_sav[0] && !access(pkgloc_sav, F_OK)) {
354 echoDebug(DBG_QUIT_REMOVING_PKGSAV, pkgloc_sav);
355 (void) rrmdir(pkgloc_sav);
361 * pkginst can be null if an administration setting doesn't all
362 * the package to be installed. Make sure pkginst exeists before
363 * updating the DB
366 if (dparts > 0)
367 ds_skiptoend(pkgdev.cdevice);
368 (void) ds_close(1);
370 /* Free the filesystem table. */
371 fs_tab_free();
373 /* Free the package information lists. */
374 pinfo_free();
376 /* Free all stragglers. */
377 bl_free(BL_ALL);
378 (void) pathdup(NULL);
380 /* Free regfiles. */
381 regfiles_free();
383 /* final exit debugging message */
385 echoDebug(DBG_EXIT_WITH_CODE, retcode);
387 exit(retcode);
388 /*NOTREACHED*/
392 * *****************************************************************************
393 * static internal (private) functions
394 * *****************************************************************************
397 static void
398 quitmsg(int retcode)
400 if (silentExit == B_TRUE) {
401 return;
404 (void) putc('\n', stderr);
405 if (pkgaskFlag) {
406 ptext(stderr, qreason(0, retcode, installStarted,
407 includeZonename), zoneName);
408 } else if (pkginst) {
409 ptext(stderr, qreason(1, retcode, installStarted,
410 includeZonename), pkginst, zoneName);
413 if (retcode && !installStarted) {
414 ptext(stderr, MSG_NOCHANGE);
418 static void
419 mailmsg(int retcode)
421 struct utsname utsbuf;
422 FILE *pp;
423 char *cmd;
424 size_t len;
426 if (silentExit == B_TRUE) {
427 return;
430 if (!installStarted || pkgaskFlag || (adm.mail == NULL)) {
431 return;
434 len = strlen(adm.mail) + sizeof (MAILCMD) + 2;
435 cmd = calloc(len, sizeof (char));
436 if (cmd == NULL) {
437 logerr(WRN_NOMAIL);
438 return;
441 (void) snprintf(cmd, len, "%s %s", MAILCMD, adm.mail);
442 if ((pp = popen(cmd, "w")) == NULL) {
443 logerr(WRN_NOMAIL);
444 return;
447 if (msgtext)
448 ptext(pp, msgtext);
450 (void) strcpy(utsbuf.nodename, MSG_NODENAME);
451 (void) uname(&utsbuf);
453 ptext(pp, qreason(2, retcode, installStarted, includeZonename),
454 pkgname, utsbuf.nodename, pkginst, zoneName);
456 if (pclose(pp)) {
457 logerr(WRN_FLMAIL);
462 * Name: trap
463 * Description: signal handler connected via quitGetTrapHandler()
464 * Arguments: signo - [RO, *RO] - (int)
465 * Integer representing the signal that caused the trap
466 * to this function to occur
467 * Returns: << NONE >>
468 * NOTE: This function exits the program after doing mandatory cleanup.
469 * NOTE: Even though quit() should NOT return, there is a call to _exit()
470 * put after each call to quit() just in case quit() ever returned
471 * by mistake.
474 static void
475 trap(int signo)
477 /* prevent reentrance */
479 if (trapEntered++ != 0) {
480 return;
483 if ((signo == SIGINT) || (signo == SIGHUP)) {
484 quit(3);
485 _exit(3);
487 quit(1);
488 _exit(1);