inet6: require RTF_ANNOUNCE to proxy NS
[dragonfly.git] / usr.bin / shlock / shlock.c
blobbeeb3da2402a7b1abe3be77fef9eea02c138c14e
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 *tmpbuf;
106 char *dir;
107 int fd, ret;
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. */
113 tmpbuf = strdup(file);
114 if ((dir = dirname(tmpbuf)) == NULL)
115 err(1, "dirname() failed");
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);
122 if (debug) {
123 printf("%s: trying lock file %s for process %ld\n",
124 getprogname(), file, (long)pid);
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);
136 /* Try again. */
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);
144 if (unlink(tmpf))
145 err(1, "could not remove temporary lock file %s", tmpf);
147 return(1);
150 close(fd);
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);
159 err(1, "could not create lock file");
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);
167 return(1); /* Lock file is valid. */
169 if (unlink(file) == 0) {
170 printf("%s: stale lock file removed\n", getprogname());
171 continue;
173 if (unlink(tmpf)) {
174 err(1, "could not remove temporary lock file %s",
175 tmpf);
177 err(1, "could not remove stale lock file");
180 if (debug)
181 printf("%s: lock successfully obtained\n", getprogname());
183 if (unlink(tmpf))
184 warn("could not remove temporary lock file %s", tmpf);
186 return(0);
189 static int
190 check_lock(const char *file, int uucpstyle, int debug)
192 char buf[BUFSIZE];
193 int fd;
194 ssize_t len;
195 pid_t pid;
197 if ((fd = open(file, O_RDONLY)) == -1) {
198 switch (errno) {
199 case ENOENT:
200 return(1); /* File doesn't exist. */
201 default:
203 * Something went wrong, bail out as
204 * if the lock existed.
206 err(1, "could not open lock file");
210 len = read(fd, buf, uucpstyle ? sizeof(pid_t) : sizeof(buf));
211 close(fd);
213 if (len < 0) {
214 if (debug)
215 warn("could not read lock file");
216 return(1);
218 if (len == 0) {
219 if (debug)
220 warnx("found empty lock file");
221 return(1);
223 if (uucpstyle) {
224 if (len != sizeof(pid_t)) {
225 if (debug)
226 warnx("invalid lock file format");
227 return(1);
229 memcpy(&pid, buf, sizeof(pid_t));
230 } else {
231 char *endptr;
232 long tmp_pid;
234 if (len == BUFSIZE) {
235 if (debug)
236 warnx("invalid lock file format");
237 return(1);
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);
251 if (kill(pid, 0) == 0)
252 return(0); /* Process is alive. */
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. */
264 static void
265 usage(void)
267 fprintf(stderr, "%s [-u] [-d] [-p pid] -f file\n", getprogname());
268 exit(1);