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 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 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 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 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 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 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 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