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 2009 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 #include <stdio.h> 31 #include <signal.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <pkgdev.h> 35 #include <locale.h> 36 #include <libintl.h> 37 38 #include <pkglib.h> 39 #include <pkgweb.h> 40 #include <messages.h> 41 42 #include <libadm.h> 43 #include <libinst.h> 44 45 #include "quit.h" 46 47 /* 48 * imported global variables 49 */ 50 51 /* imported from main.c */ 52 53 extern struct pkgdev pkgdev; /* holds info about the installation device */ 54 55 extern int npkgs; /* the number of packages yet to be installed */ 56 extern int admnflag; /* != 0 if any pkgop admin setting failed (4) */ 57 extern int doreboot; /* != 0 if reboot required after installation */ 58 extern int failflag; /* != 0 if fatal error has occurred (1) */ 59 extern int intrflag; /* != 0 if user selected quit (3) */ 60 extern int ireboot; /* != 0 if immediate reboot required */ 61 extern int nullflag; /* != 0 if admin interaction required (5) */ 62 extern int warnflag; /* != 0 if non-fatal error has occurred (2) */ 63 64 /* 65 * forward declarations 66 */ 67 68 static char *dwnldTempDir = (char *)NULL; 69 static char *idsName = (char *)NULL; 70 static char *zoneTempDir = (char *)NULL; 71 static ckreturnFunc_t *ckreturnFunc = (ckreturnFunc_t *)NULL; 72 static int trapEntered = 0; 73 static void trap(int signo); 74 static zoneList_t zoneList = (zoneList_t)NULL; 75 76 /* 77 * exported functions 78 */ 79 80 void quit(int retcode); 81 void quitSetCkreturnFunc(ckreturnFunc_t *a_ckreturnFunc); 82 void quitSetDwnldTmpdir(char *a_dwnldTempDir); 83 void quitSetIdsName(char *a_idsName); 84 void quitSetZoneName(char *a_zoneName); 85 void quitSetZoneTmpdir(char *z_zoneTempDir); 86 void quitSetZonelist(zoneList_t a_zlst); 87 sighdlrFunc_t *quitGetTrapHandler(void); 88 89 /* 90 * ***************************************************************************** 91 * global external (public) functions 92 * ***************************************************************************** 93 */ 94 95 /* 96 * Name: quitGetTrapHandler 97 * Description: return address of this modules "signal trap" handler 98 * Arguments: void 99 * Returns: sighdlrFunc_t 100 * The address of the trap handler that can be passed to 101 * the signal() type system calls 102 */ 103 104 sighdlrFunc_t * 105 quitGetTrapHandler() 106 { 107 return (&trap); 108 } 109 110 /* 111 * Name: quitSetIdsName 112 * Description: set the input data stream name to use when quit() is called 113 * Arguments: a_idsName - pointer to string representing the input data 114 * stream object currently open 115 * == NULL - there is no input datastream object to use 116 * Returns: void 117 * NOTE: When quit() is called, if an input datastream object is set, 118 * quit will close the datastream and cleanup certain objects 119 * associated with the datastream 120 */ 121 122 void 123 quitSetIdsName(char *a_idsName) 124 { 125 idsName = a_idsName; 126 } 127 128 /* 129 * Name: quitSetCkreturnFunc 130 * Description: set the ckreturn() interface to call when quit() is called 131 * Arguments: a_ckreturnFunc - pointer to function to call when quit() is 132 * called 133 * Returns: void 134 * NOTE: When quit() is called if a "ckreturnfunc" is set, then the first 135 * action quit() takes is to call the "ckreturnfunc" specified with 136 * the value passed to quit as the first argument. Quit will then 137 * set the final return code to be used when exit() is called based 138 * on the contents of these global variables: 139 * - admnflag - != 0 if any pkgop admin setting failed (4) 140 * - doreboot - != 0 if reboot required after installation 141 * - failflag - != 0 if fatal error has occurred (1) 142 * - intrflag - != 0 if user selected quit (3) 143 * - ireboot - != 0 if immediate reboot required 144 * - nullflag - != 0 if admin interaction required (5) 145 * - warnflag - != 0 if non-fatal error has occurred (2) 146 */ 147 148 void 149 quitSetCkreturnFunc(ckreturnFunc_t *a_ckreturnFunc) 150 { 151 ckreturnFunc = a_ckreturnFunc; 152 } 153 154 /* 155 * Name: quitSetZonelist 156 * Description: set the list of zones that are "locked" so that the zones can 157 * be unlocked if quit() is called to exit 158 * Arguments: a_zlst - list of zones that are "locked" 159 * Returns: void 160 * NOTE: When quit() is called, if this list is set, then z_unlock_zones 161 * is called to unlock all of the zones in the list. If this list 162 * is NOT set, then z_unlock_this_zone is called to unlock this 163 * zone. 164 */ 165 166 void 167 quitSetZonelist(zoneList_t a_zlst) 168 { 169 zoneList = a_zlst; 170 } 171 172 /* 173 * Name: quitSetZoneName 174 * Description: set the zone name the program is running in 175 * Arguments: a_zoneName - pointer to string representing the name of the zone 176 * that the program is running in 177 * Returns: void 178 */ 179 180 /* ARGSUSED */ 181 void 182 quitSetZoneName(char *a_zoneName) 183 { 184 } 185 186 /* 187 * Name: quitSetZoneTmpdir 188 * Description: set the path to the "zone temporary directory" in use 189 * Arguments: a_zoneTempDir - pointer to string representing the full path to 190 * the temporary directory used to hold files used during 191 * zone operations 192 * Returns: void 193 * NOTE: If a zone temporary directory is set when quit() is called, the 194 * directory is recursively removed before quit() calls exit 195 */ 196 197 void 198 quitSetZoneTmpdir(char *a_zoneTempDir) 199 { 200 zoneTempDir = a_zoneTempDir; 201 } 202 203 /* 204 * Name: quitSetDwnldTmpdir 205 * Description: set the path to the "download temporary directory" in use 206 * Arguments: a_dwnldTempDir - pointer to string representing the full path to 207 * the temporary directory used to hold files used during 208 * download operations 209 * Returns: void 210 * NOTE: If a download temporary directory is set when quit() is called, 211 * the directory is recursively removed before quit() calls exit 212 */ 213 214 void 215 quitSetDwnldTmpdir(char *a_dwnldTempDir) 216 { 217 dwnldTempDir = a_dwnldTempDir; 218 } 219 220 /* 221 * Name: quit 222 * Description: cleanup and exit 223 * Arguments: a_retcode - the code to use to determine final exit status; 224 * if this is NOT "99" and if a "ckreturnFunc" is 225 * set, then that function is called with a_retcode 226 * to set the final exit status. 227 * Valid values are: 228 * 0 - success 229 * 1 - package operation failed (fatal error) 230 * 2 - non-fatal error (warning) 231 * 3 - user selected quit (operation interrupted) 232 * 4 - admin settings prevented operation 233 * 5 - interaction required and -n (non-interactive) specified 234 * "10" is added to indicate "immediate reboot required" 235 * "20" is be added to indicate "reboot after install required" 236 * 99 - do not interpret the code - just exit "99" 237 * Returns: <<this function does not return - calls exit()>> 238 */ 239 240 void 241 quit(int a_retcode) 242 { 243 /* disable interrupts */ 244 245 (void) signal(SIGINT, SIG_IGN); 246 (void) signal(SIGHUP, SIG_IGN); 247 248 if (!restore_local_fs()) { 249 progerr(ERR_CANNOT_RESTORE_LOCAL_FS); 250 } 251 252 /* process return code if not quit(99) */ 253 254 if (a_retcode != 99) { 255 if (ckreturnFunc != (ckreturnFunc_t *)NULL) { 256 (ckreturnFunc)(a_retcode); 257 } 258 if (failflag) { 259 a_retcode = 1; 260 } else if (warnflag) { 261 a_retcode = 2; 262 } else if (intrflag) { 263 a_retcode = 3; 264 } else if (admnflag) { 265 a_retcode = 4; 266 } else if (nullflag) { 267 a_retcode = 5; 268 } else { 269 a_retcode = 0; 270 } 271 if (ireboot) { 272 a_retcode = (a_retcode % 10) + 20; 273 } 274 if (doreboot) { 275 a_retcode = (a_retcode % 10) + 10; 276 } 277 } 278 279 if (doreboot || ireboot) { 280 ptext(stderr, MSG_REBOOT); 281 } 282 283 (void) chdir("/"); 284 285 /* if set remove download temporary directory */ 286 287 if (dwnldTempDir != (char *)NULL) { 288 echoDebug(DBG_REMOVING_DWNLD_TMPDIR, dwnldTempDir); 289 (void) rrmdir(dwnldTempDir); 290 dwnldTempDir = (char *)NULL; 291 } 292 293 /* if set remove zone temporary directory */ 294 295 if (zoneTempDir != (char *)NULL) { 296 echoDebug(DBG_REMOVING_ZONE_TMPDIR, zoneTempDir); 297 (void) rrmdir(zoneTempDir); 298 zoneTempDir = (char *)NULL; 299 } 300 301 /* close and cleanup if input datastream is set */ 302 303 if (idsName != (char *)NULL) { /* datastream */ 304 if (pkgdev.dirname != NULL) { 305 echoDebug(DBG_REMOVING_DSTREAM_TMPDIR, pkgdev.dirname); 306 (void) rrmdir(pkgdev.dirname); /* from tempnam */ 307 } 308 /* 309 * cleanup after a web-based install. 310 * web-based install failures 311 * are indicated by exit codes 10-98 312 * exit code 99 is fatal error exit. 313 */ 314 if (pkgdev.pathname != NULL && is_web_install() && 315 (a_retcode == 0 || 316 (a_retcode >= 10 && a_retcode < 99))) { 317 (void) web_cleanup(); 318 } 319 (void) ds_close(1); 320 } else if (pkgdev.mount) { 321 (void) pkgumount(&pkgdev); 322 } 323 324 /* 325 * issue final exit message depending on number of packages left 326 * to process 327 */ 328 329 if (npkgs == 1) { 330 echo(MSG_1_PKG_NOT_PROCESSED); 331 } else if (npkgs) { 332 echo(MSG_N_PKGS_NOT_PROCESSED, npkgs); 333 } 334 335 /* if a zone list exists, unlock all zones */ 336 337 if (zoneList != (zoneList_t)NULL) { 338 (void) z_unlock_zones(zoneList, ZLOCKS_ALL); 339 } else { 340 (void) z_unlock_this_zone(ZLOCKS_ALL); 341 } 342 343 /* final exit debugging message */ 344 345 echoDebug(DBG_EXIT_WITH_CODE, a_retcode); 346 347 exit(a_retcode); 348 /* NOTREACHED */ 349 } 350 351 /* 352 * ***************************************************************************** 353 * static internal (private) functions 354 * ***************************************************************************** 355 */ 356 357 /* 358 * Name: trap 359 * Description: signal handler connected via quitGetTrapHandler() 360 * Arguments: signo - [RO, *RO] - (int) 361 * Integer representing the signal that caused the trap 362 * to this function to occur 363 * Returns: << NONE >> 364 * NOTE: This function exits the program after doing mandatory cleanup. 365 * NOTE: Even though quit() should NOT return, there is a call to _exit() 366 * put after each call to quit() just in case quit() ever returned 367 * by mistake. 368 */ 369 370 static void 371 trap(int signo) 372 { 373 /* prevent reentrance */ 374 375 if (trapEntered++ != 0) { 376 return; 377 } 378 379 if ((signo == SIGINT) || (signo == SIGHUP)) { 380 quit(3); 381 _exit(3); 382 } 383 quit(1); 384 _exit(1); 385 } 386