aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-16 02:27:24 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-16 02:27:24 +0000
commit39c36b524f83cae7c64bdd2d91c59f30d9cb6243 (patch)
tree3a5f790604219213666cbf5cccd747c02528912c
parent2ec77e221f3354928e99e307932dc4ae812dc433 (diff)
downloadbusybox-w32-39c36b524f83cae7c64bdd2d91c59f30d9cb6243.tar.gz
busybox-w32-39c36b524f83cae7c64bdd2d91c59f30d9cb6243.tar.bz2
busybox-w32-39c36b524f83cae7c64bdd2d91c59f30d9cb6243.zip
svlogd: new applet. +9k. Still too big, but it was 12k yesterday.
git-svn-id: svn://busybox.net/trunk/busybox@16535 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--console-tools/loadfont.c2
-rw-r--r--include/applets.h1
-rw-r--r--include/libbb.h2
-rw-r--r--include/usage.h7
-rw-r--r--libbb/xatol.c10
-rw-r--r--runit/Config.in8
-rw-r--r--runit/Kbuild1
-rw-r--r--runit/chpst.c47
-rw-r--r--runit/runit_lib.c999
-rw-r--r--runit/runit_lib.h403
-rw-r--r--runit/svlogd.c880
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
13enum{ 13enum {
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))
270USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS)) 270USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS))
271USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER)) 271USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER))
272USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 272USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
273USE_SVLOGD(APPLET(svlogd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
273USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff)) 274USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff))
274USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon)) 275USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon))
275USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) 276USE_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);
335long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes); 335long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes);
336long xatol(const char *numstr); 336long xatol(const char *numstr);
337/* Specialized: */ 337/* Specialized: */
338unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper);
339unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes);
338unsigned xatou(const char *numstr); 340unsigned xatou(const char *numstr);
339int xatoi_range(const char *numstr, int lower, int upper); 341int xatoi_range(const char *numstr, int lower, int upper);
340int xatoi(const char *numstr); 342int 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
198unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper)
199{
200 return xstrtoul_range_sfx(numstr, 10, lower, upper, NULL);
201}
202
203unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes)
204{
205 return xstrtoul_range_sfx(numstr, 10, 0, UINT_MAX, suffixes);
206}
207
198unsigned xatou(const char *numstr) 208unsigned 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
6menu "Runit Utilities" 6menu "Runit Utilities"
7 7
8config 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
8config CHPST 16config 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
7lib-y:= 7lib-y:=
8lib-$(CONFIG_CHPST) += chpst.o 8lib-$(CONFIG_CHPST) += chpst.o
9lib-$(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/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED 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
43void 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
55static 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
66static 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
75int 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
88int 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
98int 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
108char *buffer_peek(buffer *s)
109{
110 return s->x + s->n;
111}
112
113void buffer_seek(buffer *s,unsigned len)
114{
115 s->n += len;
116 s->p -= len;
117}
118
119
120/*** buffer_put.c ***/
121
122static 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
139int 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
149int 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
166int 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
188int 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
194int buffer_putsalign(buffer *s,const char *buf)
195{
196 return buffer_putalign(s,buf,strlen(buf));
197}
198
199int buffer_puts(buffer *s,const char *buf)
200{
201 return buffer_put(s,buf,strlen(buf));
202}
203
204int buffer_putsflush(buffer *s,const char *buf)
205{
206 return buffer_putflush(s,buf,strlen(buf));
207}
208
209
210/*** buffer_read.c ***/
211
212int buffer_unixread(int fd,char *buf,unsigned len)
213{
214 return read(fd,buf,len);
215}
216
217
218/*** buffer_write.c ***/
219
220int buffer_unixwrite(int fd,char *buf,unsigned len)
221{
222 return write(fd,buf,len);
223}
224
225
226/*** byte_chr.c ***/
227
228unsigned 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
247int coe(int fd)
248{
249 return fcntl(fd,F_SETFD,FD_CLOEXEC);
250}
251
252
253/*** fd_copy.c ***/
254
255int 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
267int 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
278int fifo_make(const char *fn,int mode) { return mkfifo(fn,mode); }
279
280
281/*** fmt_ptime.c ***/
282
283unsigned 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
300unsigned 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
317unsigned fmt_uint(char *s,unsigned u)
318{
319 return fmt_ulong(s,u);
320}
321
322
323/*** fmt_uint0.c ***/
324
325unsigned 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
337unsigned 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
352void tai_now(struct tai *t)
353{
354 tai_unix(t,time((time_t *) 0));
355}
356
357
358/*** tai_pack.c ***/
359
360void 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
378void 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
386void 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
406void 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
424double taia_approx(const struct taia *t)
425{
426 return tai_approx(&t->sec) + taia_frac(t);
427}
428
429
430/*** taia_frac.c ***/
431
432double 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
442int 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
454void 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
466void 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
490void 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
513void 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
523int 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
531int 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
544int stralloc_cats(stralloc *sa,const char *s)
545{
546 return stralloc_catb(sa,s,strlen(s));
547}
548
549
550/*** stralloc_eady.c ***/
551
552GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
553GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
554
555
556/*** stralloc_opyb.c ***/
557
558int 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
570int stralloc_copys(stralloc *sa,const char *s)
571{
572 return stralloc_copyb(sa,s,strlen(s));
573}
574
575
576/*** stralloc_pend.c ***/
577
578GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
579
580
581/*** iopause.c ***/
582
583void 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
612int lock_ex(int fd)
613{
614 return flock(fd,LOCK_EX);
615}
616
617
618/*** lock_exnb.c ***/
619
620int lock_exnb(int fd)
621{
622 return flock(fd,LOCK_EX | LOCK_NB);
623}
624
625
626/*** ndelay_off.c ***/
627
628int 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
636int 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
644int 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
652int open_read(const char *fn)
653{
654 return open(fn,O_RDONLY | O_NDELAY);
655}
656
657
658/*** open_trunc.c ***/
659
660int 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
668int open_write(const char *fn)
669{
670 return open(fn,O_WRONLY | O_NDELAY);
671}
672
673
674/*** openreadclose.c ***/
675
676int 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
691static stralloc plus;
692static stralloc tmp;
693
694int 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
706void 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
755static stralloc tmp;
756
757void 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
799unsigned 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
842int 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
849int prot_uid(int uid)
850{
851 return setuid(uid);
852}
853
854
855/*** readclose.c ***/
856
857int 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
869int 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
878unsigned 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
894int 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
902int sig_alarm = SIGALRM;
903int sig_child = SIGCHLD;
904int sig_cont = SIGCONT;
905int sig_hangup = SIGHUP;
906int sig_int = SIGINT;
907int sig_pipe = SIGPIPE;
908int sig_term = SIGTERM;
909
910void (*sig_defaulthandler)(int) = SIG_DFL;
911void (*sig_ignorehandler)(int) = SIG_IGN;
912
913
914/*** sig_block.c ***/
915
916void 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
924void 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
932void 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
942void 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
954void sig_pause(void)
955{
956 sigset_t ss;
957 sigemptyset(&ss);
958 sigsuspend(&ss);
959}
960
961
962/*** str_chr.c ***/
963
964unsigned 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
983int wait_nohang(int *wstat)
984{
985 return waitpid(-1,wstat,WNOHANG);
986}
987
988
989/*** wait_pid.c ***/
990
991int 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/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/*** buffer.h ***/
29
30typedef 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
42extern void buffer_init(buffer *,int (*)(int fd,char *buf,unsigned len),int,char *,unsigned);
43
44extern int buffer_flush(buffer *);
45extern int buffer_put(buffer *,const char *,unsigned);
46extern int buffer_putalign(buffer *,const char *,unsigned);
47extern int buffer_putflush(buffer *,const char *,unsigned);
48extern int buffer_puts(buffer *,const char *);
49extern int buffer_putsalign(buffer *,const char *);
50extern 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
58extern int buffer_get(buffer *,char *,unsigned);
59extern int buffer_bget(buffer *,char *,unsigned);
60extern int buffer_feed(buffer *);
61
62extern char *buffer_peek(buffer *);
63extern 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
74extern int buffer_copy(buffer *,buffer *);
75
76extern int buffer_unixread(int,char *,unsigned);
77/* Actually, int buffer_unixwrite(int,const char *,unsigned),
78 but that 'const' will produce warnings... oh well */
79extern int buffer_unixwrite(int,char *,unsigned);
80
81
82/*** byte.h ***/
83
84extern unsigned byte_chr(char *s,unsigned n,int c);
85
86
87/*** coe.h ***/
88
89extern int coe(int);
90
91
92/*** direntry.h ***/
93
94#define direntry struct dirent
95
96
97/*** fd.h ***/
98
99extern int fd_copy(int,int);
100extern int fd_move(int,int);
101
102
103/*** fifo.h ***/
104
105extern 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
113extern unsigned fmt_uint(char *,unsigned);
114extern unsigned fmt_uint0(char *,unsigned,unsigned);
115extern unsigned fmt_xint(char *,unsigned);
116extern unsigned fmt_nbbint(char *,unsigned,unsigned,unsigned,unsigned);
117extern unsigned fmt_ushort(char *,unsigned short);
118extern unsigned fmt_xshort(char *,unsigned short);
119extern unsigned fmt_nbbshort(char *,unsigned,unsigned,unsigned,unsigned short);
120extern unsigned fmt_ulong(char *,unsigned long);
121extern unsigned fmt_xlong(char *,unsigned long);
122extern unsigned fmt_nbblong(char *,unsigned,unsigned,unsigned,unsigned long);
123
124extern unsigned fmt_plusminus(char *,int);
125extern unsigned fmt_minus(char *,int);
126extern unsigned fmt_0x(char *,int);
127
128extern unsigned fmt_str(char *,const char *);
129extern unsigned fmt_strn(char *,const char *,unsigned);
130
131
132/*** tai.h ***/
133
134struct tai {
135 uint64_t x;
136} ;
137
138#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64_t) (u)))
139
140extern void tai_now(struct tai *);
141
142#define tai_approx(t) ((double) ((t)->x))
143
144extern void tai_add(struct tai *,const struct tai *,const struct tai *);
145extern 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
149extern void tai_pack(char *,const struct tai *);
150extern void tai_unpack(const char *,struct tai *);
151
152extern void tai_uint(struct tai *,unsigned);
153
154
155/*** taia.h ***/
156
157struct taia {
158 struct tai sec;
159 unsigned long nano; /* 0...999999999 */
160 unsigned long atto; /* 0...999999999 */
161} ;
162
163extern void taia_tai(const struct taia *,struct tai *);
164
165extern void taia_now(struct taia *);
166
167extern double taia_approx(const struct taia *);
168extern double taia_frac(const struct taia *);
169
170extern void taia_add(struct taia *,const struct taia *,const struct taia *);
171extern void taia_addsec(struct taia *,const struct taia *,int);
172extern void taia_sub(struct taia *,const struct taia *,const struct taia *);
173extern void taia_half(struct taia *,const struct taia *);
174extern int taia_less(const struct taia *,const struct taia *);
175
176#define TAIA_PACK 16
177extern void taia_pack(char *,const struct taia *);
178extern void taia_unpack(const char *,struct taia *);
179
180#define TAIA_FMTFRAC 19
181extern unsigned taia_fmtfrac(char *,const struct taia *);
182
183extern void taia_uint(struct taia *,unsigned);
184
185
186/*** fmt_ptime.h ***/
187
188#define FMT_PTIME 30
189
190extern unsigned fmt_ptime(char *, struct taia *);
191extern 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) \
203int 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) \
217int 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) \
231int 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
237GEN_ALLOC_typedef(stralloc,char,s,len,a)
238
239extern int stralloc_ready(stralloc *,unsigned);
240extern int stralloc_readyplus(stralloc *,unsigned);
241extern int stralloc_copy(stralloc *,const stralloc *);
242extern int stralloc_cat(stralloc *,const stralloc *);
243extern int stralloc_copys(stralloc *,const char *);
244extern int stralloc_cats(stralloc *,const char *);
245extern int stralloc_copyb(stralloc *,const char *,unsigned);
246extern int stralloc_catb(stralloc *,const char *,unsigned);
247extern int stralloc_append(stralloc *,const char *); /* beware: this takes a pointer to 1 char */
248extern int stralloc_starts(stralloc *,const char *);
249
250#define stralloc_0(sa) stralloc_append(sa,"")
251
252extern int stralloc_catulong0(stralloc *,unsigned long,unsigned);
253extern 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
263typedef struct pollfd iopause_fd;
264#define IOPAUSE_READ POLLIN
265#define IOPAUSE_WRITE POLLOUT
266
267extern void iopause(iopause_fd *,unsigned,struct taia *,struct taia *);
268
269
270/*** lock.h ***/
271
272extern int lock_ex(int);
273extern int lock_un(int);
274extern int lock_exnb(int);
275
276
277/*** ndelay.h ***/
278
279extern int ndelay_on(int);
280extern int ndelay_off(int);
281
282
283/*** open.h ***/
284
285extern int open_read(const char *);
286extern int open_excl(const char *);
287extern int open_append(const char *);
288extern int open_trunc(const char *);
289extern int open_write(const char *);
290
291
292/*** openreadclose.h ***/
293
294extern int openreadclose(const char *,stralloc *,unsigned);
295
296
297/*** pathexec.h ***/
298
299extern void pathexec_run(const char *,char *const *,char *const *);
300extern int pathexec_env(const char *,const char *);
301extern void pathexec(char **);
302
303
304/*** pmatch.h ***/
305
306extern unsigned pmatch(const char *, const char *, unsigned);
307
308
309/*** prot.h ***/
310
311extern int prot_gid(int);
312extern int prot_uid(int);
313
314
315/*** readclose.h ***/
316
317extern int readclose_append(int,stralloc *,unsigned);
318extern int readclose(int,stralloc *,unsigned);
319
320
321/*** scan.h ***/
322
323extern unsigned scan_uint(const char *,unsigned *);
324extern unsigned scan_xint(const char *,unsigned *);
325extern unsigned scan_nbbint(const char *,unsigned,unsigned,unsigned,unsigned *);
326extern unsigned scan_ushort(const char *,unsigned short *);
327extern unsigned scan_xshort(const char *,unsigned short *);
328extern unsigned scan_nbbshort(const char *,unsigned,unsigned,unsigned,unsigned short *);
329extern unsigned scan_ulong(const char *,unsigned long *);
330extern unsigned scan_xlong(const char *,unsigned long *);
331extern unsigned scan_nbblong(const char *,unsigned,unsigned,unsigned,unsigned long *);
332
333extern unsigned scan_plusminus(const char *,int *);
334extern unsigned scan_0x(const char *,unsigned *);
335
336extern unsigned scan_whitenskip(const char *,unsigned);
337extern unsigned scan_nonwhitenskip(const char *,unsigned);
338extern unsigned scan_charsetnskip(const char *,const char *,unsigned);
339extern unsigned scan_noncharsetnskip(const char *,const char *,unsigned);
340
341extern unsigned scan_strncmp(const char *,const char *,unsigned);
342extern unsigned scan_memcmp(const char *,const char *,unsigned);
343
344extern unsigned scan_long(const char *,long *);
345extern unsigned scan_8long(const char *,unsigned long *);
346
347
348/*** seek.h ***/
349
350typedef unsigned long seek_pos;
351
352extern seek_pos seek_cur(int);
353
354extern int seek_set(int,seek_pos);
355extern int seek_end(int);
356
357extern int seek_trunc(int,seek_pos);
358
359#define seek_begin(fd) (seek_set((fd),(seek_pos) 0))
360
361
362/*** sig.h ***/
363
364extern int sig_alarm;
365extern int sig_child;
366extern int sig_cont;
367extern int sig_hangup;
368extern int sig_int;
369extern int sig_pipe;
370extern int sig_term;
371
372extern void (*sig_defaulthandler)(int);
373extern void (*sig_ignorehandler)(int);
374
375extern 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
379extern void sig_block(int);
380extern void sig_unblock(int);
381extern void sig_blocknone(void);
382extern void sig_pause(void);
383
384extern void sig_dfl(int);
385
386
387/*** str.h ***/
388
389extern 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
397extern int wait_pid(int *wstat, int pid);
398extern 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/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED 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
36static unsigned verbose;
37static int linemax = 1000;
38static int buflen = 1024;
39static int linelen;
40
41static char **fndir;
42static int fdwdir;
43static int wstat;
44static struct taia trotate;
45
46static char *line;
47static unsigned exitasap;
48static unsigned rotateasap;
49static unsigned reopenasap;
50static unsigned linecomplete = 1;
51static unsigned tmaxflag;
52static iopause_fd in;
53
54static const char *replace = "";
55static char repl;
56
57static 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;
78static 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()
86static void fatalx(char *m0)
87{
88 bb_error_msg_and_die(FATAL"%s", m0);
89}
90static void warn(char *m0) {
91 bb_perror_msg(WARNING"%s", m0);
92}
93static void warn2(char *m0, char *m1)
94{
95 bb_perror_msg(WARNING"%s: %s", m0, m1);
96}
97static void warnx(char *m0, char *m1)
98{
99 bb_error_msg(WARNING"%s: %s", m0, m1);
100}
101static void pause_nomem(void)
102{
103 bb_error_msg(PAUSE"out of memory"); sleep(3);
104}
105static void pause1cannot(char *m0)
106{
107 bb_perror_msg(PAUSE"cannot %s", m0); sleep(3);
108}
109static void pause2cannot(char *m0, char *m1)
110{
111 bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
112 sleep(3);
113}
114
115static char* wstrdup(const char *str)
116{
117 char *s;
118 while (!(s = strdup(str))) pause_nomem();
119 return s;
120}
121
122static 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
178static 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
221static 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
255static 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
317static 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
379static 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
403static 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
563static 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 */
579static 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
657static 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
664static 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
679static 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
686static 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
693static 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
717int 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, &timestamp, &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}