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 *dir; 106 int fd, ret; 107 108 ret = snprintf(buf, sizeof(buf), "%ld\n", (long)pid); 109 if (ret >= (int)sizeof(buf) || ret == -1) 110 err(1, "snprintf() failed"); /* Must not happen. */ 111 112 if ((dir = dirname(file)) == NULL) 113 err(1, "dirname() failed"); 114 115 ret = snprintf(tmpf, sizeof(tmpf), "%s/shlock%ld", dir, (long)getpid()); 116 if (ret >= (int)sizeof(tmpf) || ret == -1) 117 err(1, "snprintf failed"); 118 119 if (debug) { 120 printf("%s: trying lock file %s for process %ld\n", 121 getprogname(), file, (long)pid); 122 } 123 124 while ((fd = open(tmpf, O_RDWR | O_CREAT | O_EXCL, 0644)) == -1){ 125 if (errno != EEXIST) 126 err(1, "could not create tempory lock file"); 127 if (debug) 128 warnx("temporary lock file %s existed already", tmpf); 129 if (unlink(tmpf) && errno != ENOENT) { 130 err(1, "could not remove old temporary lock file %s", 131 tmpf); 132 } 133 /* Try again. */ 134 } 135 136 if ((uucpstyle && write(fd, &pid, sizeof(pid)) != sizeof(pid)) || 137 (!uucpstyle && write(fd, buf, strlen(buf)) != (int)strlen(buf))) { 138 warn("could not write PID to temporary lock file"); 139 close(fd); 140 141 if (unlink(tmpf)) 142 err(1, "could not remove temporary lock file %s", tmpf); 143 144 free(tmpf); 145 return(1); 146 } 147 148 close(fd); 149 150 while (link(tmpf, file)) { 151 if (errno != EEXIST) { 152 if (unlink(tmpf)) { 153 err(1, 154 "could not remove temporary lock file %s", 155 tmpf); 156 } 157 err(1, "could not create lock file"); 158 } 159 if (check_lock(file, uucpstyle, debug) == 0) { 160 if (unlink(tmpf)) { 161 err(1, 162 "could not remove temporary lock file %s", 163 tmpf); 164 } 165 return(1); /* Lock file is valid. */ 166 } 167 if (unlink(file) == 0) { 168 printf("%s: stale lock file removed\n", getprogname()); 169 continue; 170 } 171 if (unlink(tmpf)) { 172 err(1, "could not remove temporary lock file %s", 173 tmpf); 174 } 175 err(1, "could not remove stale lock file"); 176 } 177 178 if (debug) 179 printf("%s: lock successfully obtained\n", getprogname()); 180 181 if (unlink(tmpf)) 182 warn("could not remove temporary lock file %s", tmpf); 183 184 return(0); 185 } 186 187 static int 188 check_lock(const char *file, int uucpstyle, int debug) 189 { 190 char buf[BUFSIZE]; 191 int fd; 192 ssize_t len; 193 pid_t pid; 194 195 if ((fd = open(file, O_RDONLY)) == -1) { 196 switch (errno) { 197 case ENOENT: 198 return(1); /* File doesn't exist. */ 199 default: 200 /* 201 * Something went wrong, bail out as 202 * if the lock existed. 203 */ 204 err(1, "could not open lock file"); 205 } 206 } 207 208 len = read(fd, buf, uucpstyle ? sizeof(pid_t) : sizeof(buf)); 209 close(fd); 210 211 if (len < 0) { 212 if (debug) 213 warn("could not read lock file"); 214 return(1); 215 } 216 if (len == 0) { 217 if (debug) 218 warnx("found empty lock file"); 219 return(1); 220 } 221 if (uucpstyle) { 222 if (len != sizeof(pid_t)) { 223 if (debug) 224 warnx("invalid lock file format"); 225 return(1); 226 } 227 memcpy(&pid, buf, sizeof(pid_t)); 228 } else { 229 char *endptr; 230 long tmp_pid; 231 232 if (len == BUFSIZE) { 233 if (debug) 234 warnx("invalid lock file format"); 235 return(1); 236 } 237 238 buf[BUFSIZE] = '\0'; 239 errno = 0; 240 tmp_pid = strtol(buf, &endptr, 10); 241 if ((*endptr != '\0' && *endptr != '\n') || errno || 242 tmp_pid < 1 || (pid = tmp_pid) != tmp_pid) { 243 if (debug) 244 warnx("invalid lock file format"); 245 return(1); 246 } 247 } 248 249 if (kill(pid, 0) == 0) 250 return(0); /* Process is alive. */ 251 252 switch (errno) { 253 case ESRCH: 254 return(1); /* Process is dead. */ 255 case EPERM: 256 return(0); /* Process is alive. */ 257 default: 258 return(0); /* Something else, assume alive. */ 259 } 260 } 261 262 static void 263 usage(void) 264 { 265 fprintf(stderr, "%s [-u] [-d] [-p pid] -f file\n", getprogname()); 266 exit(1); 267 } 268