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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 
30 
31 /*
32  * System includes
33  */
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <sys/utsname.h>
41 #include <locale.h>
42 #include <libintl.h>
43 
44 /*
45  * consolidation pkg command library includes
46  */
47 
48 #include <pkglib.h>
49 
50 /*
51  * local pkg command library includes
52  */
53 
54 #include "install.h"
55 #include "libadm.h"
56 #include "libinst.h"
57 #include "messages.h"
58 
59 #define	MAILCMD	"/usr/bin/mail"
60 
61 /* lockinst.c */
62 extern void	unlockinst(void);
63 
64 /* mntinfo.c */
65 extern int	unmount_client(void);
66 
67 extern char	*msgtext;
68 extern char	*pkginst;
69 
70 extern int	started;
71 extern int	dreboot;	/* != 0 if reboot required after installation */
72 extern int	failflag;	/* != 0 if fatal error has occurred (1) */
73 extern int	ireboot;	/* != 0 if immediate reboot required */
74 extern int	warnflag;	/* != 0 if non-fatal error has occurred (2) */
75 
76 extern struct admin	adm;
77 
78 /*
79  * exported functions
80  */
81 
82 void			quit(int retcode);
83 void			quitSetSilentExit(boolean_t a_silentExit);
84 void			quitSetZoneName(char *a_zoneName);
85 sighdlrFunc_t		*quitGetTrapHandler(void);
86 
87 /*
88  * forward declarations
89  */
90 
91 static void		mailmsg(int retcode);
92 static void		quitmsg(int retcode);
93 static void		trap(int signo);
94 
95 static char		*zoneName = (char *)NULL;
96 static boolean_t	silentExit = B_FALSE;
97 static int		includeZonename = 0;
98 static int		trapEntered = 0;
99 
100 /*
101  * *****************************************************************************
102  * global external (public) functions
103  * *****************************************************************************
104  */
105 
106 /*
107  * Name:	quitGetTrapHandler
108  * Description:	return address of this modules "signal trap" handler
109  * Arguments:	void
110  * Returns:	sighdlrFunc_t
111  *			The address of the trap handler that can be passed to
112  *			the signal() type system calls
113  */
114 
115 sighdlrFunc_t *
quitGetTrapHandler()116 quitGetTrapHandler()
117 {
118 	return (&trap);
119 }
120 
121 /*
122  * Name:	quitSetZoneName
123  * Description:	set the zone name the program is running in
124  * Arguments:	a_zoneName - pointer to string representing the name of the zone
125  *			that the program is running in
126  * Returns:	void
127  */
128 
129 void
quitSetZoneName(char * a_zoneName)130 quitSetZoneName(char *a_zoneName)
131 {
132 	zoneName = a_zoneName;
133 	if ((zoneName == (char *)NULL || *zoneName == '\0')) {
134 		includeZonename = 0;
135 	} else {
136 		includeZonename = 1;
137 	}
138 }
139 
140 /*
141  * Name:	quitSetSilentExit
142  * Description:	set the "silent exit" flag - if silent exit is TRUE, then
143  *		no messages are output by quit() when it is called
144  * Arguments:	a_silentExit - indicates whether or not silent exit is set
145  * Returns:	void
146  */
147 
148 void
quitSetSilentExit(boolean_t a_silentExit)149 quitSetSilentExit(boolean_t a_silentExit)
150 {
151 	silentExit = a_silentExit;
152 }
153 
154 /*
155  * Name:	quit
156  * Description:	cleanup and exit
157  * Arguments:	a_retcode - the code to use to determine final exit status;
158  *			if this is NOT "99" and if a "ckreturnFunc" is
159  *			set, then that function is called with a_retcode
160  *			to set the final exit status.
161  *		Valid values are:
162  *		0 - success
163  *		1 - package operation failed (fatal error)
164  *		2 - non-fatal error (warning)
165  *		3 - user selected quit (operation interrupted)
166  *		4 - admin settings prevented operation
167  *		5 - interaction required and -n (non-interactive) specified
168  *		"10" is added to indicate "immediate reboot required"
169  *		"20" is be added to indicate "reboot after install required"
170  *		99 - do not interpret the code - just exit "99"
171  * Returns:	<<this function does not return - calls exit()>>
172  */
173 
174 void
quit(int retcode)175 quit(int retcode)
176 {
177 	/* disable interrupts */
178 
179 	(void) signal(SIGINT, SIG_IGN);
180 	(void) signal(SIGHUP, SIG_IGN);
181 
182 	/* process return code if not quit(99) */
183 
184 	if (retcode != 99) {
185 		if ((retcode % 10) == 0) {
186 			if (failflag) {
187 				retcode += 1;
188 			} else if (warnflag) {
189 				retcode += 2;
190 			}
191 		}
192 
193 		if (ireboot) {
194 			retcode = (retcode % 10) + 20;
195 		}
196 
197 		if (dreboot) {
198 			retcode = (retcode % 10) + 10;
199 		}
200 	}
201 
202 	/*
203 	 * In the event that this quit() was called prior to completion of
204 	 * the task, do an unlockinst() just in case.
205 	 */
206 	unlockinst();
207 
208 	/* unmount the mounts that are our responsibility. */
209 	(void) unmount_client();
210 
211 	/* send mail to appropriate user list */
212 	mailmsg(retcode);
213 
214 	/* display message about this installation */
215 	quitmsg(retcode);
216 
217 	/* final exit debugging message */
218 
219 	echoDebug(DBG_EXIT_WITH_CODE, retcode);
220 
221 	exit(retcode);
222 	/*NOTREACHED*/
223 }
224 
225 /*
226  * *****************************************************************************
227  * static internal (private) functions
228  * *****************************************************************************
229  */
230 
231 static void
quitmsg(int retcode)232 quitmsg(int retcode)
233 {
234 	if (silentExit == B_TRUE) {
235 		return;
236 	}
237 
238 	(void) putc('\n', stderr);
239 
240 	/* if there is no pkgname, no message to report */
241 	if (pkginst != (char *)NULL) {
242 		ptext(stderr, qreason(3, retcode, 0, includeZonename),
243 			pkginst, zoneName);
244 	}
245 
246 	if (retcode && !started) {
247 		ptext(stderr, MSG_NOCHANGE);
248 	}
249 }
250 
251 static void
mailmsg(int retcode)252 mailmsg(int retcode)
253 {
254 	struct utsname utsbuf;
255 	FILE	*pp;
256 	char	*cmd;
257 	size_t	len;
258 
259 	if (silentExit == B_TRUE) {
260 		return;
261 	}
262 
263 	if (!started || (adm.mail == NULL))
264 		return;
265 
266 	len = strlen(adm.mail) + sizeof (MAILCMD) + 2;
267 	cmd = calloc(len, sizeof (char));
268 	if (cmd == NULL) {
269 		logerr(WRN_NOMAIL);
270 		return;
271 	}
272 
273 	(void) snprintf(cmd, len, "%s %s", MAILCMD, adm.mail);
274 	if ((pp = popen(cmd, "w")) == NULL) {
275 		logerr(WRN_NOMAIL);
276 		return;
277 	}
278 
279 	if (msgtext) {
280 		ptext(pp, gettext(msgtext));
281 	}
282 
283 	(void) strcpy(utsbuf.nodename, gettext("(unknown)"));
284 	(void) uname(&utsbuf);
285 	ptext(pp, qreason(4, retcode, 0, includeZonename), pkginst,
286 		utsbuf.nodename, zoneName);
287 
288 	if (pclose(pp)) {
289 		logerr(WRN_FLMAIL);
290 	}
291 }
292 
293 /*
294  * Name:	trap
295  * Description:	signal handler connected via quitGetTrapHandler()
296  * Arguments:	signo - [RO, *RO] - (int)
297  *			Integer representing the signal that caused the trap
298  *			to this function to occur
299  * Returns:	<< NONE >>
300  * NOTE:	This function exits the program after doing mandatory cleanup.
301  * NOTE:	Even though quit() should NOT return, there is a call to _exit()
302  *		put after each call to quit() just in case quit() ever returned
303  *		by mistake.
304  */
305 
306 static void
trap(int signo)307 trap(int signo)
308 {
309 	/* prevent reentrance */
310 
311 	if (trapEntered++ != 0) {
312 		return;
313 	}
314 
315 	if ((signo == SIGINT) || (signo == SIGHUP)) {
316 		quit(3);
317 		_exit(3);
318 	}
319 	quit(1);
320 	_exit(1);
321 }
322