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 | } | ||
