blob: 579b705f346451534c6fb6ffe14da9df54a481c3 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001--- /dev/null
2+++ b/miscutils/lock.c
3@@ -0,0 +1,155 @@
4+/*
5+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
6+ *
7+ * This is free software, licensed under the GNU General Public License v2.
8+ */
9+
10+//config:config LOCK
11+//config: bool "lock"
12+//config: default n
13+//config: help
14+//config: Small utility for using locks in scripts
15+
16+//applet:IF_LOCK(APPLET(lock, BB_DIR_BIN, BB_SUID_DROP))
17+
18+//kbuild:lib-$(CONFIG_LOCK) += lock.o
19+
20+//usage:#define lock_trivial_usage NOUSAGE_STR
21+//usage:#define lock_full_usage ""
22+
23+#include <sys/types.h>
24+#include <sys/file.h>
25+#include <sys/stat.h>
26+#include <signal.h>
27+#include <fcntl.h>
28+#include <unistd.h>
29+#include <stdio.h>
30+#include "busybox.h"
31+
32+static int unlock = 0;
33+static int shared = 0;
34+static int waitonly = 0;
35+static int try_lock = 0;
36+static int fd;
37+static char *file;
38+
39+static void usage(char *name)
40+{
41+ fprintf(stderr, "Usage: %s [-suw] <filename>\n"
42+ " -s Use shared locking\n"
43+ " -u Unlock\n"
44+ " -w Wait for the lock to become free, don't acquire lock\n"
45+ " -n Don't wait for the lock to become free. Fail with exit code\n"
46+ "\n", name);
47+ exit(1);
48+}
49+
50+static void exit_unlock(int sig)
51+{
52+ flock(fd, LOCK_UN);
53+ exit(0);
54+}
55+
56+static int do_unlock(void)
57+{
58+ FILE *f;
59+ int i;
60+
61+ if ((f = fopen(file, "r")) == NULL)
62+ return 0;
63+
64+ fscanf(f, "%d", &i);
65+ if (i > 0)
66+ kill(i, SIGTERM);
67+
68+ fclose(f);
69+
70+ return 0;
71+}
72+
73+static int do_lock(void)
74+{
75+ pid_t pid;
76+ int flags;
77+ char pidstr[12];
78+
79+ if ((fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
80+ if ((fd = open(file, O_RDWR)) < 0) {
81+ fprintf(stderr, "Can't open %s\n", file);
82+ return 1;
83+ }
84+ }
85+
86+ flags = shared ? LOCK_SH : LOCK_EX;
87+ flags |= try_lock ? LOCK_NB : 0;
88+
89+ if (flock(fd, flags) < 0) {
90+ fprintf(stderr, "Can't lock %s\n", file);
91+ return 1;
92+ }
93+
94+ pid = fork();
95+
96+ if (pid < 0)
97+ return -1;
98+
99+ if (pid == 0) {
100+ signal(SIGKILL, exit_unlock);
101+ signal(SIGTERM, exit_unlock);
102+ signal(SIGINT, exit_unlock);
103+ if (waitonly)
104+ exit_unlock(0);
105+ else
106+ while (1)
107+ sleep(1);
108+ } else {
109+ if (!waitonly) {
110+ lseek(fd, 0, SEEK_SET);
111+ ftruncate(fd, 0);
112+ snprintf(pidstr, sizeof(pidstr), "%d\n", pid);
113+ write(fd, pidstr, strlen(pidstr));
114+ close(fd);
115+ }
116+
117+ return 0;
118+ }
119+ return 0;
120+}
121+
122+int lock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
123+int lock_main(int argc, char **argv)
124+{
125+ char **args = &argv[1];
126+ int c = argc - 1;
127+
128+ while ((*args != NULL) && (*args)[0] == '-') {
129+ char *ch = *args;
130+ while (*(++ch) > 0) {
131+ switch(*ch) {
132+ case 'w':
133+ waitonly = 1;
134+ break;
135+ case 's':
136+ shared = 1;
137+ break;
138+ case 'u':
139+ unlock = 1;
140+ break;
141+ case 'n':
142+ try_lock = 1;
143+ break;
144+ }
145+ }
146+ c--;
147+ args++;
148+ }
149+
150+ if (c != 1)
151+ usage(argv[0]);
152+
153+ file = *args;
154+ if (unlock)
155+ return do_unlock();
156+ else
157+ return do_lock();
158+}