1 /* $NetBSD: pidlock.c,v 1.3 1997/10/19 18:10:58 mycroft Exp $ */ 2 3 /* 4 * Copyright 1996, 1997 by Curt Sampson <cjs@netbsd.org>. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 16 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 * SUCH DAMAGE. 23 */ 24 25 #include <sys/cdefs.h> 26 #if defined(LIBC_SCCS) && !defined(lint) 27 __RCSID("$NetBSD: pidlock.c,v 1.3 1997/10/19 18:10:58 mycroft Exp $"); 28 #endif /* LIBC_SCCS and not lint */ 29 30 #include <sys/errno.h> 31 #include <sys/param.h> 32 #include <sys/stat.h> 33 #include <sys/types.h> 34 35 #include <fcntl.h> 36 #include <signal.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <util.h> 42 43 /* 44 * Create a lockfile. Return 0 when locked, -1 on error. 45 */ 46 int 47 pidlock(lockfile, flags, locker, info) 48 const char *lockfile; 49 int flags; 50 pid_t *locker; 51 const char *info; 52 { 53 char tempfile[MAXPATHLEN]; 54 char hostname[256]; 55 pid_t pid2 = -1; 56 struct stat st; 57 int err; 58 int f; 59 char s[256]; 60 char *p; 61 62 if (gethostname(hostname, sizeof(hostname))) 63 return -1; 64 65 /* 66 * Build a path to the temporary file. 67 * We use the path with the PID and hostname appended. 68 * XXX This is not thread safe. 69 */ 70 if (snprintf(tempfile, sizeof(tempfile), "%s.%d.%s", lockfile, 71 (int) getpid(), hostname) >= sizeof(tempfile)) { 72 errno = ENAMETOOLONG; 73 return -1; 74 } 75 76 /* Open it, write pid, hostname, info. */ 77 if ( (f = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1 ) { 78 err = errno; 79 unlink(tempfile); 80 errno = err; 81 return -1; 82 } 83 snprintf(s, sizeof(s), "%10d\n", getpid()); /* pid */ 84 if (write(f, s, 11) != 11) { 85 err = errno; 86 close(f); 87 unlink(tempfile); 88 errno = err; 89 return -1; 90 } 91 if ((flags & PIDLOCK_USEHOSTNAME)) { /* hostname */ 92 if ((write(f, hostname, strlen(hostname)) != strlen(hostname)) 93 || (write(f, "\n", 1) != 1)) { 94 err = errno; 95 close(f); 96 unlink(tempfile); 97 errno = err; 98 return -1; 99 } 100 } 101 if (info) { /* info */ 102 if (!(flags & PIDLOCK_USEHOSTNAME)) { 103 /* write blank line because there's no hostname */ 104 if (write(f, "\n", 1) != 1) { 105 err = errno; 106 close(f); 107 unlink(tempfile); 108 errno = err; 109 return -1; 110 } 111 } 112 if (write(f, info, strlen(info)) != strlen(info) || 113 (write(f, "\n", 1) != 1)) { 114 err = errno; 115 close(f); 116 unlink(tempfile); 117 errno = err; 118 return -1; 119 } 120 } 121 close(f); 122 123 /* Hard link the temporary file to the real lock file. */ 124 /* This is an atomic operation. */ 125 lockfailed: 126 while (link(tempfile, lockfile) != 0) { 127 if (errno != EEXIST) { 128 err = errno; 129 unlink(tempfile); 130 errno = err; 131 return -1; 132 } 133 /* Find out who has this lockfile. */ 134 if ((f = open(lockfile, O_RDONLY, 0)) != 0) { 135 read(f, s, 11); 136 pid2 = atoi(s); 137 read(f, s, sizeof(s)-2); 138 s[sizeof(s)-1] = '\0'; 139 if ((p=strchr(s, '\n'))) 140 *p = '\0'; 141 close(f); 142 143 if (!((flags & PIDLOCK_USEHOSTNAME) && 144 strcmp(s, hostname))) { 145 if ((kill(pid2, 0) != 0) && (errno == ESRCH)) { 146 /* process doesn't exist */ 147 unlink(lockfile); 148 continue; 149 } 150 } 151 } 152 if (flags & PIDLOCK_NONBLOCK) { 153 if (locker) 154 *locker = pid2; 155 unlink(tempfile); 156 errno = EWOULDBLOCK; 157 return -1; 158 } else 159 sleep(5); 160 } 161 /* 162 * Check to see that we really were successful (in case we're 163 * using NFS) by making sure that something really is linked 164 * to our tempfile (reference count is two). 165 */ 166 if (stat(tempfile, &st) != 0) { 167 err = errno; 168 /* 169 * We don't know if lockfile was really created by us, 170 * so we can't remove it. 171 */ 172 unlink(tempfile); 173 errno = err; 174 return -1; 175 } 176 if (st.st_nlink != 2) 177 goto lockfailed; 178 179 unlink(tempfile); 180 if (locker) 181 *locker = getpid(); /* return this process's PID on lock */ 182 errno = 0; 183 return 0; 184 } 185 186 #define LOCKPATH "/var/spool/lock/LCK.." 187 #define DEVPATH "/dev/" 188 189 int 190 ttylock(tty, flags, locker) 191 const char *tty; 192 int flags; 193 pid_t *locker; 194 { 195 char lockfile[MAXPATHLEN]; 196 char ttyfile[MAXPATHLEN]; 197 struct stat sb; 198 199 /* make sure the tty exists */ 200 strcpy(ttyfile, DEVPATH); 201 strncat(ttyfile, tty, MAXPATHLEN-strlen(DEVPATH)); 202 if (stat(ttyfile, &sb)) { 203 errno = ENOENT; return -1; 204 } 205 if (!S_ISCHR(sb.st_mode)) { 206 errno = ENOENT; return -1; 207 } 208 209 /* do the lock */ 210 strcpy(lockfile, LOCKPATH); 211 strncat(lockfile, tty, MAXPATHLEN-strlen(LOCKPATH)); 212 return pidlock(lockfile, 0, 0, 0); 213 } 214 215 int 216 ttyunlock(tty) 217 const char *tty; 218 { 219 char lockfile[MAXPATHLEN]; 220 char ttyfile[MAXPATHLEN]; 221 struct stat sb; 222 223 /* make sure the tty exists */ 224 strcpy(ttyfile, DEVPATH); 225 strncat(ttyfile, tty, MAXPATHLEN-strlen(DEVPATH)); 226 if (stat(ttyfile, &sb)) { 227 errno = ENOENT; return -1; 228 } 229 if (!S_ISCHR(sb.st_mode)) { 230 errno = ENOENT; return -1; 231 } 232 233 /* undo the lock */ 234 strcpy(lockfile, LOCKPATH); 235 strncat(lockfile, tty, MAXPATHLEN-strlen(LOCKPATH)); 236 return unlink(lockfile); 237 } 238