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