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 2005 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 #include <stdio.h> 32 #include <limits.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 #include <pkglocs.h> 38 #include <locale.h> 39 #include <libintl.h> 40 #include <string.h> 41 #include <signal.h> 42 #include <sys/types.h> 43 #include <sys/signal.h> 44 #include <sys/fault.h> 45 #include <sys/syscall.h> 46 #include <pkglib.h> 47 #include "libadm.h" 48 49 extern int errno; 50 51 #define ST_QUIT 1 52 #define ST_OK 0 53 54 #define LOCKFILE ".lockfile" 55 #define LCKBUFSIZ 128 56 #define LOCKWAIT 20 /* seconds between retries */ 57 #define LOCKRETRY 10 /* number of retries for a DB lock */ 58 #define LF_SIZE 128 /* size of governing lock file */ 59 60 #define MSG_WTING "NOTE: Waiting for access to the package database." 61 #define MSG_XWTING "NOTE: Waiting for exclusive access to the package " \ 62 "database." 63 #define MSG_WTFOR "NOTE: Waiting for %s of %s to complete." 64 #define WRN_CLRLOCK "WARNING: Stale lock installed for %s, pkg %s quit " \ 65 "in %s state." 66 #define WRN_CLRLOCK1 "Removing lock." 67 #define ERR_MKLOCK "unable to create governing lock file <%s>." 68 #define ERR_NOLOCK "unable to install governing lock on <%s>." 69 #define ERR_NOOPEN "unable to open <%s>." 70 #define ERR_LCKTBL "unable to lock <%s> - lock table full." 71 #define ERR_LCKREM "unable to lock <%s> - remote host unavailable." 72 #define ERR_BADLCK "unable to lock <%s> - unknown error." 73 #define ERR_DEADLCK "unable to lock <%s> - deadlock condition." 74 75 static pid_t lock_pid; 76 static int lock_fd, lock_is_applied; 77 static char lock_name[PKGSIZ]; 78 static char lock_pkg[PKGSIZ]; 79 static char lock_place[PKGSIZ]; 80 static unsigned int lock_state; 81 static char lockbuf[LCKBUFSIZ]; 82 static char lockpath[PATH_MAX]; 83 84 #define LOCK_NAME_OLD_PKG "old version pkg command" 85 #define LOCK_PKG_UNKNOWN "unknown package" 86 #define LOCK_PLACE_UNKNOWN "unknown" 87 88 /* 89 * This function writes the PID, effective utility name, package name, 90 * current progress of the utility and the exit state to the lockfile in 91 * support of post mortem operations. 92 */ 93 static int 94 wrlockdata(int fd, int this_pid, char *this_name, 95 char *this_pkg, char *this_place, unsigned int this_state) 96 { 97 if (this_pid < 0 || *this_name == '\000') 98 return (0); 99 100 (void) memset(lockbuf, 0, LCKBUFSIZ); 101 102 (void) snprintf(lockbuf, sizeof (lockbuf), 103 "%d %s %s %s %d\n", this_pid, this_name, this_pkg, 104 this_place, this_state); 105 106 (void) lseek(fd, 0, SEEK_SET); 107 if (write(fd, lockbuf, LF_SIZE) == LF_SIZE) 108 return (1); 109 else 110 return (0); 111 } 112 113 /* 114 * This function reads the lockfile to obtain the PID and name of the lock 115 * holder. Upon those rare circumstances that an older version of pkgadd 116 * created the lock, this detects that zero-length file and provides the 117 * appropriate data. Since this data is only used if an actual lock (from 118 * lockf()) is detected, a manually created .lockfile will not result in a 119 * message. 120 */ 121 static void 122 rdlockdata(int fd) 123 { 124 (void) lseek(fd, 0, SEEK_SET); 125 if (read(fd, lockbuf, LF_SIZE) != LF_SIZE) { 126 lock_pid = 0; 127 (void) strlcpy(lock_name, LOCK_NAME_OLD_PKG, 128 sizeof (lock_name)); 129 130 (void) strlcpy(lock_pkg, LOCK_PKG_UNKNOWN, 131 sizeof (lock_pkg)); 132 133 (void) strlcpy(lock_place, LOCK_PLACE_UNKNOWN, 134 sizeof (lock_place)); 135 136 lock_state = ST_OK; 137 } else { 138 /* LINTED format argument contains unbounded string specifier */ 139 (void) sscanf(lockbuf, "%ld %s %s %s %u", &lock_pid, 140 lock_name, lock_pkg, lock_place, &lock_state); 141 } 142 } 143 144 static void 145 do_alarm(int n) 146 { 147 #ifdef lint 148 int i = n; 149 n = i; 150 #endif /* lint */ 151 (void) signal(SIGALRM, do_alarm); 152 (void) alarm(LOCKWAIT); 153 } 154 155 /* 156 * This establishes a locked status file for a pkgadd, pkgrm or swmtool - any 157 * of the complex package processes. Since numerous packages currently use 158 * installf and removef in preinstall scripts, we can't enforce a contents 159 * file write lock throughout the install process. In 2.7 we will enforce the 160 * write lock and allow this lock to serve as a simple information carrier 161 * which can be used by installf and removef too. 162 * Arguments: 163 * util_name - the name of the utility that is claiming the lock 164 * pkg_name - the package that is being locked (or "all package") 165 * place - a string of ascii characters that defines the initial "place" where 166 * the current operation is - this is updated by lockupd() and is a string 167 * is used fr post mortem operations if the utility should quit improperly. 168 * Returns (int): 169 * == 0 - failure 170 * != 0 - success 171 */ 172 173 int 174 lockinst(char *util_name, char *pkg_name, char *place) 175 { 176 int fd, retry_cnt; 177 178 /* assume "initial" if no "place" during processing specified */ 179 180 if ((place == (char *)NULL) || (*place == '\0')) { 181 place = "initial"; 182 } 183 184 (void) snprintf(lockpath, sizeof (lockpath), 185 "%s/%s", get_PKGADM(), LOCKFILE); 186 187 /* If the exit file is not present, create it. */ 188 /* LINTED O_CREAT without O_EXCL specified in call to open() */ 189 if ((fd = open(lockpath, O_RDWR | O_CREAT, 0600)) == -1) { 190 progerr(gettext(ERR_MKLOCK), lockpath); 191 return (0); 192 } 193 194 lock_fd = fd; 195 196 retry_cnt = LOCKRETRY; 197 lock_is_applied = 0; 198 199 (void) signal(SIGALRM, do_alarm); 200 (void) alarm(LOCKWAIT); 201 202 /* 203 * This tries to create the lock LOCKRETRY times waiting LOCKWAIT 204 * seconds between retries. 205 */ 206 do { 207 208 if (lockf(fd, F_LOCK, 0)) { 209 /* 210 * Try to read the status of the last (or current) 211 * utility. 212 */ 213 rdlockdata(fd); 214 215 logerr(gettext(MSG_WTFOR), lock_name, lock_pkg); 216 } else { /* This process has the lock. */ 217 rdlockdata(fd); 218 219 if (lock_state != 0) { 220 logerr(gettext(WRN_CLRLOCK), lock_name, 221 lock_pkg, lock_place); 222 logerr(gettext(WRN_CLRLOCK1)); 223 } 224 225 lock_pid = getpid(); 226 (void) strlcpy(lock_name, (util_name) ? 227 util_name : gettext("unknown"), sizeof (lock_name)); 228 229 (void) strlcpy(lock_pkg, (pkg_name) ? 230 pkg_name : gettext("unknown"), sizeof (lock_pkg)); 231 232 (void) wrlockdata(fd, lock_pid, lock_name, 233 lock_pkg, place, ST_QUIT); 234 lock_is_applied = 1; 235 break; 236 } 237 } while (retry_cnt--); 238 239 (void) signal(SIGALRM, SIG_IGN); 240 241 if (!lock_is_applied) { 242 progerr(gettext(ERR_NOLOCK), lockpath); 243 return (0); 244 } 245 246 return (1); 247 } 248 249 /* 250 * This function updates the utility progress data in the lock file. It is 251 * used for post mortem operations if the utility should quit improperly. 252 */ 253 void 254 lockupd(char *place) 255 { 256 (void) wrlockdata(lock_fd, lock_pid, lock_name, lock_pkg, place, 257 ST_QUIT); 258 } 259 260 /* 261 * This clears the governing lock and closes the lock file. If this was 262 * called already, it just returns. 263 */ 264 void 265 unlockinst(void) 266 { 267 if (lock_is_applied) { 268 (void) wrlockdata(lock_fd, lock_pid, lock_name, lock_pkg, 269 "finished", ST_OK); 270 271 /* 272 * If close() fails, we can't be sure the lock has been 273 * removed, so we assume the worst in case this function is 274 * called again. 275 */ 276 if (close(lock_fd) != -1) 277 lock_is_applied = 0; 278 } 279 } 280