"Fossies" - the Fresh Open Source Software Archive 
Member "schily-2021-09-18/sunpro/Make/lib/vroot/src/lock.cc" (14 Aug 2021, 6192 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:
1 /*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may use this file only in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23 /*
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27 /*
28 * @(#)lock.cc 1.17 06/12/12
29 */
30
31 #pragma ident "@(#)lock.cc 1.17 06/12/12"
32
33 /*
34 * Copyright 2017-2021 J. Schilling
35 *
36 * @(#)lock.cc 1.10 21/08/15 2017-2021 J. Schilling
37 */
38 #include <schily/mconfig.h>
39 #ifndef lint
40 static UConst char sccsid[] =
41 "@(#)lock.cc 1.10 21/08/15 2017-2021 J. Schilling";
42 #endif
43
44 #include <avo/intl.h> /* for NOCATGETS */
45
46 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
47 #include <schily/stdio.h>
48 #include <schily/stdlib.h>
49 #include <schily/string.h>
50 #include <schily/param.h>
51 #include <schily/stat.h>
52 #include <schily/types.h>
53 #include <schily/unistd.h>
54 #else
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <sys/param.h>
59 #include <sys/stat.h>
60 #include <sys/types.h>
61 #include <unistd.h>
62 #endif
63
64 #include <vroot/vroot.h>
65 #include <mksh/defs.h> /* for libintl */
66
67 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
68 #include <schily/signal.h>
69 #include <schily/errno.h> /* errno */
70 #else
71 #include <signal.h>
72 #include <errno.h> /* errno */
73 #endif
74
75 #if !defined(HAVE_STRERROR)
76 extern char *sys_errlist[];
77 extern int sys_nerr;
78 #endif
79
80 static void file_lock_error(char *msg, char *file, const char *str, const char *arg1, const char *arg2);
81
82 #define BLOCK_INTERUPTS sigfillset(&newset) ; \
83 sigprocmask(SIG_SETMASK, &newset, &oldset)
84
85 #define UNBLOCK_INTERUPTS \
86 sigprocmask(SIG_SETMASK, &oldset, &newset)
87
88 /*
89 * This code stolen from the NSE library and changed to not depend
90 * upon any NSE routines or header files.
91 *
92 * Simple file locking.
93 * Create a symlink to a file. The "test and set" will be
94 * atomic as creating the symlink provides both functions.
95 *
96 * The timeout value specifies how long to wait for stale locks
97 * to disappear. If the lock is more than 'timeout' seconds old
98 * then it is ok to blow it away. This part has a small window
99 * of vunerability as the operations of testing the time,
100 * removing the lock and creating a new one are not atomic.
101 * It would be possible for two processes to both decide to blow
102 * away the lock and then have process A remove the lock and establish
103 * its own, and then then have process B remove the lock which accidentily
104 * removes A's lock rather than the stale one.
105 *
106 * A further complication is with the NFS. If the file in question is
107 * being served by an NFS server, then its time is set by that server.
108 * We can not use the time on the client machine to check for a stale
109 * lock. Therefore, a temp file on the server is created to get
110 * the servers current time.
111 *
112 * Returns an error message. NULL return means the lock was obtained.
113 *
114 * 12/6/91 Added the parameter "file_locked". Before this parameter
115 * was added, the calling procedure would have to wait for file_lock()
116 * to return before it sets the flag. If the user interrupted "make"
117 * between the time the lock was acquired and the time file_lock()
118 * returns, make wouldn't know that the file has been locked, and therefore
119 * it wouldn' remove the lock. Setting the flag right after locking the file
120 * makes this window much smaller.
121 */
122
123 int
124 file_lock(char *name, char *lockname, int *file_locked, int timeout)
125 {
126 int counter = 0;
127 static char msg[MAXPATHLEN+1];
128 int printed_warning = 0;
129 int r;
130 struct stat statb;
131 sigset_t newset;
132 sigset_t oldset;
133
134 *file_locked = 0;
135 if (timeout <= 0) {
136 timeout = 120;
137 }
138 for (;;) {
139 BLOCK_INTERUPTS;
140 r = symlink(name, lockname);
141 if (r == 0) {
142 *file_locked = 1;
143 UNBLOCK_INTERUPTS;
144 return 0; /* success */
145 }
146 UNBLOCK_INTERUPTS;
147
148 if (errno != EEXIST) {
149 file_lock_error(msg, name, NOCATGETS("symlink(%s, %s)"),
150 name, lockname);
151 fprintf(stderr, "%s", msg);
152 return errno;
153 }
154
155 counter = 0;
156 for (;;) {
157 sleep(1);
158 r = lstat(lockname, &statb);
159 if (r == -1) {
160 /*
161 * The lock must have just gone away - try
162 * again.
163 */
164 break;
165 }
166
167 if ((counter > 5) && (!printed_warning)) {
168 /* Print waiting message after 5 secs */
169 if (getcwd(msg, MAXPATHLEN) == NULL)
170 msg[0] = nul_char;
171 fprintf(stderr,
172 gettext("file_lock: file %s is already locked.\n"),
173 name);
174 fprintf(stderr,
175 gettext("file_lock: will periodically check the lockfile %s for two minutes.\n"),
176 lockname);
177 fprintf(stderr,
178 gettext("Current working directory %s\n"),
179 msg);
180
181 printed_warning = 1;
182 }
183
184 if (++counter > timeout ) {
185 /*
186 * Waited enough - return an error..
187 */
188 return EEXIST;
189 }
190 }
191 }
192 /* NOTREACHED */
193 }
194
195 /*
196 * Format a message telling why the lock could not be created.
197 */
198 static void
199 file_lock_error(char *msg, char *file, const char *str, const char *arg1, const char *arg2)
200 {
201 int len;
202
203 sprintf(msg, gettext("Could not lock file `%s'; "), file);
204 len = strlen(msg);
205 sprintf(&msg[len], str, arg1, arg2);
206 strcat(msg, gettext(" failed - "));
207 #ifdef HAVE_STRERROR
208 char *emsg;
209
210 emsg = strerror(errno);
211 if (emsg) {
212 strcat(msg, strerror(errno));
213 } else {
214 len = strlen(msg);
215 sprintf(&msg[len], NOCATGETS("errno %d"), errno);
216 }
217 #else
218 if (errno < sys_nerr) {
219 strcat(msg, sys_errlist[errno]);
220 } else {
221 len = strlen(msg);
222 sprintf(&msg[len], NOCATGETS("errno %d"), errno);
223 }
224 #endif
225 }