1 /* $NetBSD: pidlock.c,v 1.4 1998/07/06 06:47:24 mrg 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.4 1998/07/06 06:47:24 mrg 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[MAXHOSTNAMELEN + 1]; 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 hostname[sizeof(hostname) - 1] = '\0'; 65 66 /* 67 * Build a path to the temporary file. 68 * We use the path with the PID and hostname appended. 69 * XXX This is not thread safe. 70 */ 71 if (snprintf(tempfile, sizeof(tempfile), "%s.%d.%s", lockfile, 72 (int) getpid(), hostname) >= sizeof(tempfile)) { 73 errno = ENAMETOOLONG; 74 return -1; 75 } 76 77 /* Open it, write pid, hostname, info. */ 78 if ( (f = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1 ) { 79 err = errno; 80 unlink(tempfile); 81 errno = err; 82 return -1; 83 } 84 snprintf(s, sizeof(s), "%10d\n", getpid()); /* pid */ 85 if (write(f, s, 11) != 11) { 86 err = errno; 87 close(f); 88 unlink(tempfile); 89 errno = err; 90 return -1; 91 } 92 if ((flags & PIDLOCK_USEHOSTNAME)) { /* hostname */ 93 if ((write(f, hostname, strlen(hostname)) != strlen(hostname)) 94 || (write(f, "\n", 1) != 1)) { 95 err = errno; 96 close(f); 97 unlink(tempfile); 98 errno = err; 99 return -1; 100 } 101 } 102 if (info) { /* info */ 103 if (!(flags & PIDLOCK_USEHOSTNAME)) { 104 /* write blank line because there's no hostname */ 105 if (write(f, "\n", 1) != 1) { 106 err = errno; 107 close(f); 108 unlink(tempfile); 109 errno = err; 110 return -1; 111 } 112 } 113 if (write(f, info, strlen(info)) != strlen(info) || 114 (write(f, "\n", 1) != 1)) { 115 err = errno; 116 close(f); 117 unlink(tempfile); 118 errno = err; 119 return -1; 120 } 121 } 122 close(f); 123 124 /* Hard link the temporary file to the real lock file. */ 125 /* This is an atomic operation. */ 126 lockfailed: 127 while (link(tempfile, lockfile) != 0) { 128 if (errno != EEXIST) { 129 err = errno; 130 unlink(tempfile); 131 errno = err; 132 return -1; 133 } 134 /* Find out who has this lockfile. */ 135 if ((f = open(lockfile, O_RDONLY, 0)) != 0) { 136 read(f, s, 11); 137 pid2 = atoi(s); 138 read(f, s, sizeof(s)-2); 139 s[sizeof(s)-1] = '\0'; 140 if ((p=strchr(s, '\n'))) 141 *p = '\0'; 142 close(f); 143 144 if (!((flags & PIDLOCK_USEHOSTNAME) && 145 strcmp(s, hostname))) { 146 if ((kill(pid2, 0) != 0) && (errno == ESRCH)) { 147 /* process doesn't exist */ 148 unlink(lockfile); 149 continue; 150 } 151 } 152 } 153 if (flags & PIDLOCK_NONBLOCK) { 154 if (locker) 155 *locker = pid2; 156 unlink(tempfile); 157 errno = EWOULDBLOCK; 158 return -1; 159 } else 160 sleep(5); 161 } 162 /* 163 * Check to see that we really were successful (in case we're 164 * using NFS) by making sure that something really is linked 165 * to our tempfile (reference count is two). 166 */ 167 if (stat(tempfile, &st) != 0) { 168 err = errno; 169 /* 170 * We don't know if lockfile was really created by us, 171 * so we can't remove it. 172 */ 173 unlink(tempfile); 174 errno = err; 175 return -1; 176 } 177 if (st.st_nlink != 2) 178 goto lockfailed; 179 180 unlink(tempfile); 181 if (locker) 182 *locker = getpid(); /* return this process's PID on lock */ 183 errno = 0; 184 return 0; 185 } 186 187 #define LOCKPATH "/var/spool/lock/LCK.." 188 #define DEVPATH "/dev/" 189 190 int 191 ttylock(tty, flags, locker) 192 const char *tty; 193 int flags; 194 pid_t *locker; 195 { 196 char lockfile[MAXPATHLEN]; 197 char ttyfile[MAXPATHLEN]; 198 struct stat sb; 199 200 /* make sure the tty exists */ 201 strcpy(ttyfile, DEVPATH); 202 strncat(ttyfile, tty, MAXPATHLEN-strlen(DEVPATH)); 203 if (stat(ttyfile, &sb)) { 204 errno = ENOENT; return -1; 205 } 206 if (!S_ISCHR(sb.st_mode)) { 207 errno = ENOENT; return -1; 208 } 209 210 /* do the lock */ 211 strcpy(lockfile, LOCKPATH); 212 strncat(lockfile, tty, MAXPATHLEN-strlen(LOCKPATH)); 213 return pidlock(lockfile, 0, 0, 0); 214 } 215 216 int 217 ttyunlock(tty) 218 const char *tty; 219 { 220 char lockfile[MAXPATHLEN]; 221 char ttyfile[MAXPATHLEN]; 222 struct stat sb; 223 224 /* make sure the tty exists */ 225 strcpy(ttyfile, DEVPATH); 226 strncat(ttyfile, tty, MAXPATHLEN-strlen(DEVPATH)); 227 if (stat(ttyfile, &sb)) { 228 errno = ENOENT; return -1; 229 } 230 if (!S_ISCHR(sb.st_mode)) { 231 errno = ENOENT; return -1; 232 } 233 234 /* undo the lock */ 235 strcpy(lockfile, LOCKPATH); 236 strncat(lockfile, tty, MAXPATHLEN-strlen(LOCKPATH)); 237 return unlink(lockfile); 238 } 239