libc/nls: Sync with FreeBSD.
[dragonfly.git] / usr.bin / shlock / shlock.c
blob9f33f564368758738cb49e806e75bb612a91a963
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 return(1);
147 close(fd);
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);
156 err(1, "could not create lock file");
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);
164 return(1); /* Lock file is valid. */
166 if (unlink(file) == 0) {
167 printf("%s: stale lock file removed\n", getprogname());
168 continue;
170 if (unlink(tmpf)) {
171 err(1, "could not remove temporary lock file %s",
172 tmpf);
174 err(1, "could not remove stale lock file");
177 if (debug)
178 printf("%s: lock successfully obtained\n", getprogname());
180 if (unlink(tmpf))
181 warn("could not remove temporary lock file %s", tmpf);
183 return(0);
186 static int
187 check_lock(const char *file, int uucpstyle, int debug)
189 char buf[BUFSIZE];
190 int fd;
191 ssize_t len;
192 pid_t pid;
194 if ((fd = open(file, O_RDONLY)) == -1) {
195 switch (errno) {
196 case ENOENT:
197 return(1); /* File doesn't exist. */
198 default:
200 * Something went wrong, bail out as
201 * if the lock existed.
203 err(1, "could not open lock file");
207 len = read(fd, buf, uucpstyle ? sizeof(pid_t) : sizeof(buf));
208 close(fd);
210 if (len < 0) {
211 if (debug)
212 warn("could not read lock file");
213 return(1);
215 if (len == 0) {
216 if (debug)
217 warnx("found empty lock file");
218 return(1);
220 if (uucpstyle) {
221 if (len != sizeof(pid_t)) {
222 if (debug)
223 warnx("invalid lock file format");
224 return(1);
226 memcpy(&pid, buf, sizeof(pid_t));
227 } else {
228 char *endptr;
229 long tmp_pid;
231 if (len == BUFSIZE) {
232 if (debug)
233 warnx("invalid lock file format");
234 return(1);
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);
248 if (kill(pid, 0) == 0)
249 return(0); /* Process is alive. */
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. */
261 static void
262 usage(void)
264 fprintf(stderr, "%s [-u] [-d] [-p pid] -f file\n", getprogname());
265 exit(1);