diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-16 02:27:24 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-16 02:27:24 +0000 |
commit | 83ea643d8dc9b6f53706ba30bc4b53338f4f7994 (patch) | |
tree | 3a5f790604219213666cbf5cccd747c02528912c | |
parent | 3672fe9e9141c0684cae1e72e84cb2704f2a8702 (diff) | |
download | busybox-w32-83ea643d8dc9b6f53706ba30bc4b53338f4f7994.tar.gz busybox-w32-83ea643d8dc9b6f53706ba30bc4b53338f4f7994.tar.bz2 busybox-w32-83ea643d8dc9b6f53706ba30bc4b53338f4f7994.zip |
svlogd: new applet. +9k. Still too big, but it was 12k yesterday.
-rw-r--r-- | console-tools/loadfont.c | 2 | ||||
-rw-r--r-- | include/applets.h | 1 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | include/usage.h | 7 | ||||
-rw-r--r-- | libbb/xatol.c | 10 | ||||
-rw-r--r-- | runit/Config.in | 8 | ||||
-rw-r--r-- | runit/Kbuild | 1 | ||||
-rw-r--r-- | runit/chpst.c | 47 | ||||
-rw-r--r-- | runit/runit_lib.c | 999 | ||||
-rw-r--r-- | runit/runit_lib.h | 403 | ||||
-rw-r--r-- | runit/svlogd.c | 880 |
11 files changed, 2342 insertions, 18 deletions
diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index 513b3c170..5a05876c2 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include "busybox.h" | 10 | #include "busybox.h" |
11 | #include <sys/kd.h> | 11 | #include <sys/kd.h> |
12 | 12 | ||
13 | enum{ | 13 | enum { |
14 | PSF_MAGIC1 = 0x36, | 14 | PSF_MAGIC1 = 0x36, |
15 | PSF_MAGIC2 = 0x04, | 15 | PSF_MAGIC2 = 0x04, |
16 | 16 | ||
diff --git a/include/applets.h b/include/applets.h index 0d0f56483..c4c75a83f 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -270,6 +270,7 @@ USE_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_NEVER)) | |||
270 | USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS)) | 270 | USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS)) |
271 | USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 271 | USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
272 | USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 272 | USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
273 | USE_SVLOGD(APPLET(svlogd, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | ||
273 | USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff)) | 274 | USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff)) |
274 | USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon)) | 275 | USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon)) |
275 | USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 276 | USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
diff --git a/include/libbb.h b/include/libbb.h index ce4b9223c..3fb477b33 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -335,6 +335,8 @@ long xatol_range(const char *numstr, long lower, long upper); | |||
335 | long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes); | 335 | long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes); |
336 | long xatol(const char *numstr); | 336 | long xatol(const char *numstr); |
337 | /* Specialized: */ | 337 | /* Specialized: */ |
338 | unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper); | ||
339 | unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes); | ||
338 | unsigned xatou(const char *numstr); | 340 | unsigned xatou(const char *numstr); |
339 | int xatoi_range(const char *numstr, int lower, int upper); | 341 | int xatoi_range(const char *numstr, int lower, int upper); |
340 | int xatoi(const char *numstr); | 342 | int xatoi(const char *numstr); |
diff --git a/include/usage.h b/include/usage.h index 7de93e00e..db41a8e79 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -2841,6 +2841,13 @@ USE_FEATURE_START_STOP_DAEMON_FANCY( \ | |||
2841 | "\t-r\tuse BSD sum algorithm (1K blocks)\n" \ | 2841 | "\t-r\tuse BSD sum algorithm (1K blocks)\n" \ |
2842 | "\t-s\tuse System V sum algorithm (512byte blocks)" | 2842 | "\t-s\tuse System V sum algorithm (512byte blocks)" |
2843 | 2843 | ||
2844 | #define svlogd_trivial_usage \ | ||
2845 | "[-ttv] [-r c] [-R abc] [-l len] [-b buflen] dir..." | ||
2846 | #define svlogd_full_usage \ | ||
2847 | "Continuously read log data from standard input, optionally " \ | ||
2848 | "filter log messages, and write the data to one or more automatically " \ | ||
2849 | "rotated logs." | ||
2850 | |||
2844 | #define swapoff_trivial_usage \ | 2851 | #define swapoff_trivial_usage \ |
2845 | "[-a] [DEVICE]" | 2852 | "[-a] [DEVICE]" |
2846 | #define swapoff_full_usage \ | 2853 | #define swapoff_full_usage \ |
diff --git a/libbb/xatol.c b/libbb/xatol.c index 74a3b9917..cce8ad3eb 100644 --- a/libbb/xatol.c +++ b/libbb/xatol.c | |||
@@ -195,6 +195,16 @@ long xatol(const char *numstr) | |||
195 | 195 | ||
196 | /* Others */ | 196 | /* Others */ |
197 | 197 | ||
198 | unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper) | ||
199 | { | ||
200 | return xstrtoul_range_sfx(numstr, 10, lower, upper, NULL); | ||
201 | } | ||
202 | |||
203 | unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes) | ||
204 | { | ||
205 | return xstrtoul_range_sfx(numstr, 10, 0, UINT_MAX, suffixes); | ||
206 | } | ||
207 | |||
198 | unsigned xatou(const char *numstr) | 208 | unsigned xatou(const char *numstr) |
199 | { | 209 | { |
200 | return xatoul_range(numstr, 0, UINT_MAX); | 210 | return xatoul_range(numstr, 0, UINT_MAX); |
diff --git a/runit/Config.in b/runit/Config.in index b90b0232e..c849c074c 100644 --- a/runit/Config.in +++ b/runit/Config.in | |||
@@ -5,6 +5,14 @@ | |||
5 | 5 | ||
6 | menu "Runit Utilities" | 6 | menu "Runit Utilities" |
7 | 7 | ||
8 | config SVLOGD | ||
9 | bool "svlogd" | ||
10 | default n | ||
11 | help | ||
12 | svlogd continuously reads log data from its standard input, optionally | ||
13 | filters log messages, and writes the data to one or more automatically | ||
14 | rotated logs. | ||
15 | |||
8 | config CHPST | 16 | config CHPST |
9 | bool "chpst" | 17 | bool "chpst" |
10 | default n | 18 | default n |
diff --git a/runit/Kbuild b/runit/Kbuild index 39a9b0229..730035632 100644 --- a/runit/Kbuild +++ b/runit/Kbuild | |||
@@ -6,3 +6,4 @@ | |||
6 | 6 | ||
7 | lib-y:= | 7 | lib-y:= |
8 | lib-$(CONFIG_CHPST) += chpst.o | 8 | lib-$(CONFIG_CHPST) += chpst.o |
9 | lib-$(CONFIG_SVLOGD) += svlogd.o runit_lib.o | ||
diff --git a/runit/chpst.c b/runit/chpst.c index de6a33764..3fcef8eec 100644 --- a/runit/chpst.c +++ b/runit/chpst.c | |||
@@ -26,6 +26,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ | 28 | /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ |
29 | /* Dependencies on runit_lib.c removed */ | ||
29 | 30 | ||
30 | #include "busybox.h" | 31 | #include "busybox.h" |
31 | 32 | ||
@@ -94,7 +95,9 @@ static void edir(const char *directory_name) | |||
94 | errno = 0; | 95 | errno = 0; |
95 | d = readdir(dir); | 96 | d = readdir(dir); |
96 | if (!d) { | 97 | if (!d) { |
97 | if (errno) bb_perror_msg_and_die("readdir %s", directory_name); | 98 | if (errno) |
99 | bb_perror_msg_and_die("readdir %s", | ||
100 | directory_name); | ||
98 | break; | 101 | break; |
99 | } | 102 | } |
100 | if (d->d_name[0] == '.') continue; | 103 | if (d->d_name[0] == '.') continue; |
@@ -102,12 +105,12 @@ static void edir(const char *directory_name) | |||
102 | if (fd < 0) { | 105 | if (fd < 0) { |
103 | if ((errno == EISDIR) && env_dir) { | 106 | if ((errno == EISDIR) && env_dir) { |
104 | if (OPT_verbose) | 107 | if (OPT_verbose) |
105 | bb_perror_msg("warning: %s/%s is a directory", directory_name, | 108 | bb_perror_msg("warning: %s/%s is a directory", |
106 | d->d_name); | 109 | directory_name, d->d_name); |
107 | continue; | 110 | continue; |
108 | } else | 111 | } else |
109 | bb_perror_msg_and_die("open %s/%s", directory_name, /* was exiting 111 */ | 112 | bb_perror_msg_and_die("open %s/%s", |
110 | d->d_name); | 113 | directory_name, d->d_name); |
111 | } | 114 | } |
112 | if (fd >= 0) { | 115 | if (fd >= 0) { |
113 | char buf[256]; | 116 | char buf[256]; |
@@ -116,8 +119,8 @@ static void edir(const char *directory_name) | |||
116 | 119 | ||
117 | size = safe_read(fd, buf, sizeof(buf)-1); | 120 | size = safe_read(fd, buf, sizeof(buf)-1); |
118 | if (size < 0) | 121 | if (size < 0) |
119 | bb_perror_msg_and_die("read %s/%s", directory_name, /* was exiting 111 */ | 122 | bb_perror_msg_and_die("read %s/%s", |
120 | d->d_name); | 123 | directory_name, d->d_name); |
121 | if (size == 0) { | 124 | if (size == 0) { |
122 | unsetenv(d->d_name); | 125 | unsetenv(d->d_name); |
123 | continue; | 126 | continue; |
@@ -158,21 +161,24 @@ static void slimit(void) | |||
158 | #ifdef RLIMIT_DATA | 161 | #ifdef RLIMIT_DATA |
159 | limit(RLIMIT_DATA, limitd); | 162 | limit(RLIMIT_DATA, limitd); |
160 | #else | 163 | #else |
161 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_DATA"); | 164 | if (OPT_verbose) bb_error_msg("system does not support %s", |
165 | "RLIMIT_DATA"); | ||
162 | #endif | 166 | #endif |
163 | } | 167 | } |
164 | if (limits >= -1) { | 168 | if (limits >= -1) { |
165 | #ifdef RLIMIT_STACK | 169 | #ifdef RLIMIT_STACK |
166 | limit(RLIMIT_STACK, limits); | 170 | limit(RLIMIT_STACK, limits); |
167 | #else | 171 | #else |
168 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_STACK"); | 172 | if (OPT_verbose) bb_error_msg("system does not support %s", |
173 | "RLIMIT_STACK"); | ||
169 | #endif | 174 | #endif |
170 | } | 175 | } |
171 | if (limitl >= -1) { | 176 | if (limitl >= -1) { |
172 | #ifdef RLIMIT_MEMLOCK | 177 | #ifdef RLIMIT_MEMLOCK |
173 | limit(RLIMIT_MEMLOCK, limitl); | 178 | limit(RLIMIT_MEMLOCK, limitl); |
174 | #else | 179 | #else |
175 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_MEMLOCK"); | 180 | if (OPT_verbose) bb_error_msg("system does not support %s", |
181 | "RLIMIT_MEMLOCK"); | ||
176 | #endif | 182 | #endif |
177 | } | 183 | } |
178 | if (limita >= -1) { | 184 | if (limita >= -1) { |
@@ -183,7 +189,8 @@ static void slimit(void) | |||
183 | limit(RLIMIT_AS, limita); | 189 | limit(RLIMIT_AS, limita); |
184 | #else | 190 | #else |
185 | if (OPT_verbose) | 191 | if (OPT_verbose) |
186 | bb_error_msg("system does not support %s", "RLIMIT_VMEM"); | 192 | bb_error_msg("system does not support %s", |
193 | "RLIMIT_VMEM"); | ||
187 | #endif | 194 | #endif |
188 | #endif | 195 | #endif |
189 | } | 196 | } |
@@ -195,7 +202,8 @@ static void slimit(void) | |||
195 | limit(RLIMIT_OFILE, limito); | 202 | limit(RLIMIT_OFILE, limito); |
196 | #else | 203 | #else |
197 | if (OPT_verbose) | 204 | if (OPT_verbose) |
198 | bb_error_msg("system does not support %s", "RLIMIT_NOFILE"); | 205 | bb_error_msg("system does not support %s", |
206 | "RLIMIT_NOFILE"); | ||
199 | #endif | 207 | #endif |
200 | #endif | 208 | #endif |
201 | } | 209 | } |
@@ -203,35 +211,40 @@ static void slimit(void) | |||
203 | #ifdef RLIMIT_NPROC | 211 | #ifdef RLIMIT_NPROC |
204 | limit(RLIMIT_NPROC, limitp); | 212 | limit(RLIMIT_NPROC, limitp); |
205 | #else | 213 | #else |
206 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_NPROC"); | 214 | if (OPT_verbose) bb_error_msg("system does not support %s", |
215 | "RLIMIT_NPROC"); | ||
207 | #endif | 216 | #endif |
208 | } | 217 | } |
209 | if (limitf >= -1) { | 218 | if (limitf >= -1) { |
210 | #ifdef RLIMIT_FSIZE | 219 | #ifdef RLIMIT_FSIZE |
211 | limit(RLIMIT_FSIZE, limitf); | 220 | limit(RLIMIT_FSIZE, limitf); |
212 | #else | 221 | #else |
213 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_FSIZE"); | 222 | if (OPT_verbose) bb_error_msg("system does not support %s", |
223 | "RLIMIT_FSIZE"); | ||
214 | #endif | 224 | #endif |
215 | } | 225 | } |
216 | if (limitc >= -1) { | 226 | if (limitc >= -1) { |
217 | #ifdef RLIMIT_CORE | 227 | #ifdef RLIMIT_CORE |
218 | limit(RLIMIT_CORE, limitc); | 228 | limit(RLIMIT_CORE, limitc); |
219 | #else | 229 | #else |
220 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_CORE"); | 230 | if (OPT_verbose) bb_error_msg("system does not support %s", |
231 | "RLIMIT_CORE"); | ||
221 | #endif | 232 | #endif |
222 | } | 233 | } |
223 | if (limitr >= -1) { | 234 | if (limitr >= -1) { |
224 | #ifdef RLIMIT_RSS | 235 | #ifdef RLIMIT_RSS |
225 | limit(RLIMIT_RSS, limitr); | 236 | limit(RLIMIT_RSS, limitr); |
226 | #else | 237 | #else |
227 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_RSS"); | 238 | if (OPT_verbose) bb_error_msg("system does not support %s", |
239 | "RLIMIT_RSS"); | ||
228 | #endif | 240 | #endif |
229 | } | 241 | } |
230 | if (limitt >= -1) { | 242 | if (limitt >= -1) { |
231 | #ifdef RLIMIT_CPU | 243 | #ifdef RLIMIT_CPU |
232 | limit(RLIMIT_CPU, limitt); | 244 | limit(RLIMIT_CPU, limitt); |
233 | #else | 245 | #else |
234 | if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_CPU"); | 246 | if (OPT_verbose) bb_error_msg("system does not support %s", |
247 | "RLIMIT_CPU"); | ||
235 | #endif | 248 | #endif |
236 | } | 249 | } |
237 | } | 250 | } |
diff --git a/runit/runit_lib.c b/runit/runit_lib.c new file mode 100644 index 000000000..322bef858 --- /dev/null +++ b/runit/runit_lib.c | |||
@@ -0,0 +1,999 @@ | |||
1 | /* | ||
2 | Copyright (c) 2001-2006, Gerrit Pape | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | 1. Redistributions of source code must retain the above copyright notice, | ||
9 | this list of conditions and the following disclaimer. | ||
10 | 2. Redistributions in binary form must reproduce the above copyright | ||
11 | notice, this list of conditions and the following disclaimer in the | ||
12 | documentation and/or other materials provided with the distribution. | ||
13 | 3. The name of the author may not be used to endorse or promote products | ||
14 | derived from this software without specific prior written permission. | ||
15 | |||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | ||
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||
22 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
23 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | ||
25 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ | ||
29 | /* Collected into one file from runit's many tiny files */ | ||
30 | /* TODO: review, eliminate unneeded stuff, move good stuff to libbb */ | ||
31 | |||
32 | #include <sys/poll.h> | ||
33 | #include <sys/file.h> | ||
34 | #include "libbb.h" | ||
35 | #include "runit_lib.h" | ||
36 | |||
37 | #ifndef O_NONBLOCK | ||
38 | #define O_NONBLOCK O_NDELAY | ||
39 | #endif | ||
40 | |||
41 | /*** buffer.c ***/ | ||
42 | |||
43 | void buffer_init(buffer *s,int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len) | ||
44 | { | ||
45 | s->x = buf; | ||
46 | s->fd = fd; | ||
47 | s->op = op; | ||
48 | s->p = 0; | ||
49 | s->n = len; | ||
50 | } | ||
51 | |||
52 | |||
53 | /*** buffer_get.c ***/ | ||
54 | |||
55 | static int oneread(int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len) | ||
56 | { | ||
57 | int r; | ||
58 | |||
59 | for (;;) { | ||
60 | r = op(fd,buf,len); | ||
61 | if (r == -1) if (errno == EINTR) continue; | ||
62 | return r; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | static int getthis(buffer *s,char *buf,unsigned len) | ||
67 | { | ||
68 | if (len > s->p) len = s->p; | ||
69 | s->p -= len; | ||
70 | memcpy(buf,s->x + s->n,len); | ||
71 | s->n += len; | ||
72 | return len; | ||
73 | } | ||
74 | |||
75 | int buffer_feed(buffer *s) | ||
76 | { | ||
77 | int r; | ||
78 | |||
79 | if (s->p) return s->p; | ||
80 | r = oneread(s->op,s->fd,s->x,s->n); | ||
81 | if (r <= 0) return r; | ||
82 | s->p = r; | ||
83 | s->n -= r; | ||
84 | if (s->n > 0) memmove(s->x + s->n,s->x,r); | ||
85 | return r; | ||
86 | } | ||
87 | |||
88 | int buffer_bget(buffer *s,char *buf,unsigned len) | ||
89 | { | ||
90 | int r; | ||
91 | |||
92 | if (s->p > 0) return getthis(s,buf,len); | ||
93 | if (s->n <= len) return oneread(s->op,s->fd,buf,s->n); | ||
94 | r = buffer_feed(s); if (r <= 0) return r; | ||
95 | return getthis(s,buf,len); | ||
96 | } | ||
97 | |||
98 | int buffer_get(buffer *s,char *buf,unsigned len) | ||
99 | { | ||
100 | int r; | ||
101 | |||
102 | if (s->p > 0) return getthis(s,buf,len); | ||
103 | if (s->n <= len) return oneread(s->op,s->fd,buf,len); | ||
104 | r = buffer_feed(s); if (r <= 0) return r; | ||
105 | return getthis(s,buf,len); | ||
106 | } | ||
107 | |||
108 | char *buffer_peek(buffer *s) | ||
109 | { | ||
110 | return s->x + s->n; | ||
111 | } | ||
112 | |||
113 | void buffer_seek(buffer *s,unsigned len) | ||
114 | { | ||
115 | s->n += len; | ||
116 | s->p -= len; | ||
117 | } | ||
118 | |||
119 | |||
120 | /*** buffer_put.c ***/ | ||
121 | |||
122 | static int allwrite(int (*op)(int fd,char *buf,unsigned len),int fd,const char *buf,unsigned len) | ||
123 | { | ||
124 | int w; | ||
125 | |||
126 | while (len) { | ||
127 | w = op(fd,(char*)buf,len); | ||
128 | if (w == -1) { | ||
129 | if (errno == EINTR) continue; | ||
130 | return -1; /* note that some data may have been written */ | ||
131 | } | ||
132 | if (w == 0) ; /* luser's fault */ | ||
133 | buf += w; | ||
134 | len -= w; | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | int buffer_flush(buffer *s) | ||
140 | { | ||
141 | int p; | ||
142 | |||
143 | p = s->p; | ||
144 | if (!p) return 0; | ||
145 | s->p = 0; | ||
146 | return allwrite(s->op,s->fd,s->x,p); | ||
147 | } | ||
148 | |||
149 | int buffer_putalign(buffer *s,const char *buf,unsigned len) | ||
150 | { | ||
151 | unsigned n; | ||
152 | |||
153 | while (len > (n = s->n - s->p)) { | ||
154 | memcpy(s->x + s->p,buf,n); | ||
155 | s->p += n; | ||
156 | buf += n; | ||
157 | len -= n; | ||
158 | if (buffer_flush(s) == -1) return -1; | ||
159 | } | ||
160 | /* now len <= s->n - s->p */ | ||
161 | memcpy(s->x + s->p,buf,len); | ||
162 | s->p += len; | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | int buffer_put(buffer *s,const char *buf,unsigned len) | ||
167 | { | ||
168 | unsigned n; | ||
169 | |||
170 | n = s->n; | ||
171 | if (len > n - s->p) { | ||
172 | if (buffer_flush(s) == -1) return -1; | ||
173 | /* now s->p == 0 */ | ||
174 | if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE; | ||
175 | while (len > s->n) { | ||
176 | if (n > len) n = len; | ||
177 | if (allwrite(s->op,s->fd,buf,n) == -1) return -1; | ||
178 | buf += n; | ||
179 | len -= n; | ||
180 | } | ||
181 | } | ||
182 | /* now len <= s->n - s->p */ | ||
183 | memcpy(s->x + s->p,buf,len); | ||
184 | s->p += len; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | int buffer_putflush(buffer *s,const char *buf,unsigned len) | ||
189 | { | ||
190 | if (buffer_flush(s) == -1) return -1; | ||
191 | return allwrite(s->op,s->fd,buf,len); | ||
192 | } | ||
193 | |||
194 | int buffer_putsalign(buffer *s,const char *buf) | ||
195 | { | ||
196 | return buffer_putalign(s,buf,strlen(buf)); | ||
197 | } | ||
198 | |||
199 | int buffer_puts(buffer *s,const char *buf) | ||
200 | { | ||
201 | return buffer_put(s,buf,strlen(buf)); | ||
202 | } | ||
203 | |||
204 | int buffer_putsflush(buffer *s,const char *buf) | ||
205 | { | ||
206 | return buffer_putflush(s,buf,strlen(buf)); | ||
207 | } | ||
208 | |||
209 | |||
210 | /*** buffer_read.c ***/ | ||
211 | |||
212 | int buffer_unixread(int fd,char *buf,unsigned len) | ||
213 | { | ||
214 | return read(fd,buf,len); | ||
215 | } | ||
216 | |||
217 | |||
218 | /*** buffer_write.c ***/ | ||
219 | |||
220 | int buffer_unixwrite(int fd,char *buf,unsigned len) | ||
221 | { | ||
222 | return write(fd,buf,len); | ||
223 | } | ||
224 | |||
225 | |||
226 | /*** byte_chr.c ***/ | ||
227 | |||
228 | unsigned byte_chr(char *s,unsigned n,int c) | ||
229 | { | ||
230 | char ch; | ||
231 | char *t; | ||
232 | |||
233 | ch = c; | ||
234 | t = s; | ||
235 | for (;;) { | ||
236 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
237 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
238 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
239 | if (!n) break; if (*t == ch) break; ++t; --n; | ||
240 | } | ||
241 | return t - s; | ||
242 | } | ||
243 | |||
244 | |||
245 | /*** coe.c ***/ | ||
246 | |||
247 | int coe(int fd) | ||
248 | { | ||
249 | return fcntl(fd,F_SETFD,FD_CLOEXEC); | ||
250 | } | ||
251 | |||
252 | |||
253 | /*** fd_copy.c ***/ | ||
254 | |||
255 | int fd_copy(int to,int from) | ||
256 | { | ||
257 | if (to == from) return 0; | ||
258 | if (fcntl(from,F_GETFL,0) == -1) return -1; | ||
259 | close(to); | ||
260 | if (fcntl(from,F_DUPFD,to) == -1) return -1; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | |||
265 | /*** fd_move.c ***/ | ||
266 | |||
267 | int fd_move(int to,int from) | ||
268 | { | ||
269 | if (to == from) return 0; | ||
270 | if (fd_copy(to,from) == -1) return -1; | ||
271 | close(from); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | |||
276 | /*** fifo.c ***/ | ||
277 | |||
278 | int fifo_make(const char *fn,int mode) { return mkfifo(fn,mode); } | ||
279 | |||
280 | |||
281 | /*** fmt_ptime.c ***/ | ||
282 | |||
283 | unsigned fmt_ptime(char *s, struct taia *ta) { | ||
284 | struct tm *t; | ||
285 | unsigned long u; | ||
286 | |||
287 | if (ta->sec.x < 4611686018427387914ULL) return 0; /* impossible? */ | ||
288 | u = ta->sec.x -4611686018427387914ULL; | ||
289 | if (!(t = gmtime((time_t*)&u))) return 0; | ||
290 | fmt_ulong(s, 1900 + t->tm_year); | ||
291 | s[4] = '-'; fmt_uint0(&s[5], t->tm_mon+1, 2); | ||
292 | s[7] = '-'; fmt_uint0(&s[8], t->tm_mday, 2); | ||
293 | s[10] = '_'; fmt_uint0(&s[11], t->tm_hour, 2); | ||
294 | s[13] = ':'; fmt_uint0(&s[14], t->tm_min, 2); | ||
295 | s[16] = ':'; fmt_uint0(&s[17], t->tm_sec, 2); | ||
296 | s[19] = '.'; fmt_uint0(&s[20], ta->nano, 9); | ||
297 | return 25; | ||
298 | } | ||
299 | |||
300 | unsigned fmt_taia(char *s, struct taia *t) { | ||
301 | static char hex[16] = "0123456789abcdef"; | ||
302 | static char pack[TAIA_PACK]; | ||
303 | int i; | ||
304 | |||
305 | taia_pack(pack, t); | ||
306 | s[0] = '@'; | ||
307 | for (i = 0; i < 12; ++i) { | ||
308 | s[i*2+1] = hex[(pack[i] >> 4) &15]; | ||
309 | s[i*2+2] = hex[pack[i] &15]; | ||
310 | } | ||
311 | return 25; | ||
312 | } | ||
313 | |||
314 | |||
315 | /*** fmt_uint.c ***/ | ||
316 | |||
317 | unsigned fmt_uint(char *s,unsigned u) | ||
318 | { | ||
319 | return fmt_ulong(s,u); | ||
320 | } | ||
321 | |||
322 | |||
323 | /*** fmt_uint0.c ***/ | ||
324 | |||
325 | unsigned fmt_uint0(char *s,unsigned u,unsigned n) | ||
326 | { | ||
327 | unsigned len; | ||
328 | len = fmt_uint(FMT_LEN,u); | ||
329 | while (len < n) { if (s) *s++ = '0'; ++len; } | ||
330 | if (s) fmt_uint(s,u); | ||
331 | return len; | ||
332 | } | ||
333 | |||
334 | |||
335 | /*** fmt_ulong.c ***/ | ||
336 | |||
337 | unsigned fmt_ulong(char *s,unsigned long u) | ||
338 | { | ||
339 | unsigned len; unsigned long q; | ||
340 | len = 1; q = u; | ||
341 | while (q > 9) { ++len; q /= 10; } | ||
342 | if (s) { | ||
343 | s += len; | ||
344 | do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ | ||
345 | } | ||
346 | return len; | ||
347 | } | ||
348 | |||
349 | |||
350 | /*** tai_now.c ***/ | ||
351 | |||
352 | void tai_now(struct tai *t) | ||
353 | { | ||
354 | tai_unix(t,time((time_t *) 0)); | ||
355 | } | ||
356 | |||
357 | |||
358 | /*** tai_pack.c ***/ | ||
359 | |||
360 | void tai_pack(char *s,const struct tai *t) | ||
361 | { | ||
362 | uint64_t x; | ||
363 | |||
364 | x = t->x; | ||
365 | s[7] = x & 255; x >>= 8; | ||
366 | s[6] = x & 255; x >>= 8; | ||
367 | s[5] = x & 255; x >>= 8; | ||
368 | s[4] = x & 255; x >>= 8; | ||
369 | s[3] = x & 255; x >>= 8; | ||
370 | s[2] = x & 255; x >>= 8; | ||
371 | s[1] = x & 255; x >>= 8; | ||
372 | s[0] = x; | ||
373 | } | ||
374 | |||
375 | |||
376 | /*** tai_sub.c ***/ | ||
377 | |||
378 | void tai_sub(struct tai *t,const struct tai *u,const struct tai *v) | ||
379 | { | ||
380 | t->x = u->x - v->x; | ||
381 | } | ||
382 | |||
383 | |||
384 | /*** tai_unpack.c ***/ | ||
385 | |||
386 | void tai_unpack(const char *s,struct tai *t) | ||
387 | { | ||
388 | uint64_t x; | ||
389 | |||
390 | x = (unsigned char) s[0]; | ||
391 | x <<= 8; x += (unsigned char) s[1]; | ||
392 | x <<= 8; x += (unsigned char) s[2]; | ||
393 | x <<= 8; x += (unsigned char) s[3]; | ||
394 | x <<= 8; x += (unsigned char) s[4]; | ||
395 | x <<= 8; x += (unsigned char) s[5]; | ||
396 | x <<= 8; x += (unsigned char) s[6]; | ||
397 | x <<= 8; x += (unsigned char) s[7]; | ||
398 | t->x = x; | ||
399 | } | ||
400 | |||
401 | |||
402 | /*** taia_add.c ***/ | ||
403 | |||
404 | /* XXX: breaks tai encapsulation */ | ||
405 | |||
406 | void taia_add(struct taia *t,const struct taia *u,const struct taia *v) | ||
407 | { | ||
408 | t->sec.x = u->sec.x + v->sec.x; | ||
409 | t->nano = u->nano + v->nano; | ||
410 | t->atto = u->atto + v->atto; | ||
411 | if (t->atto > 999999999UL) { | ||
412 | t->atto -= 1000000000UL; | ||
413 | ++t->nano; | ||
414 | } | ||
415 | if (t->nano > 999999999UL) { | ||
416 | t->nano -= 1000000000UL; | ||
417 | ++t->sec.x; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | |||
422 | /*** taia_approx.c ***/ | ||
423 | |||
424 | double taia_approx(const struct taia *t) | ||
425 | { | ||
426 | return tai_approx(&t->sec) + taia_frac(t); | ||
427 | } | ||
428 | |||
429 | |||
430 | /*** taia_frac.c ***/ | ||
431 | |||
432 | double taia_frac(const struct taia *t) | ||
433 | { | ||
434 | return (t->atto * 0.000000001 + t->nano) * 0.000000001; | ||
435 | } | ||
436 | |||
437 | |||
438 | /*** taia_less.c ***/ | ||
439 | |||
440 | /* XXX: breaks tai encapsulation */ | ||
441 | |||
442 | int taia_less(const struct taia *t,const struct taia *u) | ||
443 | { | ||
444 | if (t->sec.x < u->sec.x) return 1; | ||
445 | if (t->sec.x > u->sec.x) return 0; | ||
446 | if (t->nano < u->nano) return 1; | ||
447 | if (t->nano > u->nano) return 0; | ||
448 | return t->atto < u->atto; | ||
449 | } | ||
450 | |||
451 | |||
452 | /*** taia_now.c ***/ | ||
453 | |||
454 | void taia_now(struct taia *t) | ||
455 | { | ||
456 | struct timeval now; | ||
457 | gettimeofday(&now,(struct timezone *) 0); | ||
458 | tai_unix(&t->sec,now.tv_sec); | ||
459 | t->nano = 1000 * now.tv_usec + 500; | ||
460 | t->atto = 0; | ||
461 | } | ||
462 | |||
463 | |||
464 | /*** taia_pack.c ***/ | ||
465 | |||
466 | void taia_pack(char *s,const struct taia *t) | ||
467 | { | ||
468 | unsigned long x; | ||
469 | |||
470 | tai_pack(s,&t->sec); | ||
471 | s += 8; | ||
472 | |||
473 | x = t->atto; | ||
474 | s[7] = x & 255; x >>= 8; | ||
475 | s[6] = x & 255; x >>= 8; | ||
476 | s[5] = x & 255; x >>= 8; | ||
477 | s[4] = x; | ||
478 | x = t->nano; | ||
479 | s[3] = x & 255; x >>= 8; | ||
480 | s[2] = x & 255; x >>= 8; | ||
481 | s[1] = x & 255; x >>= 8; | ||
482 | s[0] = x; | ||
483 | } | ||
484 | |||
485 | |||
486 | /*** taia_sub.c ***/ | ||
487 | |||
488 | /* XXX: breaks tai encapsulation */ | ||
489 | |||
490 | void taia_sub(struct taia *t,const struct taia *u,const struct taia *v) | ||
491 | { | ||
492 | unsigned long unano = u->nano; | ||
493 | unsigned long uatto = u->atto; | ||
494 | |||
495 | t->sec.x = u->sec.x - v->sec.x; | ||
496 | t->nano = unano - v->nano; | ||
497 | t->atto = uatto - v->atto; | ||
498 | if (t->atto > uatto) { | ||
499 | t->atto += 1000000000UL; | ||
500 | --t->nano; | ||
501 | } | ||
502 | if (t->nano > unano) { | ||
503 | t->nano += 1000000000UL; | ||
504 | --t->sec.x; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | |||
509 | /*** taia_uint.c ***/ | ||
510 | |||
511 | /* XXX: breaks tai encapsulation */ | ||
512 | |||
513 | void taia_uint(struct taia *t,unsigned s) | ||
514 | { | ||
515 | t->sec.x = s; | ||
516 | t->nano = 0; | ||
517 | t->atto = 0; | ||
518 | } | ||
519 | |||
520 | |||
521 | /*** stralloc_cat.c ***/ | ||
522 | |||
523 | int stralloc_cat(stralloc *sato,const stralloc *safrom) | ||
524 | { | ||
525 | return stralloc_catb(sato,safrom->s,safrom->len); | ||
526 | } | ||
527 | |||
528 | |||
529 | /*** stralloc_catb.c ***/ | ||
530 | |||
531 | int stralloc_catb(stralloc *sa,const char *s,unsigned n) | ||
532 | { | ||
533 | if (!sa->s) return stralloc_copyb(sa,s,n); | ||
534 | if (!stralloc_readyplus(sa,n + 1)) return 0; | ||
535 | memcpy(sa->s + sa->len,s,n); | ||
536 | sa->len += n; | ||
537 | sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ | ||
538 | return 1; | ||
539 | } | ||
540 | |||
541 | |||
542 | /*** stralloc_cats.c ***/ | ||
543 | |||
544 | int stralloc_cats(stralloc *sa,const char *s) | ||
545 | { | ||
546 | return stralloc_catb(sa,s,strlen(s)); | ||
547 | } | ||
548 | |||
549 | |||
550 | /*** stralloc_eady.c ***/ | ||
551 | |||
552 | GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) | ||
553 | GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) | ||
554 | |||
555 | |||
556 | /*** stralloc_opyb.c ***/ | ||
557 | |||
558 | int stralloc_copyb(stralloc *sa,const char *s,unsigned n) | ||
559 | { | ||
560 | if (!stralloc_ready(sa,n + 1)) return 0; | ||
561 | memcpy(sa->s,s,n); | ||
562 | sa->len = n; | ||
563 | sa->s[n] = 'Z'; /* ``offensive programming'' */ | ||
564 | return 1; | ||
565 | } | ||
566 | |||
567 | |||
568 | /*** stralloc_opys.c ***/ | ||
569 | |||
570 | int stralloc_copys(stralloc *sa,const char *s) | ||
571 | { | ||
572 | return stralloc_copyb(sa,s,strlen(s)); | ||
573 | } | ||
574 | |||
575 | |||
576 | /*** stralloc_pend.c ***/ | ||
577 | |||
578 | GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) | ||
579 | |||
580 | |||
581 | /*** iopause.c ***/ | ||
582 | |||
583 | void iopause(iopause_fd *x,unsigned len,struct taia *deadline,struct taia *stamp) | ||
584 | { | ||
585 | struct taia t; | ||
586 | int millisecs; | ||
587 | double d; | ||
588 | int i; | ||
589 | |||
590 | if (taia_less(deadline,stamp)) | ||
591 | millisecs = 0; | ||
592 | else { | ||
593 | t = *stamp; | ||
594 | taia_sub(&t,deadline,&t); | ||
595 | d = taia_approx(&t); | ||
596 | if (d > 1000.0) d = 1000.0; | ||
597 | millisecs = d * 1000.0 + 20.0; | ||
598 | } | ||
599 | |||
600 | for (i = 0;i < len;++i) | ||
601 | x[i].revents = 0; | ||
602 | |||
603 | poll(x,len,millisecs); | ||
604 | /* XXX: some kernels apparently need x[0] even if len is 0 */ | ||
605 | /* XXX: how to handle EAGAIN? are kernels really this dumb? */ | ||
606 | /* XXX: how to handle EINVAL? when exactly can this happen? */ | ||
607 | } | ||
608 | |||
609 | |||
610 | /*** lock_ex.c ***/ | ||
611 | |||
612 | int lock_ex(int fd) | ||
613 | { | ||
614 | return flock(fd,LOCK_EX); | ||
615 | } | ||
616 | |||
617 | |||
618 | /*** lock_exnb.c ***/ | ||
619 | |||
620 | int lock_exnb(int fd) | ||
621 | { | ||
622 | return flock(fd,LOCK_EX | LOCK_NB); | ||
623 | } | ||
624 | |||
625 | |||
626 | /*** ndelay_off.c ***/ | ||
627 | |||
628 | int ndelay_off(int fd) | ||
629 | { | ||
630 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); | ||
631 | } | ||
632 | |||
633 | |||
634 | /*** ndelay_on.c ***/ | ||
635 | |||
636 | int ndelay_on(int fd) | ||
637 | { | ||
638 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); | ||
639 | } | ||
640 | |||
641 | |||
642 | /*** open_append.c ***/ | ||
643 | |||
644 | int open_append(const char *fn) | ||
645 | { | ||
646 | return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600); | ||
647 | } | ||
648 | |||
649 | |||
650 | /*** open_read.c ***/ | ||
651 | |||
652 | int open_read(const char *fn) | ||
653 | { | ||
654 | return open(fn,O_RDONLY | O_NDELAY); | ||
655 | } | ||
656 | |||
657 | |||
658 | /*** open_trunc.c ***/ | ||
659 | |||
660 | int open_trunc(const char *fn) | ||
661 | { | ||
662 | return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); | ||
663 | } | ||
664 | |||
665 | |||
666 | /*** open_write.c ***/ | ||
667 | |||
668 | int open_write(const char *fn) | ||
669 | { | ||
670 | return open(fn,O_WRONLY | O_NDELAY); | ||
671 | } | ||
672 | |||
673 | |||
674 | /*** openreadclose.c ***/ | ||
675 | |||
676 | int openreadclose(const char *fn,stralloc *sa,unsigned bufsize) | ||
677 | { | ||
678 | int fd; | ||
679 | fd = open_read(fn); | ||
680 | if (fd == -1) { | ||
681 | if (errno == ENOENT) return 0; | ||
682 | return -1; | ||
683 | } | ||
684 | if (readclose(fd,sa,bufsize) == -1) return -1; | ||
685 | return 1; | ||
686 | } | ||
687 | |||
688 | |||
689 | /*** pathexec_env.c ***/ | ||
690 | |||
691 | static stralloc plus; | ||
692 | static stralloc tmp; | ||
693 | |||
694 | int pathexec_env(const char *s,const char *t) | ||
695 | { | ||
696 | if (!s) return 1; | ||
697 | if (!stralloc_copys(&tmp,s)) return 0; | ||
698 | if (t) { | ||
699 | if (!stralloc_cats(&tmp,"=")) return 0; | ||
700 | if (!stralloc_cats(&tmp,t)) return 0; | ||
701 | } | ||
702 | if (!stralloc_0(&tmp)) return 0; | ||
703 | return stralloc_cat(&plus,&tmp); | ||
704 | } | ||
705 | |||
706 | void pathexec(char **argv) | ||
707 | { | ||
708 | char **e; | ||
709 | unsigned elen; | ||
710 | unsigned i; | ||
711 | unsigned j; | ||
712 | unsigned split; | ||
713 | unsigned t; | ||
714 | |||
715 | if (!stralloc_cats(&plus,"")) return; | ||
716 | |||
717 | elen = 0; | ||
718 | for (i = 0;environ[i];++i) | ||
719 | ++elen; | ||
720 | for (i = 0;i < plus.len;++i) | ||
721 | if (!plus.s[i]) | ||
722 | ++elen; | ||
723 | |||
724 | e = malloc((elen + 1) * sizeof(char *)); | ||
725 | if (!e) return; | ||
726 | |||
727 | elen = 0; | ||
728 | for (i = 0;environ[i];++i) | ||
729 | e[elen++] = environ[i]; | ||
730 | |||
731 | j = 0; | ||
732 | for (i = 0;i < plus.len;++i) | ||
733 | if (!plus.s[i]) { | ||
734 | split = str_chr(plus.s + j,'='); | ||
735 | for (t = 0;t < elen;++t) | ||
736 | if (memcmp(plus.s + j,e[t],split) == 0) | ||
737 | if (e[t][split] == '=') { | ||
738 | --elen; | ||
739 | e[t] = e[elen]; | ||
740 | break; | ||
741 | } | ||
742 | if (plus.s[j + split]) | ||
743 | e[elen++] = plus.s + j; | ||
744 | j = i + 1; | ||
745 | } | ||
746 | e[elen] = 0; | ||
747 | |||
748 | pathexec_run(*argv,argv,e); | ||
749 | free(e); | ||
750 | } | ||
751 | |||
752 | |||
753 | /*** pathexec_run.c ***/ | ||
754 | |||
755 | static stralloc tmp; | ||
756 | |||
757 | void pathexec_run(const char *file,char *const *argv,char *const *envp) | ||
758 | { | ||
759 | const char *path; | ||
760 | unsigned split; | ||
761 | int savederrno; | ||
762 | |||
763 | if (file[str_chr(file,'/')]) { | ||
764 | execve(file,argv,envp); | ||
765 | return; | ||
766 | } | ||
767 | |||
768 | path = getenv("PATH"); | ||
769 | if (!path) path = "/bin:/usr/bin"; | ||
770 | |||
771 | savederrno = 0; | ||
772 | for (;;) { | ||
773 | split = str_chr(path,':'); | ||
774 | if (!stralloc_copyb(&tmp,path,split)) return; | ||
775 | if (!split) | ||
776 | if (!stralloc_cats(&tmp,".")) return; | ||
777 | if (!stralloc_cats(&tmp,"/")) return; | ||
778 | if (!stralloc_cats(&tmp,file)) return; | ||
779 | if (!stralloc_0(&tmp)) return; | ||
780 | |||
781 | execve(tmp.s,argv,envp); | ||
782 | if (errno != ENOENT) { | ||
783 | savederrno = errno; | ||
784 | if ((errno != EACCES) && (errno != EPERM) && (errno != EISDIR)) return; | ||
785 | } | ||
786 | |||
787 | if (!path[split]) { | ||
788 | if (savederrno) errno = savederrno; | ||
789 | return; | ||
790 | } | ||
791 | path += split; | ||
792 | path += 1; | ||
793 | } | ||
794 | } | ||
795 | |||
796 | |||
797 | /*** pmatch.c ***/ | ||
798 | |||
799 | unsigned pmatch(const char *p, const char *s, unsigned len) { | ||
800 | for (;;) { | ||
801 | char c = *p++; | ||
802 | if (!c) return !len; | ||
803 | switch (c) { | ||
804 | case '*': | ||
805 | if (!(c = *p)) return 1; | ||
806 | for (;;) { | ||
807 | if (!len) return 0; | ||
808 | if (*s == c) break; | ||
809 | ++s; --len; | ||
810 | } | ||
811 | continue; | ||
812 | case '+': | ||
813 | if ((c = *p++) != *s) return 0; | ||
814 | for (;;) { | ||
815 | if (!len) return 1; | ||
816 | if (*s != c) break; | ||
817 | ++s; --len; | ||
818 | } | ||
819 | continue; | ||
820 | /* | ||
821 | case '?': | ||
822 | if (*p == '?') { | ||
823 | if (*s != '?') return 0; | ||
824 | ++p; | ||
825 | } | ||
826 | ++s; --len; | ||
827 | continue; | ||
828 | */ | ||
829 | default: | ||
830 | if (!len) return 0; | ||
831 | if (*s != c) return 0; | ||
832 | ++s; --len; | ||
833 | continue; | ||
834 | } | ||
835 | } | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | |||
840 | /*** prot.c ***/ | ||
841 | |||
842 | int prot_gid(int gid) | ||
843 | { | ||
844 | gid_t x = gid; | ||
845 | if (setgroups(1,&x) == -1) return -1; | ||
846 | return setgid(gid); /* _should_ be redundant, but on some systems it isn't */ | ||
847 | } | ||
848 | |||
849 | int prot_uid(int uid) | ||
850 | { | ||
851 | return setuid(uid); | ||
852 | } | ||
853 | |||
854 | |||
855 | /*** readclose.c ***/ | ||
856 | |||
857 | int readclose_append(int fd,stralloc *sa,unsigned bufsize) | ||
858 | { | ||
859 | int r; | ||
860 | for (;;) { | ||
861 | if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; } | ||
862 | r = read(fd,sa->s + sa->len,bufsize); | ||
863 | if (r == -1) if (errno == EINTR) continue; | ||
864 | if (r <= 0) { close(fd); return r; } | ||
865 | sa->len += r; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | int readclose(int fd,stralloc *sa,unsigned bufsize) | ||
870 | { | ||
871 | if (!stralloc_copys(sa,"")) { close(fd); return -1; } | ||
872 | return readclose_append(fd,sa,bufsize); | ||
873 | } | ||
874 | |||
875 | |||
876 | /*** scan_ulong.c ***/ | ||
877 | |||
878 | unsigned scan_ulong(const char *s,unsigned long *u) | ||
879 | { | ||
880 | unsigned pos = 0; | ||
881 | unsigned long result = 0; | ||
882 | unsigned long c; | ||
883 | while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) { | ||
884 | result = result * 10 + c; | ||
885 | ++pos; | ||
886 | } | ||
887 | *u = result; | ||
888 | return pos; | ||
889 | } | ||
890 | |||
891 | |||
892 | /*** seek_set.c ***/ | ||
893 | |||
894 | int seek_set(int fd,seek_pos pos) | ||
895 | { | ||
896 | if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; return 0; | ||
897 | } | ||
898 | |||
899 | |||
900 | /*** sig.c ***/ | ||
901 | |||
902 | int sig_alarm = SIGALRM; | ||
903 | int sig_child = SIGCHLD; | ||
904 | int sig_cont = SIGCONT; | ||
905 | int sig_hangup = SIGHUP; | ||
906 | int sig_int = SIGINT; | ||
907 | int sig_pipe = SIGPIPE; | ||
908 | int sig_term = SIGTERM; | ||
909 | |||
910 | void (*sig_defaulthandler)(int) = SIG_DFL; | ||
911 | void (*sig_ignorehandler)(int) = SIG_IGN; | ||
912 | |||
913 | |||
914 | /*** sig_block.c ***/ | ||
915 | |||
916 | void sig_block(int sig) | ||
917 | { | ||
918 | sigset_t ss; | ||
919 | sigemptyset(&ss); | ||
920 | sigaddset(&ss,sig); | ||
921 | sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0); | ||
922 | } | ||
923 | |||
924 | void sig_unblock(int sig) | ||
925 | { | ||
926 | sigset_t ss; | ||
927 | sigemptyset(&ss); | ||
928 | sigaddset(&ss,sig); | ||
929 | sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0); | ||
930 | } | ||
931 | |||
932 | void sig_blocknone(void) | ||
933 | { | ||
934 | sigset_t ss; | ||
935 | sigemptyset(&ss); | ||
936 | sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0); | ||
937 | } | ||
938 | |||
939 | |||
940 | /*** sig_catch.c ***/ | ||
941 | |||
942 | void sig_catch(int sig,void (*f)(int)) | ||
943 | { | ||
944 | struct sigaction sa; | ||
945 | sa.sa_handler = f; | ||
946 | sa.sa_flags = 0; | ||
947 | sigemptyset(&sa.sa_mask); | ||
948 | sigaction(sig,&sa,(struct sigaction *) 0); | ||
949 | } | ||
950 | |||
951 | |||
952 | /*** sig_pause.c ***/ | ||
953 | |||
954 | void sig_pause(void) | ||
955 | { | ||
956 | sigset_t ss; | ||
957 | sigemptyset(&ss); | ||
958 | sigsuspend(&ss); | ||
959 | } | ||
960 | |||
961 | |||
962 | /*** str_chr.c ***/ | ||
963 | |||
964 | unsigned str_chr(const char *s,int c) | ||
965 | { | ||
966 | char ch; | ||
967 | const char *t; | ||
968 | |||
969 | ch = c; | ||
970 | t = s; | ||
971 | for (;;) { | ||
972 | if (!*t) break; if (*t == ch) break; ++t; | ||
973 | if (!*t) break; if (*t == ch) break; ++t; | ||
974 | if (!*t) break; if (*t == ch) break; ++t; | ||
975 | if (!*t) break; if (*t == ch) break; ++t; | ||
976 | } | ||
977 | return t - s; | ||
978 | } | ||
979 | |||
980 | |||
981 | /*** wait_nohang.c ***/ | ||
982 | |||
983 | int wait_nohang(int *wstat) | ||
984 | { | ||
985 | return waitpid(-1,wstat,WNOHANG); | ||
986 | } | ||
987 | |||
988 | |||
989 | /*** wait_pid.c ***/ | ||
990 | |||
991 | int wait_pid(int *wstat, int pid) | ||
992 | { | ||
993 | int r; | ||
994 | |||
995 | do | ||
996 | r = waitpid(pid,wstat,0); | ||
997 | while ((r == -1) && (errno == EINTR)); | ||
998 | return r; | ||
999 | } | ||
diff --git a/runit/runit_lib.h b/runit/runit_lib.h new file mode 100644 index 000000000..d306164ea --- /dev/null +++ b/runit/runit_lib.h | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | Copyright (c) 2001-2006, Gerrit Pape | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | 1. Redistributions of source code must retain the above copyright notice, | ||
9 | this list of conditions and the following disclaimer. | ||
10 | 2. Redistributions in binary form must reproduce the above copyright | ||
11 | notice, this list of conditions and the following disclaimer in the | ||
12 | documentation and/or other materials provided with the distribution. | ||
13 | 3. The name of the author may not be used to endorse or promote products | ||
14 | derived from this software without specific prior written permission. | ||
15 | |||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | ||
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||
22 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
23 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | ||
25 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | /*** buffer.h ***/ | ||
29 | |||
30 | typedef struct buffer { | ||
31 | char *x; | ||
32 | unsigned p; | ||
33 | unsigned n; | ||
34 | int fd; | ||
35 | int (*op)(int fd,char *buf,unsigned len); | ||
36 | } buffer; | ||
37 | |||
38 | #define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } | ||
39 | #define BUFFER_INSIZE 8192 | ||
40 | #define BUFFER_OUTSIZE 8192 | ||
41 | |||
42 | extern void buffer_init(buffer *,int (*)(int fd,char *buf,unsigned len),int,char *,unsigned); | ||
43 | |||
44 | extern int buffer_flush(buffer *); | ||
45 | extern int buffer_put(buffer *,const char *,unsigned); | ||
46 | extern int buffer_putalign(buffer *,const char *,unsigned); | ||
47 | extern int buffer_putflush(buffer *,const char *,unsigned); | ||
48 | extern int buffer_puts(buffer *,const char *); | ||
49 | extern int buffer_putsalign(buffer *,const char *); | ||
50 | extern int buffer_putsflush(buffer *,const char *); | ||
51 | |||
52 | #define buffer_PUTC(s,c) \ | ||
53 | ( ((s)->n != (s)->p) \ | ||
54 | ? ( (s)->x[(s)->p++] = (c), 0 ) \ | ||
55 | : buffer_put((s),&(c),1) \ | ||
56 | ) | ||
57 | |||
58 | extern int buffer_get(buffer *,char *,unsigned); | ||
59 | extern int buffer_bget(buffer *,char *,unsigned); | ||
60 | extern int buffer_feed(buffer *); | ||
61 | |||
62 | extern char *buffer_peek(buffer *); | ||
63 | extern void buffer_seek(buffer *,unsigned); | ||
64 | |||
65 | #define buffer_PEEK(s) ( (s)->x + (s)->n ) | ||
66 | #define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) | ||
67 | |||
68 | #define buffer_GETC(s,c) \ | ||
69 | ( ((s)->p > 0) \ | ||
70 | ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \ | ||
71 | : buffer_get((s),(c),1) \ | ||
72 | ) | ||
73 | |||
74 | extern int buffer_copy(buffer *,buffer *); | ||
75 | |||
76 | extern int buffer_unixread(int,char *,unsigned); | ||
77 | /* Actually, int buffer_unixwrite(int,const char *,unsigned), | ||
78 | but that 'const' will produce warnings... oh well */ | ||
79 | extern int buffer_unixwrite(int,char *,unsigned); | ||
80 | |||
81 | |||
82 | /*** byte.h ***/ | ||
83 | |||
84 | extern unsigned byte_chr(char *s,unsigned n,int c); | ||
85 | |||
86 | |||
87 | /*** coe.h ***/ | ||
88 | |||
89 | extern int coe(int); | ||
90 | |||
91 | |||
92 | /*** direntry.h ***/ | ||
93 | |||
94 | #define direntry struct dirent | ||
95 | |||
96 | |||
97 | /*** fd.h ***/ | ||
98 | |||
99 | extern int fd_copy(int,int); | ||
100 | extern int fd_move(int,int); | ||
101 | |||
102 | |||
103 | /*** fifo.h ***/ | ||
104 | |||
105 | extern int fifo_make(const char *,int); | ||
106 | |||
107 | |||
108 | /*** fmt.h ***/ | ||
109 | |||
110 | #define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ | ||
111 | #define FMT_LEN ((char *) 0) /* convenient abbreviation */ | ||
112 | |||
113 | extern unsigned fmt_uint(char *,unsigned); | ||
114 | extern unsigned fmt_uint0(char *,unsigned,unsigned); | ||
115 | extern unsigned fmt_xint(char *,unsigned); | ||
116 | extern unsigned fmt_nbbint(char *,unsigned,unsigned,unsigned,unsigned); | ||
117 | extern unsigned fmt_ushort(char *,unsigned short); | ||
118 | extern unsigned fmt_xshort(char *,unsigned short); | ||
119 | extern unsigned fmt_nbbshort(char *,unsigned,unsigned,unsigned,unsigned short); | ||
120 | extern unsigned fmt_ulong(char *,unsigned long); | ||
121 | extern unsigned fmt_xlong(char *,unsigned long); | ||
122 | extern unsigned fmt_nbblong(char *,unsigned,unsigned,unsigned,unsigned long); | ||
123 | |||
124 | extern unsigned fmt_plusminus(char *,int); | ||
125 | extern unsigned fmt_minus(char *,int); | ||
126 | extern unsigned fmt_0x(char *,int); | ||
127 | |||
128 | extern unsigned fmt_str(char *,const char *); | ||
129 | extern unsigned fmt_strn(char *,const char *,unsigned); | ||
130 | |||
131 | |||
132 | /*** tai.h ***/ | ||
133 | |||
134 | struct tai { | ||
135 | uint64_t x; | ||
136 | } ; | ||
137 | |||
138 | #define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64_t) (u))) | ||
139 | |||
140 | extern void tai_now(struct tai *); | ||
141 | |||
142 | #define tai_approx(t) ((double) ((t)->x)) | ||
143 | |||
144 | extern void tai_add(struct tai *,const struct tai *,const struct tai *); | ||
145 | extern void tai_sub(struct tai *,const struct tai *,const struct tai *); | ||
146 | #define tai_less(t,u) ((t)->x < (u)->x) | ||
147 | |||
148 | #define TAI_PACK 8 | ||
149 | extern void tai_pack(char *,const struct tai *); | ||
150 | extern void tai_unpack(const char *,struct tai *); | ||
151 | |||
152 | extern void tai_uint(struct tai *,unsigned); | ||
153 | |||
154 | |||
155 | /*** taia.h ***/ | ||
156 | |||
157 | struct taia { | ||
158 | struct tai sec; | ||
159 | unsigned long nano; /* 0...999999999 */ | ||
160 | unsigned long atto; /* 0...999999999 */ | ||
161 | } ; | ||
162 | |||
163 | extern void taia_tai(const struct taia *,struct tai *); | ||
164 | |||
165 | extern void taia_now(struct taia *); | ||
166 | |||
167 | extern double taia_approx(const struct taia *); | ||
168 | extern double taia_frac(const struct taia *); | ||
169 | |||
170 | extern void taia_add(struct taia *,const struct taia *,const struct taia *); | ||
171 | extern void taia_addsec(struct taia *,const struct taia *,int); | ||
172 | extern void taia_sub(struct taia *,const struct taia *,const struct taia *); | ||
173 | extern void taia_half(struct taia *,const struct taia *); | ||
174 | extern int taia_less(const struct taia *,const struct taia *); | ||
175 | |||
176 | #define TAIA_PACK 16 | ||
177 | extern void taia_pack(char *,const struct taia *); | ||
178 | extern void taia_unpack(const char *,struct taia *); | ||
179 | |||
180 | #define TAIA_FMTFRAC 19 | ||
181 | extern unsigned taia_fmtfrac(char *,const struct taia *); | ||
182 | |||
183 | extern void taia_uint(struct taia *,unsigned); | ||
184 | |||
185 | |||
186 | /*** fmt_ptime.h ***/ | ||
187 | |||
188 | #define FMT_PTIME 30 | ||
189 | |||
190 | extern unsigned fmt_ptime(char *, struct taia *); | ||
191 | extern unsigned fmt_taia(char *, struct taia *); | ||
192 | |||
193 | |||
194 | /*** gen_alloc.h ***/ | ||
195 | |||
196 | #define GEN_ALLOC_typedef(ta,type,field,len,a) \ | ||
197 | typedef struct ta { type *field; unsigned len; unsigned a; } ta; | ||
198 | |||
199 | |||
200 | /*** gen_allocdefs.h ***/ | ||
201 | |||
202 | #define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ | ||
203 | int ta_ready(ta *x,unsigned n) \ | ||
204 | { unsigned i; \ | ||
205 | if (x->field) { \ | ||
206 | i = x->a; \ | ||
207 | if (n > i) { \ | ||
208 | x->a = base + n + (n >> 3); \ | ||
209 | x->field = realloc(x->field,x->a * sizeof(type)); \ | ||
210 | if (x->field) return 1; \ | ||
211 | x->a = i; return 0; } \ | ||
212 | return 1; } \ | ||
213 | x->len = 0; \ | ||
214 | return !!(x->field = malloc((x->a = n) * sizeof(type))); } | ||
215 | |||
216 | #define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ | ||
217 | int ta_rplus(ta *x,unsigned n) \ | ||
218 | { unsigned i; \ | ||
219 | if (x->field) { \ | ||
220 | i = x->a; n += x->len; \ | ||
221 | if (n > i) { \ | ||
222 | x->a = base + n + (n >> 3); \ | ||
223 | x->field = realloc(x->field,x->a * sizeof(type)); \ | ||
224 | if (x->field) return 1; \ | ||
225 | x->a = i; return 0; } \ | ||
226 | return 1; } \ | ||
227 | x->len = 0; \ | ||
228 | return !!(x->field = malloc((x->a = n) * sizeof(type))); } | ||
229 | |||
230 | #define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ | ||
231 | int ta_append(ta *x,const type *i) \ | ||
232 | { if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } | ||
233 | |||
234 | |||
235 | /*** stralloc.h ***/ | ||
236 | |||
237 | GEN_ALLOC_typedef(stralloc,char,s,len,a) | ||
238 | |||
239 | extern int stralloc_ready(stralloc *,unsigned); | ||
240 | extern int stralloc_readyplus(stralloc *,unsigned); | ||
241 | extern int stralloc_copy(stralloc *,const stralloc *); | ||
242 | extern int stralloc_cat(stralloc *,const stralloc *); | ||
243 | extern int stralloc_copys(stralloc *,const char *); | ||
244 | extern int stralloc_cats(stralloc *,const char *); | ||
245 | extern int stralloc_copyb(stralloc *,const char *,unsigned); | ||
246 | extern int stralloc_catb(stralloc *,const char *,unsigned); | ||
247 | extern int stralloc_append(stralloc *,const char *); /* beware: this takes a pointer to 1 char */ | ||
248 | extern int stralloc_starts(stralloc *,const char *); | ||
249 | |||
250 | #define stralloc_0(sa) stralloc_append(sa,"") | ||
251 | |||
252 | extern int stralloc_catulong0(stralloc *,unsigned long,unsigned); | ||
253 | extern int stralloc_catlong0(stralloc *,long,unsigned); | ||
254 | |||
255 | #define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0)) | ||
256 | #define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n))) | ||
257 | #define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n))) | ||
258 | #define stralloc_catint(sa,i) (stralloc_catlong0((sa),(i),0)) | ||
259 | |||
260 | |||
261 | /*** iopause.h ***/ | ||
262 | |||
263 | typedef struct pollfd iopause_fd; | ||
264 | #define IOPAUSE_READ POLLIN | ||
265 | #define IOPAUSE_WRITE POLLOUT | ||
266 | |||
267 | extern void iopause(iopause_fd *,unsigned,struct taia *,struct taia *); | ||
268 | |||
269 | |||
270 | /*** lock.h ***/ | ||
271 | |||
272 | extern int lock_ex(int); | ||
273 | extern int lock_un(int); | ||
274 | extern int lock_exnb(int); | ||
275 | |||
276 | |||
277 | /*** ndelay.h ***/ | ||
278 | |||
279 | extern int ndelay_on(int); | ||
280 | extern int ndelay_off(int); | ||
281 | |||
282 | |||
283 | /*** open.h ***/ | ||
284 | |||
285 | extern int open_read(const char *); | ||
286 | extern int open_excl(const char *); | ||
287 | extern int open_append(const char *); | ||
288 | extern int open_trunc(const char *); | ||
289 | extern int open_write(const char *); | ||
290 | |||
291 | |||
292 | /*** openreadclose.h ***/ | ||
293 | |||
294 | extern int openreadclose(const char *,stralloc *,unsigned); | ||
295 | |||
296 | |||
297 | /*** pathexec.h ***/ | ||
298 | |||
299 | extern void pathexec_run(const char *,char *const *,char *const *); | ||
300 | extern int pathexec_env(const char *,const char *); | ||
301 | extern void pathexec(char **); | ||
302 | |||
303 | |||
304 | /*** pmatch.h ***/ | ||
305 | |||
306 | extern unsigned pmatch(const char *, const char *, unsigned); | ||
307 | |||
308 | |||
309 | /*** prot.h ***/ | ||
310 | |||
311 | extern int prot_gid(int); | ||
312 | extern int prot_uid(int); | ||
313 | |||
314 | |||
315 | /*** readclose.h ***/ | ||
316 | |||
317 | extern int readclose_append(int,stralloc *,unsigned); | ||
318 | extern int readclose(int,stralloc *,unsigned); | ||
319 | |||
320 | |||
321 | /*** scan.h ***/ | ||
322 | |||
323 | extern unsigned scan_uint(const char *,unsigned *); | ||
324 | extern unsigned scan_xint(const char *,unsigned *); | ||
325 | extern unsigned scan_nbbint(const char *,unsigned,unsigned,unsigned,unsigned *); | ||
326 | extern unsigned scan_ushort(const char *,unsigned short *); | ||
327 | extern unsigned scan_xshort(const char *,unsigned short *); | ||
328 | extern unsigned scan_nbbshort(const char *,unsigned,unsigned,unsigned,unsigned short *); | ||
329 | extern unsigned scan_ulong(const char *,unsigned long *); | ||
330 | extern unsigned scan_xlong(const char *,unsigned long *); | ||
331 | extern unsigned scan_nbblong(const char *,unsigned,unsigned,unsigned,unsigned long *); | ||
332 | |||
333 | extern unsigned scan_plusminus(const char *,int *); | ||
334 | extern unsigned scan_0x(const char *,unsigned *); | ||
335 | |||
336 | extern unsigned scan_whitenskip(const char *,unsigned); | ||
337 | extern unsigned scan_nonwhitenskip(const char *,unsigned); | ||
338 | extern unsigned scan_charsetnskip(const char *,const char *,unsigned); | ||
339 | extern unsigned scan_noncharsetnskip(const char *,const char *,unsigned); | ||
340 | |||
341 | extern unsigned scan_strncmp(const char *,const char *,unsigned); | ||
342 | extern unsigned scan_memcmp(const char *,const char *,unsigned); | ||
343 | |||
344 | extern unsigned scan_long(const char *,long *); | ||
345 | extern unsigned scan_8long(const char *,unsigned long *); | ||
346 | |||
347 | |||
348 | /*** seek.h ***/ | ||
349 | |||
350 | typedef unsigned long seek_pos; | ||
351 | |||
352 | extern seek_pos seek_cur(int); | ||
353 | |||
354 | extern int seek_set(int,seek_pos); | ||
355 | extern int seek_end(int); | ||
356 | |||
357 | extern int seek_trunc(int,seek_pos); | ||
358 | |||
359 | #define seek_begin(fd) (seek_set((fd),(seek_pos) 0)) | ||
360 | |||
361 | |||
362 | /*** sig.h ***/ | ||
363 | |||
364 | extern int sig_alarm; | ||
365 | extern int sig_child; | ||
366 | extern int sig_cont; | ||
367 | extern int sig_hangup; | ||
368 | extern int sig_int; | ||
369 | extern int sig_pipe; | ||
370 | extern int sig_term; | ||
371 | |||
372 | extern void (*sig_defaulthandler)(int); | ||
373 | extern void (*sig_ignorehandler)(int); | ||
374 | |||
375 | extern void sig_catch(int,void (*)(int)); | ||
376 | #define sig_ignore(s) (sig_catch((s),sig_ignorehandler)) | ||
377 | #define sig_uncatch(s) (sig_catch((s),sig_defaulthandler)) | ||
378 | |||
379 | extern void sig_block(int); | ||
380 | extern void sig_unblock(int); | ||
381 | extern void sig_blocknone(void); | ||
382 | extern void sig_pause(void); | ||
383 | |||
384 | extern void sig_dfl(int); | ||
385 | |||
386 | |||
387 | /*** str.h ***/ | ||
388 | |||
389 | extern unsigned str_chr(const char *,int); /* never returns NULL */ | ||
390 | |||
391 | #define str_diff(s,t) strcmp((s),(t)) | ||
392 | #define str_equal(s,t) (!strcmp((s),(t))) | ||
393 | |||
394 | |||
395 | /*** wait.h ***/ | ||
396 | |||
397 | extern int wait_pid(int *wstat, int pid); | ||
398 | extern int wait_nohang(int *wstat); | ||
399 | |||
400 | #define wait_crashed(w) ((w) & 127) | ||
401 | #define wait_exitcode(w) ((w) >> 8) | ||
402 | #define wait_stopsig(w) ((w) >> 8) | ||
403 | #define wait_stopped(w) (((w) & 127) == 127) | ||
diff --git a/runit/svlogd.c b/runit/svlogd.c new file mode 100644 index 000000000..8e012d239 --- /dev/null +++ b/runit/svlogd.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* | ||
2 | Copyright (c) 2001-2006, Gerrit Pape | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | 1. Redistributions of source code must retain the above copyright notice, | ||
9 | this list of conditions and the following disclaimer. | ||
10 | 2. Redistributions in binary form must reproduce the above copyright | ||
11 | notice, this list of conditions and the following disclaimer in the | ||
12 | documentation and/or other materials provided with the distribution. | ||
13 | 3. The name of the author may not be used to endorse or promote products | ||
14 | derived from this software without specific prior written permission. | ||
15 | |||
16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | ||
19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||
22 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
23 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | ||
25 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ | ||
29 | /* TODO: depends on runit_lib.c - review and reduce/eliminate */ | ||
30 | |||
31 | #include <sys/poll.h> | ||
32 | #include <sys/file.h> | ||
33 | #include "busybox.h" | ||
34 | #include "runit_lib.h" | ||
35 | |||
36 | static unsigned verbose; | ||
37 | static int linemax = 1000; | ||
38 | static int buflen = 1024; | ||
39 | static int linelen; | ||
40 | |||
41 | static char **fndir; | ||
42 | static int fdwdir; | ||
43 | static int wstat; | ||
44 | static struct taia trotate; | ||
45 | |||
46 | static char *line; | ||
47 | static unsigned exitasap; | ||
48 | static unsigned rotateasap; | ||
49 | static unsigned reopenasap; | ||
50 | static unsigned linecomplete = 1; | ||
51 | static unsigned tmaxflag; | ||
52 | static iopause_fd in; | ||
53 | |||
54 | static const char *replace = ""; | ||
55 | static char repl; | ||
56 | |||
57 | static struct logdir { | ||
58 | char *btmp; | ||
59 | /* pattern list to match, in "aa\0bb\0\cc\0\0" form */ | ||
60 | char *inst; | ||
61 | char *processor; | ||
62 | char *name; | ||
63 | unsigned size; | ||
64 | unsigned sizemax; | ||
65 | unsigned nmax; | ||
66 | unsigned nmin; | ||
67 | /* int (not long) because of taia_uint() usage: */ | ||
68 | unsigned tmax; | ||
69 | int ppid; | ||
70 | int fddir; | ||
71 | int fdcur; | ||
72 | int fdlock; | ||
73 | struct taia trotate; | ||
74 | char fnsave[FMT_PTIME]; | ||
75 | char match; | ||
76 | char matcherr; | ||
77 | } *dir; | ||
78 | static unsigned dirn = 0; | ||
79 | |||
80 | #define FATAL "fatal: " | ||
81 | #define WARNING "warning: " | ||
82 | #define PAUSE "pausing: " | ||
83 | #define INFO "info: " | ||
84 | |||
85 | #define usage() bb_show_usage() | ||
86 | static void fatalx(char *m0) | ||
87 | { | ||
88 | bb_error_msg_and_die(FATAL"%s", m0); | ||
89 | } | ||
90 | static void warn(char *m0) { | ||
91 | bb_perror_msg(WARNING"%s", m0); | ||
92 | } | ||
93 | static void warn2(char *m0, char *m1) | ||
94 | { | ||
95 | bb_perror_msg(WARNING"%s: %s", m0, m1); | ||
96 | } | ||
97 | static void warnx(char *m0, char *m1) | ||
98 | { | ||
99 | bb_error_msg(WARNING"%s: %s", m0, m1); | ||
100 | } | ||
101 | static void pause_nomem(void) | ||
102 | { | ||
103 | bb_error_msg(PAUSE"out of memory"); sleep(3); | ||
104 | } | ||
105 | static void pause1cannot(char *m0) | ||
106 | { | ||
107 | bb_perror_msg(PAUSE"cannot %s", m0); sleep(3); | ||
108 | } | ||
109 | static void pause2cannot(char *m0, char *m1) | ||
110 | { | ||
111 | bb_perror_msg(PAUSE"cannot %s %s", m0, m1); | ||
112 | sleep(3); | ||
113 | } | ||
114 | |||
115 | static char* wstrdup(const char *str) | ||
116 | { | ||
117 | char *s; | ||
118 | while (!(s = strdup(str))) pause_nomem(); | ||
119 | return s; | ||
120 | } | ||
121 | |||
122 | static unsigned processorstart(struct logdir *ld) | ||
123 | { | ||
124 | int pid; | ||
125 | |||
126 | if (!ld->processor) return 0; | ||
127 | if (ld->ppid) { | ||
128 | warnx("processor already running", ld->name); | ||
129 | return 0; | ||
130 | } | ||
131 | while ((pid = fork()) == -1) | ||
132 | pause2cannot("fork for processor", ld->name); | ||
133 | if (!pid) { | ||
134 | char *prog[4]; | ||
135 | int fd; | ||
136 | |||
137 | /* child */ | ||
138 | sig_uncatch(sig_term); | ||
139 | sig_uncatch(sig_alarm); | ||
140 | sig_uncatch(sig_hangup); | ||
141 | sig_unblock(sig_term); | ||
142 | sig_unblock(sig_alarm); | ||
143 | sig_unblock(sig_hangup); | ||
144 | |||
145 | if (verbose) | ||
146 | bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave); | ||
147 | fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY); | ||
148 | if (fd_move(0, fd) == -1) | ||
149 | bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name); | ||
150 | ld->fnsave[26] = 't'; | ||
151 | fd = xopen3(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT, 0644); | ||
152 | if (fd_move(1, fd) == -1) | ||
153 | bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name); | ||
154 | fd = open_read("state"); | ||
155 | if (fd == -1) { | ||
156 | if (errno != ENOENT) | ||
157 | bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name); | ||
158 | close(xopen3("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT, 0644)); | ||
159 | fd = xopen("state", O_RDONLY|O_NDELAY); | ||
160 | } | ||
161 | if (fd_move(4, fd) == -1) | ||
162 | bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name); | ||
163 | fd = xopen3("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT, 0644); | ||
164 | if (fd_move(5, fd) == -1) | ||
165 | bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name); | ||
166 | |||
167 | prog[0] = "sh"; | ||
168 | prog[1] = "-c"; | ||
169 | prog[2] = ld->processor; | ||
170 | prog[3] = '\0'; | ||
171 | execve("/bin/sh", prog, environ); | ||
172 | bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name); | ||
173 | } | ||
174 | ld->ppid = pid; | ||
175 | return 1; | ||
176 | } | ||
177 | |||
178 | static unsigned processorstop(struct logdir *ld) | ||
179 | { | ||
180 | char f[28]; | ||
181 | |||
182 | if (ld->ppid) { | ||
183 | sig_unblock(sig_hangup); | ||
184 | while (wait_pid(&wstat, ld->ppid) == -1) | ||
185 | pause2cannot("wait for processor", ld->name); | ||
186 | sig_block(sig_hangup); | ||
187 | ld->ppid = 0; | ||
188 | } | ||
189 | if (ld->fddir == -1) return 1; | ||
190 | while (fchdir(ld->fddir) == -1) | ||
191 | pause2cannot("change directory, want processor", ld->name); | ||
192 | if (wait_exitcode(wstat) != 0) { | ||
193 | warnx("processor failed, restart", ld->name); | ||
194 | ld->fnsave[26] = 't'; | ||
195 | unlink(ld->fnsave); | ||
196 | ld->fnsave[26] = 'u'; | ||
197 | processorstart(ld); | ||
198 | while (fchdir(fdwdir) == -1) | ||
199 | pause1cannot("change to initial working directory"); | ||
200 | return ld->processor ? 0 : 1; | ||
201 | } | ||
202 | ld->fnsave[26] = 't'; | ||
203 | memcpy(f, ld->fnsave, 26); | ||
204 | f[26] = 's'; | ||
205 | f[27] = '\0'; | ||
206 | while (rename(ld->fnsave, f) == -1) | ||
207 | pause2cannot("rename processed", ld->name); | ||
208 | while (chmod(f, 0744) == -1) | ||
209 | pause2cannot("set mode of processed", ld->name); | ||
210 | ld->fnsave[26] = 'u'; | ||
211 | if (unlink(ld->fnsave) == -1) | ||
212 | bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave); | ||
213 | while (rename("newstate", "state") == -1) | ||
214 | pause2cannot("rename state", ld->name); | ||
215 | if (verbose) bb_error_msg(INFO"processed: %s/%s", ld->name, f); | ||
216 | while (fchdir(fdwdir) == -1) | ||
217 | pause1cannot("change to initial working directory"); | ||
218 | return 1; | ||
219 | } | ||
220 | |||
221 | static void rmoldest(struct logdir *ld) | ||
222 | { | ||
223 | DIR *d; | ||
224 | struct dirent *f; | ||
225 | char oldest[FMT_PTIME]; | ||
226 | int n = 0; | ||
227 | |||
228 | oldest[0] = 'A'; oldest[1] = oldest[27] = 0; | ||
229 | while (!(d = opendir("."))) | ||
230 | pause2cannot("open directory, want rotate", ld->name); | ||
231 | errno = 0; | ||
232 | while ((f = readdir(d))) { | ||
233 | if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) { | ||
234 | if (f->d_name[26] == 't') { | ||
235 | if (unlink(f->d_name) == -1) | ||
236 | warn2("cannot unlink processor leftover", f->d_name); | ||
237 | } else { | ||
238 | ++n; | ||
239 | if (strcmp(f->d_name, oldest) < 0) | ||
240 | memcpy(oldest, f->d_name, 27); | ||
241 | } | ||
242 | errno = 0; | ||
243 | } | ||
244 | } | ||
245 | if (errno) warn2("cannot read directory", ld->name); | ||
246 | closedir(d); | ||
247 | |||
248 | if (ld->nmax && (n > ld->nmax)) { | ||
249 | if (verbose) bb_error_msg(INFO"delete: %s/%s", ld->name, oldest); | ||
250 | if ((*oldest == '@') && (unlink(oldest) == -1)) | ||
251 | warn2("cannot unlink oldest logfile", ld->name); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | static unsigned rotate(struct logdir *ld) | ||
256 | { | ||
257 | struct stat st; | ||
258 | struct taia now; | ||
259 | |||
260 | if (ld->fddir == -1) { | ||
261 | ld->tmax = 0; | ||
262 | return 0; | ||
263 | } | ||
264 | if (ld->ppid) | ||
265 | while(!processorstop(ld)) | ||
266 | /* wait */; | ||
267 | |||
268 | while (fchdir(ld->fddir) == -1) | ||
269 | pause2cannot("change directory, want rotate", ld->name); | ||
270 | |||
271 | /* create new filename */ | ||
272 | ld->fnsave[25] = '.'; | ||
273 | ld->fnsave[26] = 's'; | ||
274 | if (ld->processor) | ||
275 | ld->fnsave[26] = 'u'; | ||
276 | ld->fnsave[27] = '\0'; | ||
277 | do { | ||
278 | taia_now(&now); | ||
279 | fmt_taia(ld->fnsave, &now); | ||
280 | errno = 0; | ||
281 | } while ((stat(ld->fnsave, &st) != -1) || (errno != ENOENT)); | ||
282 | |||
283 | if (ld->tmax && taia_less(&ld->trotate, &now)) { | ||
284 | taia_uint(&ld->trotate, ld->tmax); | ||
285 | taia_add(&ld->trotate, &now, &ld->trotate); | ||
286 | if (taia_less(&ld->trotate, &trotate)) | ||
287 | trotate = ld->trotate; | ||
288 | } | ||
289 | |||
290 | if (ld->size > 0) { | ||
291 | while (fsync(ld->fdcur) == -1) | ||
292 | pause2cannot("fsync current logfile", ld->name); | ||
293 | while (fchmod(ld->fdcur, 0744) == -1) | ||
294 | pause2cannot("set mode of current", ld->name); | ||
295 | close(ld->fdcur); | ||
296 | if (verbose) { | ||
297 | bb_error_msg(INFO"rename: %s/current %s %u", ld->name, | ||
298 | ld->fnsave, ld->size); | ||
299 | } | ||
300 | while (rename("current", ld->fnsave) == -1) | ||
301 | pause2cannot("rename current", ld->name); | ||
302 | while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1) | ||
303 | pause2cannot("create new current", ld->name); | ||
304 | coe(ld->fdcur); | ||
305 | ld->size = 0; | ||
306 | while (fchmod(ld->fdcur, 0644) == -1) | ||
307 | pause2cannot("set mode of current", ld->name); | ||
308 | rmoldest(ld); | ||
309 | processorstart(ld); | ||
310 | } | ||
311 | |||
312 | while (fchdir(fdwdir) == -1) | ||
313 | pause1cannot("change to initial working directory"); | ||
314 | return 1; | ||
315 | } | ||
316 | |||
317 | static int buffer_pwrite(int n, char *s, unsigned len) | ||
318 | { | ||
319 | int i; | ||
320 | struct logdir *ld = &dir[n]; | ||
321 | |||
322 | if (ld->sizemax) { | ||
323 | if (ld->size >= ld->sizemax) | ||
324 | rotate(ld); | ||
325 | if (len > (ld->sizemax - ld->size)) | ||
326 | len = ld->sizemax - ld->size; | ||
327 | } | ||
328 | while ((i = write(ld->fdcur, s, len)) == -1) { | ||
329 | if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) { | ||
330 | DIR *d; | ||
331 | struct dirent *f; | ||
332 | char oldest[FMT_PTIME]; | ||
333 | int j = 0; | ||
334 | |||
335 | while (fchdir(ld->fddir) == -1) | ||
336 | pause2cannot("change directory, want remove old logfile", | ||
337 | ld->name); | ||
338 | oldest[0] = 'A'; | ||
339 | oldest[1] = oldest[27] = '\0'; | ||
340 | while (!(d = opendir("."))) | ||
341 | pause2cannot("open directory, want remove old logfile", | ||
342 | ld->name); | ||
343 | errno = 0; | ||
344 | while ((f = readdir(d))) | ||
345 | if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) { | ||
346 | ++j; | ||
347 | if (strcmp(f->d_name, oldest) < 0) | ||
348 | memcpy(oldest, f->d_name, 27); | ||
349 | } | ||
350 | if (errno) warn2("cannot read directory, want remove old logfile", | ||
351 | ld->name); | ||
352 | closedir(d); | ||
353 | errno = ENOSPC; | ||
354 | if (j > ld->nmin) { | ||
355 | if (*oldest == '@') { | ||
356 | bb_error_msg(WARNING"out of disk space, delete: %s/%s", | ||
357 | ld->name, oldest); | ||
358 | errno = 0; | ||
359 | if (unlink(oldest) == -1) { | ||
360 | warn2("cannot unlink oldest logfile", ld->name); | ||
361 | errno = ENOSPC; | ||
362 | } | ||
363 | while (fchdir(fdwdir) == -1) | ||
364 | pause1cannot("change to initial working directory"); | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | if (errno) pause2cannot("write to current", ld->name); | ||
369 | } | ||
370 | |||
371 | ld->size += i; | ||
372 | if (ld->sizemax) | ||
373 | if (s[i-1] == '\n') | ||
374 | if (ld->size >= (ld->sizemax - linemax)) | ||
375 | rotate(ld); | ||
376 | return i; | ||
377 | } | ||
378 | |||
379 | static void logdir_close(struct logdir *ld) | ||
380 | { | ||
381 | if (ld->fddir == -1) | ||
382 | return; | ||
383 | if (verbose) | ||
384 | bb_error_msg(INFO"close: %s", ld->name); | ||
385 | close(ld->fddir); | ||
386 | ld->fddir = -1; | ||
387 | if (ld->fdcur == -1) | ||
388 | return; /* impossible */ | ||
389 | while (fsync(ld->fdcur) == -1) | ||
390 | pause2cannot("fsync current logfile", ld->name); | ||
391 | while (fchmod(ld->fdcur, 0744) == -1) | ||
392 | pause2cannot("set mode of current", ld->name); | ||
393 | close(ld->fdcur); | ||
394 | ld->fdcur = -1; | ||
395 | if (ld->fdlock == -1) | ||
396 | return; /* impossible */ | ||
397 | close(ld->fdlock); | ||
398 | ld->fdlock = -1; | ||
399 | free(ld->processor); | ||
400 | ld->processor = NULL; | ||
401 | } | ||
402 | |||
403 | static unsigned logdir_open(struct logdir *ld, const char *fn) | ||
404 | { | ||
405 | char buf[128]; | ||
406 | struct taia now; | ||
407 | char *new, *s, *np; | ||
408 | int i; | ||
409 | struct stat st; | ||
410 | |||
411 | ld->fddir = open(fn, O_RDONLY|O_NDELAY); | ||
412 | if (ld->fddir == -1) { | ||
413 | warn2("cannot open log directory", (char*)fn); | ||
414 | return 0; | ||
415 | } | ||
416 | coe(ld->fddir); | ||
417 | if (fchdir(ld->fddir) == -1) { | ||
418 | logdir_close(ld); | ||
419 | warn2("cannot change directory", (char*)fn); | ||
420 | return 0; | ||
421 | } | ||
422 | ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); | ||
423 | if ((ld->fdlock == -1) | ||
424 | || (lock_exnb(ld->fdlock) == -1) | ||
425 | ) { | ||
426 | logdir_close(ld); | ||
427 | warn2("cannot lock directory", (char*)fn); | ||
428 | while (fchdir(fdwdir) == -1) | ||
429 | pause1cannot("change to initial working directory"); | ||
430 | return 0; | ||
431 | } | ||
432 | coe(ld->fdlock); | ||
433 | |||
434 | ld->size = 0; | ||
435 | ld->sizemax = 1000000; | ||
436 | ld->nmax = ld->nmin = 10; | ||
437 | ld->tmax = 0; | ||
438 | ld->name = (char*)fn; | ||
439 | ld->ppid = 0; | ||
440 | ld->match = '+'; | ||
441 | free(ld->inst); ld->inst = NULL; | ||
442 | free(ld->processor); ld->processor = NULL; | ||
443 | |||
444 | /* read config */ | ||
445 | i = open_read_close("config", buf, sizeof(buf)); | ||
446 | if (i < 0) | ||
447 | warn2("cannot read config", ld->name); | ||
448 | if (i > 0) { | ||
449 | if (verbose) bb_error_msg(INFO"read: %s/config", ld->name); | ||
450 | s = buf; | ||
451 | while (s) { | ||
452 | np = strchr(s, '\n'); | ||
453 | if (np) *np++ = '\0'; | ||
454 | switch (s[0]) { | ||
455 | case '+': | ||
456 | case '-': | ||
457 | case 'e': | ||
458 | case 'E': | ||
459 | while (1) { | ||
460 | int l = asprintf(&new, "%s%s\n", ld->inst?:"", s); | ||
461 | if (l >= 0 && new) break; | ||
462 | pause_nomem(); | ||
463 | } | ||
464 | free(ld->inst); | ||
465 | ld->inst = new; | ||
466 | break; | ||
467 | case 's': { | ||
468 | static const struct suffix_mult km_suffixes[] = { | ||
469 | { "k", 1024 }, | ||
470 | { "m", 1024*1024 }, | ||
471 | { NULL, 0 } | ||
472 | }; | ||
473 | ld->sizemax = xatou_sfx(&s[1], km_suffixes); | ||
474 | break; | ||
475 | } | ||
476 | case 'n': | ||
477 | ld->nmax = xatoi_u(&s[1]); | ||
478 | break; | ||
479 | case 'N': | ||
480 | ld->nmin = xatoi_u(&s[1]); | ||
481 | break; | ||
482 | case 't': { | ||
483 | static const struct suffix_mult mh_suffixes[] = { | ||
484 | { "m", 60 }, | ||
485 | { "h", 60*60 }, | ||
486 | /*{ "d", 24*60*60 },*/ | ||
487 | { NULL, 0 } | ||
488 | }; | ||
489 | ld->tmax = xatou_sfx(&s[1], mh_suffixes); | ||
490 | if (ld->tmax) { | ||
491 | taia_uint(&ld->trotate, ld->tmax); | ||
492 | taia_add(&ld->trotate, &now, &ld->trotate); | ||
493 | if (!tmaxflag || taia_less(&ld->trotate, &trotate)) | ||
494 | trotate = ld->trotate; | ||
495 | tmaxflag = 1; | ||
496 | } | ||
497 | break; | ||
498 | } | ||
499 | case '!': | ||
500 | if (s[1]) { | ||
501 | free(ld->processor); | ||
502 | ld->processor = wstrdup(s); | ||
503 | } | ||
504 | break; | ||
505 | } | ||
506 | s = np; | ||
507 | } | ||
508 | /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */ | ||
509 | s = ld->inst; | ||
510 | while (s) { | ||
511 | np = strchr(s, '\n'); | ||
512 | if (np) *np++ = '\0'; | ||
513 | s = np; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* open current */ | ||
518 | i = stat("current", &st); | ||
519 | if (i != -1) { | ||
520 | if (st.st_size && ! (st.st_mode & S_IXUSR)) { | ||
521 | ld->fnsave[25] = '.'; | ||
522 | ld->fnsave[26] = 'u'; | ||
523 | ld->fnsave[27] = '\0'; | ||
524 | do { | ||
525 | taia_now(&now); | ||
526 | fmt_taia(ld->fnsave, &now); | ||
527 | errno = 0; | ||
528 | } while ((stat(ld->fnsave, &st) != -1) || (errno != ENOENT)); | ||
529 | while (rename("current", ld->fnsave) == -1) | ||
530 | pause2cannot("rename current", ld->name); | ||
531 | rmoldest(ld); | ||
532 | i = -1; | ||
533 | } else { | ||
534 | /* Be paranoid: st.st_size can be not just bigger, but WIDER! */ | ||
535 | /* (bug in original svlogd. remove this comment when fixed there) */ | ||
536 | ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size; | ||
537 | } | ||
538 | } else { | ||
539 | if (errno != ENOENT) { | ||
540 | logdir_close(ld); | ||
541 | warn2("cannot stat current", ld->name); | ||
542 | while (fchdir(fdwdir) == -1) | ||
543 | pause1cannot("change to initial working directory"); | ||
544 | return 0; | ||
545 | } | ||
546 | } | ||
547 | while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1) | ||
548 | pause2cannot("open current", ld->name); | ||
549 | coe(ld->fdcur); | ||
550 | while (fchmod(ld->fdcur, 0644) == -1) | ||
551 | pause2cannot("set mode of current", ld->name); | ||
552 | |||
553 | if (verbose) { | ||
554 | if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name); | ||
555 | else bb_error_msg(INFO"new: %s/current", ld->name); | ||
556 | } | ||
557 | |||
558 | while (fchdir(fdwdir) == -1) | ||
559 | pause1cannot("change to initial working directory"); | ||
560 | return 1; | ||
561 | } | ||
562 | |||
563 | static void logdirs_reopen(void) | ||
564 | { | ||
565 | struct taia now; | ||
566 | int l; | ||
567 | int ok = 0; | ||
568 | |||
569 | tmaxflag = 0; | ||
570 | taia_now(&now); | ||
571 | for (l = 0; l < dirn; ++l) { | ||
572 | logdir_close(&dir[l]); | ||
573 | if (logdir_open(&dir[l], fndir[l])) ok = 1; | ||
574 | } | ||
575 | if (!ok) fatalx("no functional log directories"); | ||
576 | } | ||
577 | |||
578 | /* Used for reading stdin */ | ||
579 | static int buffer_pread(int fd, char *s, unsigned len) | ||
580 | { | ||
581 | struct taia now; | ||
582 | int i; | ||
583 | |||
584 | if (rotateasap) { | ||
585 | for (i = 0; i < dirn; ++i) | ||
586 | rotate(dir+i); | ||
587 | rotateasap = 0; | ||
588 | } | ||
589 | if (exitasap) { | ||
590 | if (linecomplete) | ||
591 | return 0; | ||
592 | len = 1; | ||
593 | } | ||
594 | if (reopenasap) { | ||
595 | logdirs_reopen(); | ||
596 | reopenasap = 0; | ||
597 | } | ||
598 | taia_now(&now); | ||
599 | taia_uint(&trotate, 2744); | ||
600 | taia_add(&trotate, &now, &trotate); | ||
601 | for (i = 0; i < dirn; ++i) | ||
602 | if (dir[i].tmax) { | ||
603 | if (taia_less(&dir[i].trotate, &now)) | ||
604 | rotate(dir+i); | ||
605 | if (taia_less(&dir[i].trotate, &trotate)) | ||
606 | trotate = dir[i].trotate; | ||
607 | } | ||
608 | |||
609 | while (1) { | ||
610 | /* Comment? */ | ||
611 | sig_unblock(sig_term); | ||
612 | sig_unblock(sig_child); | ||
613 | sig_unblock(sig_alarm); | ||
614 | sig_unblock(sig_hangup); | ||
615 | iopause(&in, 1, &trotate, &now); | ||
616 | sig_block(sig_term); | ||
617 | sig_block(sig_child); | ||
618 | sig_block(sig_alarm); | ||
619 | sig_block(sig_hangup); | ||
620 | i = safe_read(fd, s, len); | ||
621 | if (i >= 0) break; | ||
622 | if (errno != EAGAIN) { | ||
623 | warn("cannot read standard input"); | ||
624 | break; | ||
625 | } | ||
626 | /* else: EAGAIN - normal, repeat silently */ | ||
627 | } | ||
628 | |||
629 | if (i > 0) { | ||
630 | int cnt; | ||
631 | linecomplete = (s[i-1] == '\n'); | ||
632 | if (!repl) return i; | ||
633 | |||
634 | cnt = i; | ||
635 | while (--cnt >= 0) { | ||
636 | char ch = *s; | ||
637 | if (ch != '\n') { | ||
638 | if (ch < 32 || ch > 126) | ||
639 | *s = repl; | ||
640 | else { | ||
641 | int j; | ||
642 | for (j = 0; replace[j]; ++j) { | ||
643 | if (ch == replace[j]) { | ||
644 | *s = repl; | ||
645 | break; | ||
646 | } | ||
647 | } | ||
648 | } | ||
649 | } | ||
650 | s++; | ||
651 | } | ||
652 | } | ||
653 | return i; | ||
654 | } | ||
655 | |||
656 | |||
657 | static void sig_term_handler(int sig_no) | ||
658 | { | ||
659 | if (verbose) | ||
660 | bb_error_msg(INFO"sig%s received", "term"); | ||
661 | exitasap = 1; | ||
662 | } | ||
663 | |||
664 | static void sig_child_handler(int sig_no) | ||
665 | { | ||
666 | int pid, l; | ||
667 | |||
668 | if (verbose) | ||
669 | bb_error_msg(INFO"sig%s received", "child"); | ||
670 | while ((pid = wait_nohang(&wstat)) > 0) | ||
671 | for (l = 0; l < dirn; ++l) | ||
672 | if (dir[l].ppid == pid) { | ||
673 | dir[l].ppid = 0; | ||
674 | processorstop(&dir[l]); | ||
675 | break; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | static void sig_alarm_handler(int sig_no) | ||
680 | { | ||
681 | if (verbose) | ||
682 | bb_error_msg(INFO"sig%s received", "alarm"); | ||
683 | rotateasap = 1; | ||
684 | } | ||
685 | |||
686 | static void sig_hangup_handler(int sig_no) | ||
687 | { | ||
688 | if (verbose) | ||
689 | bb_error_msg(INFO"sig%s received", "hangup"); | ||
690 | reopenasap = 1; | ||
691 | } | ||
692 | |||
693 | static void logmatch(struct logdir *ld) | ||
694 | { | ||
695 | char *s; | ||
696 | |||
697 | ld->match = '+'; | ||
698 | ld->matcherr = 'E'; | ||
699 | s = ld->inst; | ||
700 | while (s && s[0]) { | ||
701 | switch (s[0]) { | ||
702 | case '+': | ||
703 | case '-': | ||
704 | if (pmatch(s+1, line, linelen)) | ||
705 | ld->match = s[0]; | ||
706 | break; | ||
707 | case 'e': | ||
708 | case 'E': | ||
709 | if (pmatch(s+1, line, linelen)) | ||
710 | ld->matcherr = s[0]; | ||
711 | break; | ||
712 | } | ||
713 | s += strlen(s) + 1; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | int svlogd_main(int argc, char **argv) | ||
718 | { | ||
719 | struct taia now; | ||
720 | char *r,*l,*b; | ||
721 | ssize_t stdin_cnt = 0; | ||
722 | int i; | ||
723 | unsigned opt; | ||
724 | unsigned timestamp = 0; | ||
725 | |||
726 | opt_complementary = "tt:vv"; | ||
727 | opt = getopt32(argc, argv, "r:R:l:b:tv", | ||
728 | &r, &replace, &l, &b, ×tamp, &verbose); | ||
729 | if (opt & 1) { // -r | ||
730 | repl = r[0]; | ||
731 | if (!repl || r[1]) usage(); | ||
732 | } | ||
733 | if (opt & 2) if (!repl) repl = '_'; // -R | ||
734 | if (opt & 4) { // -l | ||
735 | linemax = xatou_range(l, 0, 1000); | ||
736 | if (linemax == 0) linemax = 1000; | ||
737 | if (linemax < 256) linemax = 256; | ||
738 | } | ||
739 | if (opt & 8) { // -b | ||
740 | buflen = xatoi_u(b); | ||
741 | if (buflen == 0) buflen = 1024; | ||
742 | } | ||
743 | //if (opt & 0x10) timestamp++; // -t | ||
744 | //if (opt & 0x20) verbose++; // -v | ||
745 | if (timestamp > 2) timestamp = 2; | ||
746 | argv += optind; | ||
747 | argc -= optind; | ||
748 | |||
749 | dirn = argc; | ||
750 | if (dirn <= 0) usage(); | ||
751 | if (buflen <= linemax) usage(); | ||
752 | fdwdir = xopen(".", O_RDONLY|O_NDELAY); | ||
753 | coe(fdwdir); | ||
754 | dir = xmalloc(dirn * sizeof(struct logdir)); | ||
755 | for (i = 0; i < dirn; ++i) { | ||
756 | dir[i].fddir = -1; | ||
757 | dir[i].fdcur = -1; | ||
758 | dir[i].btmp = xmalloc(buflen); | ||
759 | dir[i].ppid = 0; | ||
760 | } | ||
761 | line = xmalloc(linemax + (timestamp ? 26 : 0)); | ||
762 | fndir = argv; | ||
763 | in.fd = 0; | ||
764 | in.events = IOPAUSE_READ; | ||
765 | ndelay_on(in.fd); | ||
766 | |||
767 | sig_block(sig_term); | ||
768 | sig_block(sig_child); | ||
769 | sig_block(sig_alarm); | ||
770 | sig_block(sig_hangup); | ||
771 | sig_catch(sig_term, sig_term_handler); | ||
772 | sig_catch(sig_child, sig_child_handler); | ||
773 | sig_catch(sig_alarm, sig_alarm_handler); | ||
774 | sig_catch(sig_hangup, sig_hangup_handler); | ||
775 | |||
776 | logdirs_reopen(); | ||
777 | |||
778 | /* Each iteration processes one line */ | ||
779 | while (1) { | ||
780 | int printlen; | ||
781 | char *lineptr = line; | ||
782 | char *np; | ||
783 | char ch; | ||
784 | |||
785 | /* Prepare timestamp if needed */ | ||
786 | if (timestamp) { | ||
787 | char stamp[FMT_PTIME]; | ||
788 | taia_now(&now); | ||
789 | switch (timestamp) { | ||
790 | case 1: | ||
791 | fmt_taia(stamp, &now); | ||
792 | break; | ||
793 | default: /* case 2: */ | ||
794 | fmt_ptime(stamp, &now); | ||
795 | break; | ||
796 | } | ||
797 | memcpy(line, stamp, 25); | ||
798 | line[25] = ' '; | ||
799 | lineptr += 26; | ||
800 | } | ||
801 | |||
802 | /* lineptr[0..linemax-1] - buffer for stdin */ | ||
803 | /* (possibly has some unprocessed data from prev loop) */ | ||
804 | |||
805 | /* Refill the buffer if needed */ | ||
806 | np = memchr(lineptr, '\n', stdin_cnt); | ||
807 | i = linemax - stdin_cnt; /* avail. bytes at tail */ | ||
808 | if (i >= 128 && !exitasap && !np) { | ||
809 | int sz = buffer_pread(0, lineptr + stdin_cnt, i); | ||
810 | if (sz <= 0) /* EOF or error on stdin */ | ||
811 | exitasap = 1; | ||
812 | else { | ||
813 | stdin_cnt += sz; | ||
814 | np = memchr(lineptr, '\n', stdin_cnt); | ||
815 | } | ||
816 | } | ||
817 | if (stdin_cnt <= 0 && exitasap) | ||
818 | break; | ||
819 | |||
820 | /* Search for '\n' (in fact, np already holds the result) */ | ||
821 | linelen = stdin_cnt; | ||
822 | if (np) linelen = np - lineptr + 1; | ||
823 | /* linelen == no of chars incl. '\n' (or == stdin_cnt) */ | ||
824 | ch = lineptr[linelen-1]; | ||
825 | |||
826 | printlen = linelen + (timestamp ? 26 : 0); | ||
827 | /* write out line[0..printlen-1] to each log destination */ | ||
828 | for (i = 0; i < dirn; ++i) { | ||
829 | struct logdir *ld = &dir[i]; | ||
830 | if (ld->fddir == -1) continue; | ||
831 | if (ld->inst) | ||
832 | logmatch(ld); | ||
833 | if (ld->matcherr == 'e') { | ||
834 | fprintf(stderr, "%.*s%s", | ||
835 | printlen, line, | ||
836 | (ch != '\n') ? "...\n" : "" | ||
837 | ); | ||
838 | } | ||
839 | if (ld->match != '+') continue; | ||
840 | buffer_pwrite(i, line, printlen); | ||
841 | } | ||
842 | |||
843 | /* If we didn't see '\n' (long input line), */ | ||
844 | /* read/write repeatedly until we see it */ | ||
845 | while (ch != '\n') { | ||
846 | /* lineptr is emptied now, safe to use as buffer */ | ||
847 | stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax); | ||
848 | if (stdin_cnt <= 0) { /* EOF or error on stdin */ | ||
849 | lineptr[0] = ch = '\n'; | ||
850 | linelen = 1; | ||
851 | exitasap = 1; | ||
852 | stdin_cnt = 1; | ||
853 | } else { | ||
854 | linelen = stdin_cnt; | ||
855 | np = memchr(lineptr, '\n', stdin_cnt); | ||
856 | if (np) linelen = np - lineptr + 1; | ||
857 | ch = lineptr[linelen-1]; | ||
858 | } | ||
859 | /* linelen == no of chars incl. '\n' (or == stdin_cnt) */ | ||
860 | for (i = 0; i < dirn; ++i) { | ||
861 | if (dir[i].fddir == -1) continue; | ||
862 | if (dir[i].match != '+') continue; | ||
863 | buffer_pwrite(i, lineptr, linelen); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | /* Move unprocessed data to the front of line */ | ||
868 | stdin_cnt -= linelen; | ||
869 | if (stdin_cnt > 0) /* TODO: slow if buffer is big */ | ||
870 | memmove(lineptr, &lineptr[linelen], stdin_cnt); | ||
871 | } | ||
872 | |||
873 | for (i = 0; i < dirn; ++i) { | ||
874 | if (dir[i].ppid) | ||
875 | while (!processorstop(&dir[i])) | ||
876 | /* repeat */; | ||
877 | logdir_close(&dir[i]); | ||
878 | } | ||
879 | _exit(0); | ||
880 | } | ||