1 /* 2 * Copyright (c) 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Joerg Sonnenberger <joerg@bec.de>. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/usr.bin/shlock/shlock.c,v 1.1 2005/07/23 19:47:15 joerg Exp $ 35 */ 36 37 #include <sys/types.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <libgen.h> 42 #include <limits.h> 43 #include <signal.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #define BUFSIZE 16 50 51 static int create_lock(const char *, pid_t, int, int); 52 static int check_lock(const char *, int, int); 53 static void usage(void); 54 55 int 56 main(int argc, char **argv) 57 { 58 int ch, debug = 0, uucpstyle = 0; 59 const char *file = NULL; 60 char *endptr; 61 pid_t pid = -1; 62 long tmp_pid; 63 64 while ((ch = getopt(argc, argv, "df:p:u")) != -1) { 65 switch (ch) { 66 case 'd': 67 debug = 1; 68 break; 69 case 'f': 70 file = optarg; 71 break; 72 case 'p': 73 errno = 0; 74 tmp_pid = strtol(optarg, &endptr, 10); 75 if (*endptr != '\0' || errno || 76 tmp_pid < 1 || (pid = tmp_pid) != tmp_pid) 77 errx(1, "invalid pid specified"); 78 break; 79 case 'u': 80 uucpstyle = 1; 81 break; 82 default: 83 usage(); 84 } 85 } 86 argc -= optind; 87 argv += optind; 88 89 if (argc != 0) 90 usage(); 91 92 if (file == NULL) 93 usage(); 94 95 if (pid != -1) 96 return(create_lock(file, pid, uucpstyle, debug)); 97 else 98 return(check_lock(file, uucpstyle, debug)); 99 } 100 101 static int 102 create_lock(const char *file, pid_t pid, int uucpstyle, int debug) 103 { 104 char buf[BUFSIZE], tmpf[PATH_MAX]; 105 char *tmpbuf; 106 char *dir; 107 int fd, ret; 108 109 ret = snprintf(buf, sizeof(buf), "%ld\n", (long)pid); 110 if (ret >= (int)sizeof(buf) || ret == -1) 111 err(1, "snprintf() failed"); /* Must not happen. */ 112 113 tmpbuf = strdup(file); 114 if ((dir = dirname(tmpbuf)) == NULL) 115 err(1, "dirname() failed"); 116 117 ret = snprintf(tmpf, sizeof(tmpf), "%s/shlock%ld", dir, (long)getpid()); 118 if (ret >= (int)sizeof(tmpf) || ret == -1) 119 err(1, "snprintf failed"); 120 free(tmpbuf); 121 122 if (debug) { 123 printf("%s: trying lock file %s for process %ld\n", 124 getprogname(), file, (long)pid); 125 } 126 127 while ((fd = open(tmpf, O_RDWR | O_CREAT | O_EXCL, 0644)) == -1){ 128 if (errno != EEXIST) 129 err(1, "could not create tempory lock file"); 130 if (debug) 131 warnx("temporary lock file %s existed already", tmpf); 132 if (unlink(tmpf) && errno != ENOENT) { 133 err(1, "could not remove old temporary lock file %s", 134 tmpf); 135 } 136 /* Try again. */ 137 } 138 139 if ((uucpstyle && write(fd, &pid, sizeof(pid)) != sizeof(pid)) || 140 (!uucpstyle && write(fd, buf, strlen(buf)) != (int)strlen(buf))) { 141 warn("could not write PID to temporary lock file"); 142 close(fd); 143 144 if (unlink(tmpf)) 145 err(1, "could not remove temporary lock file %s", tmpf); 146 147 return(1); 148 } 149 150 close(fd); 151 152 while (link(tmpf, file)) { 153 if (errno != EEXIST) { 154 if (unlink(tmpf)) { 155 err(1, 156 "could not remove temporary lock file %s", 157 tmpf); 158 } 159 err(1, "could not create lock file"); 160 } 161 if (check_lock(file, uucpstyle, debug) == 0) { 162 if (unlink(tmpf)) { 163 err(1, 164 "could not remove temporary lock file %s", 165 tmpf); 166 } 167 return(1); /* Lock file is valid. */ 168 } 169 if (unlink(file) == 0) { 170 printf("%s: stale lock file removed\n", getprogname()); 171 continue; 172 } 173 if (unlink(tmpf)) { 174 err(1, "could not remove temporary lock file %s", 175 tmpf); 176 } 177 err(1, "could not remove stale lock file"); 178 } 179 180 if (debug) 181 printf("%s: lock successfully obtained\n", getprogname()); 182 183 if (unlink(tmpf)) 184 warn("could not remove temporary lock file %s", tmpf); 185 186 return(0); 187 } 188 189 static int 190 check_lock(const char *file, int uucpstyle, int debug) 191 { 192 char buf[BUFSIZE]; 193 int fd; 194 ssize_t len; 195 pid_t pid; 196 197 if ((fd = open(file, O_RDONLY)) == -1) { 198 switch (errno) { 199 case ENOENT: 200 return(1); /* File doesn't exist. */ 201 default: 202 /* 203 * Something went wrong, bail out as 204 * if the lock existed. 205 */ 206 err(1, "could not open lock file"); 207 } 208 } 209 210 len = read(fd, buf, uucpstyle ? sizeof(pid_t) : sizeof(buf)); 211 close(fd); 212 213 if (len < 0) { 214 if (debug) 215 warn("could not read lock file"); 216 return(1); 217 } 218 if (len == 0) { 219 if (debug) 220 warnx("found empty lock file"); 221 return(1); 222 } 223 if (uucpstyle) { 224 if (len != sizeof(pid_t)) { 225 if (debug) 226 warnx("invalid lock file format"); 227 return(1); 228 } 229 memcpy(&pid, buf, sizeof(pid_t)); 230 } else { 231 char *endptr; 232 long tmp_pid; 233 234 if (len == BUFSIZE) { 235 if (debug) 236 warnx("invalid lock file format"); 237 return(1); 238 } 239 240 buf[BUFSIZE - 1] = '\0'; 241 errno = 0; 242 tmp_pid = strtol(buf, &endptr, 10); 243 if ((*endptr != '\0' && *endptr != '\n') || errno || 244 tmp_pid < 1 || (pid = tmp_pid) != tmp_pid) { 245 if (debug) 246 warnx("invalid lock file format"); 247 return(1); 248 } 249 } 250 251 if (kill(pid, 0) == 0) 252 return(0); /* Process is alive. */ 253 254 switch (errno) { 255 case ESRCH: 256 return(1); /* Process is dead. */ 257 case EPERM: 258 return(0); /* Process is alive. */ 259 default: 260 return(0); /* Something else, assume alive. */ 261 } 262 } 263 264 static void 265 usage(void) 266 { 267 fprintf(stderr, "%s [-u] [-d] [-p pid] -f file\n", getprogname()); 268 exit(1); 269 } 270