"Fossies" - the Fresh Open Source Software Archive 
Member "schily-2021-09-18/sunpro/Make/lib/makestate/src/lock.c" (14 Aug 2021, 5919 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.c 1.5 06/12/12
29 */
30
31 /*
32 * Copyright 2017-2021 J. Schilling
33 *
34 * @(#)lock.c 1.11 21/08/15 2017-2021 J. Schilling
35 */
36 #include <schily/mconfig.h>
37 #ifndef lint
38 static UConst char sccsid[] =
39 "@(#)lock.c 1.11 21/08/15 2017-2021 J. Schilling";
40 #endif
41
42 #if defined(SCHILY_BUILD) || defined(SCHILY_INCLUDES)
43 #include <schily/stdio.h>
44 #include <schily/stdlib.h>
45 #include <schily/unistd.h>
46 #include <schily/string.h>
47 #include <schily/fcntl.h>
48 #include <schily/types.h>
49 #include <schily/param.h>
50 #include <schily/stat.h>
51 #include <schily/maxpath.h>
52 #include <schily/errno.h> /* errno */
53 #else
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <fcntl.h>
59 #include <sys/types.h>
60 #include <sys/param.h>
61 #include <sys/stat.h>
62 #include <errno.h> /* errno */
63 #endif
64
65 #ifdef HAVE_STRERROR
66 /*
67 * The symbols _sys_errlist and _sys_nerr are not visible in the
68 * LP64 libc. Use strerror(3C) instead.
69 */
70 #else /* #_LP64 */
71 extern char *sys_errlist[];
72 extern int sys_nerr;
73 #endif /* #_LP64 */
74
75 char *file_lock __PR((char *name, char *lockname,
76 int timeout));
77 static void file_lock_error __PR((char *msg, char *file,
78 const char *str,
79 char *arg1, char *arg2));
80
81 /*
82 * This code stolen from the NSE library and changed to not depend
83 * upon any NSE routines or header files.
84 *
85 * Simple file locking.
86 * Create a symlink to a file. The "test and set" will be
87 * atomic as creating the symlink provides both functions.
88 *
89 * The timeout value specifies how long to wait for stale locks
90 * to disappear. If the lock is more than 'timeout' seconds old
91 * then it is ok to blow it away. This part has a small window
92 * of vunerability as the operations of testing the time,
93 * removing the lock and creating a new one are not atomic.
94 * It would be possible for two processes to both decide to blow
95 * away the lock and then have process A remove the lock and establish
96 * its own, and then then have process B remove the lock which accidentily
97 * removes A's lock rather than the stale one.
98 *
99 * A further complication is with the NFS. If the file in question is
100 * being served by an NFS server, then its time is set by that server.
101 * We can not use the time on the client machine to check for a stale
102 * lock. Therefore, a temp file on the server is created to get
103 * the servers current time.
104 *
105 * Returns an error message. NULL return means the lock was obtained.
106 *
107 */
108 char *
109 file_lock(name, lockname, timeout)
110 char *name;
111 char *lockname;
112 int timeout;
113 {
114 int r;
115 int fd;
116 struct stat statb;
117 struct stat fs_statb;
118 char tmpname[MAXPATHLEN];
119 static char msg[MAXPATHLEN];
120
121 if (timeout <= 0) {
122 timeout = 15;
123 }
124 for (;;) {
125 r = symlink(name, lockname);
126 if (r == 0) {
127 return (NULL);
128 }
129 if (errno != EEXIST) {
130 file_lock_error(msg, name,
131 (const char *)"symlink(%s, %s)", name, lockname);
132 return (msg);
133 }
134 for (;;) {
135 (void) sleep(1);
136 r = lstat(lockname, &statb);
137 if (r == -1) {
138 /*
139 * The lock must have just gone away - try
140 * again.
141 */
142 break;
143 }
144
145 /*
146 * With the NFS the time given a file is the time on
147 * the file server. This time may vary from the
148 * client's time. Therefore, we create a tmpfile in
149 * the same directory to establish the time on the
150 * server and use this time to see if the lock has
151 * expired.
152 */
153 (void) sprintf(tmpname, "%s.XXXXXX", lockname);
154 #ifdef HAVE_MKSTEMP
155 fd = mkstemp(tmpname);
156 #else
157 (void) mktemp(tmpname);
158 fd = creat(tmpname, 0666);
159 #endif
160 if (fd != -1) {
161 (void) close(fd);
162 } else {
163 file_lock_error(msg, name,
164 (const char *)"creat(%s)", tmpname, 0);
165 return (msg);
166 }
167 if (stat(tmpname, &fs_statb) == -1) {
168 file_lock_error(msg, name,
169 (const char *)"stat(%s)", tmpname, 0);
170 return (msg);
171 }
172 (void) unlink(tmpname);
173 if (statb.st_mtime + timeout < fs_statb.st_mtime) {
174 /*
175 * The lock has expired - blow it away.
176 */
177 (void) unlink(lockname);
178 break;
179 }
180 }
181 }
182 /* NOTREACHED */
183 }
184
185 /*
186 * Format a message telling why the lock could not be created.
187 */
188 /* VARARGS4 */
189 static void
190 file_lock_error(msg, file, str, arg1, arg2)
191 char *msg;
192 char *file;
193 const char *str;
194 char *arg1;
195 char *arg2;
196 {
197 int len;
198 #ifdef HAVE_STRERROR
199 char *emsg;
200 #endif
201
202 (void) sprintf(msg, "Could not lock file `%s'; ", file);
203 len = strlen(msg);
204 (void) sprintf(&msg[len], str, arg1, arg2);
205 (void) strcat(msg, " failed - ");
206 #ifdef HAVE_STRERROR
207 /* Needs to be changed to use strerror(3C) instead. */
208 emsg = strerror(errno);
209 if (emsg) {
210 (void) strcat(msg, emsg);
211 } else {
212 len = strlen(msg);
213 (void) sprintf(&msg[len], "errno %d", errno);
214 }
215 #else /* #_LP64 */
216 if (errno < sys_nerr) {
217 (void) strcat(msg, sys_errlist[errno]);
218 } else {
219 len = strlen(msg);
220 (void) sprintf(&msg[len], "errno %d", errno);
221 }
222 #endif /* #_LP64 */
223 }