1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
10 */
11
12 /*
13 * defs that come from uucp.h
14 */
15 #define NAMESIZE 40
16 #define FAIL -1
17 #define SAME 0
18 #define SLCKTIME (8*60*60) /* device timeout (LCK.. files) in seconds */
19 #ifdef __STDC__
20 #define ASSERT(e, f, v) if (!(e)) {\
21 (void) fprintf(stderr, "AERROR - (%s) ", #e); \
22 (void) fprintf(stderr, f, v); \
23 finish(FAIL); \
24 }
25 #else
26 #define ASSERT(e, f, v) if (!(e)) {\
27 (void) fprintf(stderr, "AERROR - (%s) ", "e"); \
28 (void) fprintf(stderr, f, v); \
29 finish(FAIL); \
30 }
31 #endif
32 #define SIZEOFPID 10 /* maximum number of digits in a pid */
33
34 #define LOCKDIR "/var/spool/locks"
35 #define LOCKPRE "LK"
36
37 /*
38 * This code is taken almost directly from uucp and follows the same
39 * conventions. This is important since uucp and tip should
40 * respect each others locks.
41 */
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/mkdev.h>
46 #include <stdio.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <signal.h>
54 #include <utime.h>
55
56 static void stlock(char *);
57 static int onelock(char *, char *, char *);
58 static int checkLock(char *);
59
60 extern void finish(int);
61
62 /*
63 * ulockf(file, atime)
64 * char *file;
65 * time_t atime;
66 *
67 * ulockf - this routine will create a lock file (file).
68 * If one already exists, send a signal 0 to the process--if
69 * it fails, then unlink it and make a new one.
70 *
71 * input:
72 * file - name of the lock file
73 * atime - is unused, but we keep it for lint compatibility
74 * with non-ATTSVKILL
75 *
76 * return codes: 0 | FAIL
77 */
78 /* ARGSUSED */
79 static int
ulockf(char * file,time_t atime)80 ulockf(char *file, time_t atime)
81 {
82 static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */
83 static char tempfile[NAMESIZE];
84
85 if (pid[0] == '\0') {
86 (void) snprintf(pid, sizeof (pid), "%*d\n", SIZEOFPID,
87 (int)getpid());
88 (void) snprintf(tempfile, sizeof (tempfile),
89 "%s/LTMP.%d", LOCKDIR, getpid());
90 }
91 if (onelock(pid, tempfile, file) == -1) {
92 /* lock file exists */
93 (void) unlink(tempfile);
94 if (checkLock(file))
95 return (FAIL);
96 else {
97 if (onelock(pid, tempfile, file)) {
98 (void) unlink(tempfile);
99 return (FAIL);
100 }
101 }
102 }
103 stlock(file);
104 return (0);
105 }
106
107 /*
108 * check to see if the lock file exists and is still active
109 * - use kill(pid, 0) - (this only works on ATTSV and some hacked
110 * BSD systems at this time)
111 * return:
112 * 0 -> success (lock file removed - no longer active)
113 * FAIL -> lock file still active
114 */
115 static int
checkLock(char * file)116 checkLock(char *file)
117 {
118 int ret;
119 int lpid = -1;
120 char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */
121 int fd;
122
123 fd = open(file, 0);
124 if (fd == -1) {
125 if (errno == ENOENT) /* file does not exist -- OK */
126 return (0);
127 goto unlk;
128 }
129 ret = read(fd, (char *)alpid, SIZEOFPID+1); /* +1 for '\n' */
130 (void) close(fd);
131 if (ret != (SIZEOFPID+1))
132 goto unlk;
133 lpid = atoi(alpid);
134 if ((ret = kill(lpid, 0)) == 0 || errno == EPERM)
135 return (FAIL);
136
137 unlk:
138 if (unlink(file) != 0)
139 return (FAIL);
140 return (0);
141 }
142
143 #define MAXLOCKS 10 /* maximum number of lock files */
144 char *Lockfile[MAXLOCKS];
145 int Nlocks = 0;
146
147 /*
148 * stlock(name) put name in list of lock files
149 * char *name;
150 *
151 * return codes: none
152 */
153
154 static void
stlock(char * name)155 stlock(char *name)
156 {
157 char *p;
158 int i;
159
160 for (i = 0; i < Nlocks; i++) {
161 if (Lockfile[i] == NULL)
162 break;
163 }
164 ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
165 if (i >= Nlocks)
166 i = Nlocks++;
167 p = calloc(strlen(name) + 1, sizeof (char));
168 ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
169 (void) strcpy(p, name);
170 Lockfile[i] = p;
171 }
172
173 /*
174 * rmlock(name) remove all lock files in list
175 * char *name; or name
176 *
177 * return codes: none
178 */
179
180 static void
rmlock(char * name)181 rmlock(char *name)
182 {
183 int i;
184
185 for (i = 0; i < Nlocks; i++) {
186 if (Lockfile[i] == NULL)
187 continue;
188 if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
189 (void) unlink(Lockfile[i]);
190 free(Lockfile[i]);
191 Lockfile[i] = NULL;
192 }
193 }
194 }
195
196 static int
onelock(char * pid,char * tempfile,char * name)197 onelock(char *pid, char *tempfile, char *name)
198 {
199 int fd;
200 static int first = 1;
201
202 fd = creat(tempfile, 0444);
203 if (fd < 0) {
204 if (first) {
205 if (errno == EACCES) {
206 (void) fprintf(stderr,
207 "tip: can't create files in lock file directory %s\n",
208 LOCKDIR);
209 } else if (access(LOCKDIR, 0) < 0) {
210 (void) fprintf(stderr,
211 "tip: lock file directory %s: ",
212 LOCKDIR);
213 perror("");
214 }
215 first = 0;
216 }
217 if (errno == EMFILE || errno == ENFILE)
218 (void) unlink(tempfile);
219 return (-1);
220 }
221 /* +1 for '\n' */
222 if (write(fd, pid, SIZEOFPID+1) != (SIZEOFPID+1)) {
223 (void) fprintf(stderr,
224 "tip: can't write to files in lock file directory %s: %s\n",
225 LOCKDIR, strerror(errno));
226 (void) unlink(tempfile);
227 return (-1);
228 }
229 (void) fchmod(fd, 0444);
230 (void) close(fd);
231 if (link(tempfile, name) < 0) {
232 (void) unlink(tempfile);
233 return (-1);
234 }
235 (void) unlink(tempfile);
236 return (0);
237 }
238
239 /*
240 * delock(sys) remove a lock file
241 * char *sys;
242 */
243
244 void
delock(char * sys)245 delock(char *sys)
246 {
247 struct stat sb;
248 char lname[NAMESIZE];
249
250 if (stat(sys, &sb) < 0)
251 return;
252 (void) snprintf(lname, sizeof (lname), "%s/%s.%3.3lu.%3.3lu.%3.3lu",
253 LOCKDIR, LOCKPRE,
254 (unsigned long)major(sb.st_dev),
255 (unsigned long)major(sb.st_rdev),
256 (unsigned long)minor(sb.st_rdev));
257 rmlock(lname);
258 }
259
260 /*
261 * tip_mlock(sys) create system lock
262 * char *sys;
263 *
264 * return codes: 0 | FAIL
265 */
266
267 int
tip_mlock(char * sys)268 tip_mlock(char *sys)
269 {
270 struct stat sb;
271 char lname[NAMESIZE];
272
273 if (stat(sys, &sb) < 0)
274 return (FAIL);
275 (void) snprintf(lname, sizeof (lname), "%s/%s.%3.3lu.%3.3lu.%3.3lu",
276 LOCKDIR, LOCKPRE,
277 (unsigned long)major(sb.st_dev),
278 (unsigned long)major(sb.st_rdev),
279 (unsigned long)minor(sb.st_rdev));
280 return (ulockf(lname, (time_t)SLCKTIME) < 0 ? FAIL : 0);
281 }
282