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]
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 */
34 #include <sys/utsname.h>
48 #include "pkginstall.h"
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 */
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) */
66 extern char pkgloc_sav
[];
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
107 * Returns: sighdlrFunc_t
108 * The address of the trap handler that can be passed to
109 * the signal() type system calls
113 quitGetTrapHandler(void)
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
127 quitSetZoneName(char *a_zoneName
)
129 zoneName
= a_zoneName
;
130 if ((zoneName
== (char *)NULL
|| *zoneName
== '\0')) {
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()
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)
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()
177 * Arguments: a_installStarted - indicates whether or not installation
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
193 * Arguments: a_pkgaskflag - indicates whether or not pkgask is being run
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
212 quitSetSilentExit(boolean_t a_silentExit
)
214 silentExit
= a_silentExit
;
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.
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()>>
240 /* disable interrupts */
242 (void) signal(SIGINT
, SIG_IGN
);
243 (void) signal(SIGHUP
, SIG_IGN
);
245 /* process return code if not quit(99) */
248 if ((retcode
% 10) == 0) {
251 } else if (warnflag
) {
257 retcode
= (retcode
% 10) + 20;
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()) {
275 set_dr_info(EXITCODE
, retcode
);
276 if (failflag
|| warnflag
) {
277 set_dr_exitmsg(msgtext
);
279 /* LINTED variable format specified */
280 (void) snprintf(exit_msg
, sizeof (exit_msg
),
281 qreason(1, retcode
, installStarted
,
283 (pkginst
? pkginst
: "unknown"),
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
);
296 /* fix bug #1082589 that deletes root file */
297 if (tmpdir
[0] != NULL
) {
298 (void) rrmdir(tmpdir
);
301 /* send mail to appropriate user list */
304 /* display message about this installation */
309 * In the event that this quit() was called prior to completion of
310 * the task, do an unlockinst() just in case.
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
);
332 (void) rrmdir(pkgloc
);
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
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
,
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
367 ds_skiptoend(pkgdev
.cdevice
);
370 /* Free the filesystem table. */
373 /* Free the package information lists. */
376 /* Free all stragglers. */
378 (void) pathdup(NULL
);
383 /* final exit debugging message */
385 echoDebug(DBG_EXIT_WITH_CODE
, retcode
);
392 * *****************************************************************************
393 * static internal (private) functions
394 * *****************************************************************************
400 if (silentExit
== B_TRUE
) {
404 (void) putc('\n', stderr
);
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
);
421 struct utsname utsbuf
;
426 if (silentExit
== B_TRUE
) {
430 if (!installStarted
|| pkgaskFlag
|| (adm
.mail
== NULL
)) {
434 len
= strlen(adm
.mail
) + sizeof (MAILCMD
) + 2;
435 cmd
= calloc(len
, sizeof (char));
441 (void) snprintf(cmd
, len
, "%s %s", MAILCMD
, adm
.mail
);
442 if ((pp
= popen(cmd
, "w")) == NULL
) {
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
);
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
477 /* prevent reentrance */
479 if (trapEntered
++ != 0) {
483 if ((signo
== SIGINT
) || (signo
== SIGHUP
)) {