SILI - Increase hard -> soft PM target delay to 5 seconds
[dragonfly.git] / usr.bin / shlock / shlock.c
blobbb3e28f82bf0c38f690cb887e7f96a067a43e2c1
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:
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.
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.
34 * $DragonFly: src/usr.bin/shlock/shlock.c,v 1.1 2005/07/23 19:47:15 joerg Exp $
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>
49 #define BUFSIZE 16
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);
55 int
56 main(int argc, char **argv)
58 int ch, debug = 0, uucpstyle = 0;
59 const char *file = NULL;
60 char *endptr;
61 pid_t pid = -1;
62 long tmp_pid;
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();
86 argc -= optind;
87 argv += optind;
89 if (argc != 0)
90 usage();
92 if (file == NULL)
93 usage();
95 if (pid != -1)
96 return(create_lock(file, pid, uucpstyle, debug));
97 else
98 return(check_lock(file, uucpstyle, debug));
101 static int
102 create_lock(const char *file, pid_t pid, int uucpstyle, int debug)
104 char buf[BUFSIZE], tmpf[PATH_MAX];
105 char *dir;
106 int fd, ret;
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. */
112 if ((dir = dirname(file)) == NULL)
113 err(1, "dirname() failed");
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");
119 if (debug) {
120 printf("%s: trying lock file %s for process %ld\n",
121 getprogname(), file, (long)pid);
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);
133 /* Try again. */
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);
141 if (unlink(tmpf))
142 err(1, "could not remove temporary lock file %s", tmpf);
144 free(tmpf);
145 return(1);
148 close(fd);
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);
157 err(1, "could not create lock file");
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);
165 return(1); /* Lock file is valid. */
167 if (unlink(file) == 0) {
168 printf("%s: stale lock file removed\n", getprogname());
169 continue;
171 if (unlink(tmpf)) {
172 err(1, "could not remove temporary lock file %s",
173 tmpf);
175 err(1, "could not remove stale lock file");
178 if (debug)
179 printf("%s: lock successfully obtained\n", getprogname());
181 if (unlink(tmpf))
182 warn("could not remove temporary lock file %s", tmpf);
184 return(0);
187 static int
188 check_lock(const char *file, int uucpstyle, int debug)
190 char buf[BUFSIZE];
191 int fd;
192 ssize_t len;
193 pid_t pid;
195 if ((fd = open(file, O_RDONLY)) == -1) {
196 switch (errno) {
197 case ENOENT:
198 return(1); /* File doesn't exist. */
199 default:
201 * Something went wrong, bail out as
202 * if the lock existed.
204 err(1, "could not open lock file");
208 len = read(fd, buf, uucpstyle ? sizeof(pid_t) : sizeof(buf));
209 close(fd);
211 if (len < 0) {
212 if (debug)
213 warn("could not read lock file");
214 return(1);
216 if (len == 0) {
217 if (debug)
218 warnx("found empty lock file");
219 return(1);
221 if (uucpstyle) {
222 if (len != sizeof(pid_t)) {
223 if (debug)
224 warnx("invalid lock file format");
225 return(1);
227 memcpy(&pid, buf, sizeof(pid_t));
228 } else {
229 char *endptr;
230 long tmp_pid;
232 if (len == BUFSIZE) {
233 if (debug)
234 warnx("invalid lock file format");
235 return(1);
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);
249 if (kill(pid, 0) == 0)
250 return(0); /* Process is alive. */
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. */
262 static void
263 usage(void)
265 fprintf(stderr, "%s [-u] [-d] [-p pid] -f file\n", getprogname());
266 exit(1);