xref: /illumos-gate/usr/src/cmd/svr4pkg/libinst/lockinst.c (revision 5c51f1241dbbdf2656d0e10011981411ed0c9673)
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
wrlockdata(int fd,int this_pid,char * this_name,char * this_pkg,char * this_place,unsigned int this_state)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
rdlockdata(int fd)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
do_alarm(int n)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
lockinst(char * util_name,char * pkg_name,char * place)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
lockupd(char * place)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
unlockinst(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