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 return(1); 145 } 146 147 close(fd); 148 149 while (link(tmpf, file)) { 150 if (errno != EEXIST) { 151 if (unlink(tmpf)) { 152 err(1, 153 "could not remove temporary lock file %s", 154 tmpf); 155 } 156 err(1, "could not create lock file"); 157 } 158 if (check_lock(file, uucpstyle, debug) == 0) { 159 if (unlink(tmpf)) { 160 err(1, 161 "could not remove temporary lock file %s", 162 tmpf); 163 } 164 return(1); /* Lock file is valid. */ 165 } 166 if (unlink(file) == 0) { 167 printf("%s: stale lock file removed\n", getprogname()); 168 continue; 169 } 170 if (unlink(tmpf)) { 171 err(1, "could not remove temporary lock file %s", 172 tmpf); 173 } 174 err(1, "could not remove stale lock file"); 175 } 176 177 if (debug) 178 printf("%s: lock successfully obtained\n", getprogname()); 179 180 if (unlink(tmpf)) 181 warn("could not remove temporary lock file %s", tmpf); 182 183 return(0); 184 } 185 186 static int 187 check_lock(const char *file, int uucpstyle, int debug) 188 { 189 char buf[BUFSIZE]; 190 int fd; 191 ssize_t len; 192 pid_t pid; 193 194 if ((fd = open(file, O_RDONLY)) == -1) { 195 switch (errno) { 196 case ENOENT: 197 return(1); /* File doesn't exist. */ 198 default: 199 /* 200 * Something went wrong, bail out as 201 * if the lock existed. 202 */ 203 err(1, "could not open lock file"); 204 } 205 } 206 207 len = read(fd, buf, uucpstyle ? sizeof(pid_t) : sizeof(buf)); 208 close(fd); 209 210 if (len < 0) { 211 if (debug) 212 warn("could not read lock file"); 213 return(1); 214 } 215 if (len == 0) { 216 if (debug) 217 warnx("found empty lock file"); 218 return(1); 219 } 220 if (uucpstyle) { 221 if (len != sizeof(pid_t)) { 222 if (debug) 223 warnx("invalid lock file format"); 224 return(1); 225 } 226 memcpy(&pid, buf, sizeof(pid_t)); 227 } else { 228 char *endptr; 229 long tmp_pid; 230 231 if (len == BUFSIZE) { 232 if (debug) 233 warnx("invalid lock file format"); 234 return(1); 235 } 236 237 buf[BUFSIZE - 1] = '\0'; 238 errno = 0; 239 tmp_pid = strtol(buf, &endptr, 10); 240 if ((*endptr != '\0' && *endptr != '\n') || errno || 241 tmp_pid < 1 || (pid = tmp_pid) != tmp_pid) { 242 if (debug) 243 warnx("invalid lock file format"); 244 return(1); 245 } 246 } 247 248 if (kill(pid, 0) == 0) 249 return(0); /* Process is alive. */ 250 251 switch (errno) { 252 case ESRCH: 253 return(1); /* Process is dead. */ 254 case EPERM: 255 return(0); /* Process is alive. */ 256 default: 257 return(0); /* Something else, assume alive. */ 258 } 259 } 260 261 static void 262 usage(void) 263 { 264 fprintf(stderr, "%s [-u] [-d] [-p pid] -f file\n", getprogname()); 265 exit(1); 266 } 267