mirror of
https://github.com/sheumann/hush.git
synced 2025-01-02 09:31:26 +00:00
svlogd: new applet. +9k. Still too big, but it was 12k yesterday.
This commit is contained in:
parent
3672fe9e91
commit
83ea643d8d
@ -10,7 +10,7 @@
|
|||||||
#include "busybox.h"
|
#include "busybox.h"
|
||||||
#include <sys/kd.h>
|
#include <sys/kd.h>
|
||||||
|
|
||||||
enum{
|
enum {
|
||||||
PSF_MAGIC1 = 0x36,
|
PSF_MAGIC1 = 0x36,
|
||||||
PSF_MAGIC2 = 0x04,
|
PSF_MAGIC2 = 0x04,
|
||||||
|
|
||||||
|
@ -270,6 +270,7 @@ USE_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_NEVER))
|
|||||||
USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS))
|
USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS))
|
||||||
USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER))
|
USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER))
|
||||||
USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
|
USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
|
||||||
|
USE_SVLOGD(APPLET(svlogd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
|
||||||
USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff))
|
USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff))
|
||||||
USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon))
|
USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon))
|
||||||
USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
|
USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
|
||||||
|
@ -335,6 +335,8 @@ long xatol_range(const char *numstr, long lower, long upper);
|
|||||||
long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes);
|
long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes);
|
||||||
long xatol(const char *numstr);
|
long xatol(const char *numstr);
|
||||||
/* Specialized: */
|
/* Specialized: */
|
||||||
|
unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper);
|
||||||
|
unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes);
|
||||||
unsigned xatou(const char *numstr);
|
unsigned xatou(const char *numstr);
|
||||||
int xatoi_range(const char *numstr, int lower, int upper);
|
int xatoi_range(const char *numstr, int lower, int upper);
|
||||||
int xatoi(const char *numstr);
|
int xatoi(const char *numstr);
|
||||||
|
@ -2841,6 +2841,13 @@ USE_FEATURE_START_STOP_DAEMON_FANCY( \
|
|||||||
"\t-r\tuse BSD sum algorithm (1K blocks)\n" \
|
"\t-r\tuse BSD sum algorithm (1K blocks)\n" \
|
||||||
"\t-s\tuse System V sum algorithm (512byte blocks)"
|
"\t-s\tuse System V sum algorithm (512byte blocks)"
|
||||||
|
|
||||||
|
#define svlogd_trivial_usage \
|
||||||
|
"[-ttv] [-r c] [-R abc] [-l len] [-b buflen] dir..."
|
||||||
|
#define svlogd_full_usage \
|
||||||
|
"Continuously read log data from standard input, optionally " \
|
||||||
|
"filter log messages, and write the data to one or more automatically " \
|
||||||
|
"rotated logs."
|
||||||
|
|
||||||
#define swapoff_trivial_usage \
|
#define swapoff_trivial_usage \
|
||||||
"[-a] [DEVICE]"
|
"[-a] [DEVICE]"
|
||||||
#define swapoff_full_usage \
|
#define swapoff_full_usage \
|
||||||
|
@ -195,6 +195,16 @@ long xatol(const char *numstr)
|
|||||||
|
|
||||||
/* Others */
|
/* Others */
|
||||||
|
|
||||||
|
unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper)
|
||||||
|
{
|
||||||
|
return xstrtoul_range_sfx(numstr, 10, lower, upper, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes)
|
||||||
|
{
|
||||||
|
return xstrtoul_range_sfx(numstr, 10, 0, UINT_MAX, suffixes);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned xatou(const char *numstr)
|
unsigned xatou(const char *numstr)
|
||||||
{
|
{
|
||||||
return xatoul_range(numstr, 0, UINT_MAX);
|
return xatoul_range(numstr, 0, UINT_MAX);
|
||||||
|
@ -5,6 +5,14 @@
|
|||||||
|
|
||||||
menu "Runit Utilities"
|
menu "Runit Utilities"
|
||||||
|
|
||||||
|
config SVLOGD
|
||||||
|
bool "svlogd"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
svlogd continuously reads log data from its standard input, optionally
|
||||||
|
filters log messages, and writes the data to one or more automatically
|
||||||
|
rotated logs.
|
||||||
|
|
||||||
config CHPST
|
config CHPST
|
||||||
bool "chpst"
|
bool "chpst"
|
||||||
default n
|
default n
|
||||||
|
@ -6,3 +6,4 @@
|
|||||||
|
|
||||||
lib-y:=
|
lib-y:=
|
||||||
lib-$(CONFIG_CHPST) += chpst.o
|
lib-$(CONFIG_CHPST) += chpst.o
|
||||||
|
lib-$(CONFIG_SVLOGD) += svlogd.o runit_lib.o
|
||||||
|
@ -26,6 +26,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
|
/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
|
||||||
|
/* Dependencies on runit_lib.c removed */
|
||||||
|
|
||||||
#include "busybox.h"
|
#include "busybox.h"
|
||||||
|
|
||||||
@ -94,7 +95,9 @@ static void edir(const char *directory_name)
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
d = readdir(dir);
|
d = readdir(dir);
|
||||||
if (!d) {
|
if (!d) {
|
||||||
if (errno) bb_perror_msg_and_die("readdir %s", directory_name);
|
if (errno)
|
||||||
|
bb_perror_msg_and_die("readdir %s",
|
||||||
|
directory_name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (d->d_name[0] == '.') continue;
|
if (d->d_name[0] == '.') continue;
|
||||||
@ -102,12 +105,12 @@ static void edir(const char *directory_name)
|
|||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
if ((errno == EISDIR) && env_dir) {
|
if ((errno == EISDIR) && env_dir) {
|
||||||
if (OPT_verbose)
|
if (OPT_verbose)
|
||||||
bb_perror_msg("warning: %s/%s is a directory", directory_name,
|
bb_perror_msg("warning: %s/%s is a directory",
|
||||||
d->d_name);
|
directory_name, d->d_name);
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
bb_perror_msg_and_die("open %s/%s", directory_name, /* was exiting 111 */
|
bb_perror_msg_and_die("open %s/%s",
|
||||||
d->d_name);
|
directory_name, d->d_name);
|
||||||
}
|
}
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
@ -116,8 +119,8 @@ static void edir(const char *directory_name)
|
|||||||
|
|
||||||
size = safe_read(fd, buf, sizeof(buf)-1);
|
size = safe_read(fd, buf, sizeof(buf)-1);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
bb_perror_msg_and_die("read %s/%s", directory_name, /* was exiting 111 */
|
bb_perror_msg_and_die("read %s/%s",
|
||||||
d->d_name);
|
directory_name, d->d_name);
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
unsetenv(d->d_name);
|
unsetenv(d->d_name);
|
||||||
continue;
|
continue;
|
||||||
@ -158,21 +161,24 @@ static void slimit(void)
|
|||||||
#ifdef RLIMIT_DATA
|
#ifdef RLIMIT_DATA
|
||||||
limit(RLIMIT_DATA, limitd);
|
limit(RLIMIT_DATA, limitd);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_DATA");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_DATA");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limits >= -1) {
|
if (limits >= -1) {
|
||||||
#ifdef RLIMIT_STACK
|
#ifdef RLIMIT_STACK
|
||||||
limit(RLIMIT_STACK, limits);
|
limit(RLIMIT_STACK, limits);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_STACK");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_STACK");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limitl >= -1) {
|
if (limitl >= -1) {
|
||||||
#ifdef RLIMIT_MEMLOCK
|
#ifdef RLIMIT_MEMLOCK
|
||||||
limit(RLIMIT_MEMLOCK, limitl);
|
limit(RLIMIT_MEMLOCK, limitl);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_MEMLOCK");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_MEMLOCK");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limita >= -1) {
|
if (limita >= -1) {
|
||||||
@ -183,7 +189,8 @@ static void slimit(void)
|
|||||||
limit(RLIMIT_AS, limita);
|
limit(RLIMIT_AS, limita);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose)
|
if (OPT_verbose)
|
||||||
bb_error_msg("system does not support %s", "RLIMIT_VMEM");
|
bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_VMEM");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -195,7 +202,8 @@ static void slimit(void)
|
|||||||
limit(RLIMIT_OFILE, limito);
|
limit(RLIMIT_OFILE, limito);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose)
|
if (OPT_verbose)
|
||||||
bb_error_msg("system does not support %s", "RLIMIT_NOFILE");
|
bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_NOFILE");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -203,35 +211,40 @@ static void slimit(void)
|
|||||||
#ifdef RLIMIT_NPROC
|
#ifdef RLIMIT_NPROC
|
||||||
limit(RLIMIT_NPROC, limitp);
|
limit(RLIMIT_NPROC, limitp);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_NPROC");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_NPROC");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limitf >= -1) {
|
if (limitf >= -1) {
|
||||||
#ifdef RLIMIT_FSIZE
|
#ifdef RLIMIT_FSIZE
|
||||||
limit(RLIMIT_FSIZE, limitf);
|
limit(RLIMIT_FSIZE, limitf);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_FSIZE");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_FSIZE");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limitc >= -1) {
|
if (limitc >= -1) {
|
||||||
#ifdef RLIMIT_CORE
|
#ifdef RLIMIT_CORE
|
||||||
limit(RLIMIT_CORE, limitc);
|
limit(RLIMIT_CORE, limitc);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_CORE");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_CORE");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limitr >= -1) {
|
if (limitr >= -1) {
|
||||||
#ifdef RLIMIT_RSS
|
#ifdef RLIMIT_RSS
|
||||||
limit(RLIMIT_RSS, limitr);
|
limit(RLIMIT_RSS, limitr);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_RSS");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_RSS");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (limitt >= -1) {
|
if (limitt >= -1) {
|
||||||
#ifdef RLIMIT_CPU
|
#ifdef RLIMIT_CPU
|
||||||
limit(RLIMIT_CPU, limitt);
|
limit(RLIMIT_CPU, limitt);
|
||||||
#else
|
#else
|
||||||
if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_CPU");
|
if (OPT_verbose) bb_error_msg("system does not support %s",
|
||||||
|
"RLIMIT_CPU");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
999
runit/runit_lib.c
Normal file
999
runit/runit_lib.c
Normal file
@ -0,0 +1,999 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2001-2006, Gerrit Pape
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
|
||||||
|
/* Collected into one file from runit's many tiny files */
|
||||||
|
/* TODO: review, eliminate unneeded stuff, move good stuff to libbb */
|
||||||
|
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include "libbb.h"
|
||||||
|
#include "runit_lib.h"
|
||||||
|
|
||||||
|
#ifndef O_NONBLOCK
|
||||||
|
#define O_NONBLOCK O_NDELAY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*** buffer.c ***/
|
||||||
|
|
||||||
|
void buffer_init(buffer *s,int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
s->x = buf;
|
||||||
|
s->fd = fd;
|
||||||
|
s->op = op;
|
||||||
|
s->p = 0;
|
||||||
|
s->n = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** buffer_get.c ***/
|
||||||
|
|
||||||
|
static int oneread(int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
r = op(fd,buf,len);
|
||||||
|
if (r == -1) if (errno == EINTR) continue;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getthis(buffer *s,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
if (len > s->p) len = s->p;
|
||||||
|
s->p -= len;
|
||||||
|
memcpy(buf,s->x + s->n,len);
|
||||||
|
s->n += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_feed(buffer *s)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (s->p) return s->p;
|
||||||
|
r = oneread(s->op,s->fd,s->x,s->n);
|
||||||
|
if (r <= 0) return r;
|
||||||
|
s->p = r;
|
||||||
|
s->n -= r;
|
||||||
|
if (s->n > 0) memmove(s->x + s->n,s->x,r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_bget(buffer *s,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (s->p > 0) return getthis(s,buf,len);
|
||||||
|
if (s->n <= len) return oneread(s->op,s->fd,buf,s->n);
|
||||||
|
r = buffer_feed(s); if (r <= 0) return r;
|
||||||
|
return getthis(s,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_get(buffer *s,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (s->p > 0) return getthis(s,buf,len);
|
||||||
|
if (s->n <= len) return oneread(s->op,s->fd,buf,len);
|
||||||
|
r = buffer_feed(s); if (r <= 0) return r;
|
||||||
|
return getthis(s,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buffer_peek(buffer *s)
|
||||||
|
{
|
||||||
|
return s->x + s->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_seek(buffer *s,unsigned len)
|
||||||
|
{
|
||||||
|
s->n += len;
|
||||||
|
s->p -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** buffer_put.c ***/
|
||||||
|
|
||||||
|
static int allwrite(int (*op)(int fd,char *buf,unsigned len),int fd,const char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
w = op(fd,(char*)buf,len);
|
||||||
|
if (w == -1) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
return -1; /* note that some data may have been written */
|
||||||
|
}
|
||||||
|
if (w == 0) ; /* luser's fault */
|
||||||
|
buf += w;
|
||||||
|
len -= w;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_flush(buffer *s)
|
||||||
|
{
|
||||||
|
int p;
|
||||||
|
|
||||||
|
p = s->p;
|
||||||
|
if (!p) return 0;
|
||||||
|
s->p = 0;
|
||||||
|
return allwrite(s->op,s->fd,s->x,p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_putalign(buffer *s,const char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
|
while (len > (n = s->n - s->p)) {
|
||||||
|
memcpy(s->x + s->p,buf,n);
|
||||||
|
s->p += n;
|
||||||
|
buf += n;
|
||||||
|
len -= n;
|
||||||
|
if (buffer_flush(s) == -1) return -1;
|
||||||
|
}
|
||||||
|
/* now len <= s->n - s->p */
|
||||||
|
memcpy(s->x + s->p,buf,len);
|
||||||
|
s->p += len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_put(buffer *s,const char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
|
n = s->n;
|
||||||
|
if (len > n - s->p) {
|
||||||
|
if (buffer_flush(s) == -1) return -1;
|
||||||
|
/* now s->p == 0 */
|
||||||
|
if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE;
|
||||||
|
while (len > s->n) {
|
||||||
|
if (n > len) n = len;
|
||||||
|
if (allwrite(s->op,s->fd,buf,n) == -1) return -1;
|
||||||
|
buf += n;
|
||||||
|
len -= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now len <= s->n - s->p */
|
||||||
|
memcpy(s->x + s->p,buf,len);
|
||||||
|
s->p += len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_putflush(buffer *s,const char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
if (buffer_flush(s) == -1) return -1;
|
||||||
|
return allwrite(s->op,s->fd,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_putsalign(buffer *s,const char *buf)
|
||||||
|
{
|
||||||
|
return buffer_putalign(s,buf,strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_puts(buffer *s,const char *buf)
|
||||||
|
{
|
||||||
|
return buffer_put(s,buf,strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_putsflush(buffer *s,const char *buf)
|
||||||
|
{
|
||||||
|
return buffer_putflush(s,buf,strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** buffer_read.c ***/
|
||||||
|
|
||||||
|
int buffer_unixread(int fd,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
return read(fd,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** buffer_write.c ***/
|
||||||
|
|
||||||
|
int buffer_unixwrite(int fd,char *buf,unsigned len)
|
||||||
|
{
|
||||||
|
return write(fd,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** byte_chr.c ***/
|
||||||
|
|
||||||
|
unsigned byte_chr(char *s,unsigned n,int c)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
ch = c;
|
||||||
|
t = s;
|
||||||
|
for (;;) {
|
||||||
|
if (!n) break; if (*t == ch) break; ++t; --n;
|
||||||
|
if (!n) break; if (*t == ch) break; ++t; --n;
|
||||||
|
if (!n) break; if (*t == ch) break; ++t; --n;
|
||||||
|
if (!n) break; if (*t == ch) break; ++t; --n;
|
||||||
|
}
|
||||||
|
return t - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** coe.c ***/
|
||||||
|
|
||||||
|
int coe(int fd)
|
||||||
|
{
|
||||||
|
return fcntl(fd,F_SETFD,FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** fd_copy.c ***/
|
||||||
|
|
||||||
|
int fd_copy(int to,int from)
|
||||||
|
{
|
||||||
|
if (to == from) return 0;
|
||||||
|
if (fcntl(from,F_GETFL,0) == -1) return -1;
|
||||||
|
close(to);
|
||||||
|
if (fcntl(from,F_DUPFD,to) == -1) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** fd_move.c ***/
|
||||||
|
|
||||||
|
int fd_move(int to,int from)
|
||||||
|
{
|
||||||
|
if (to == from) return 0;
|
||||||
|
if (fd_copy(to,from) == -1) return -1;
|
||||||
|
close(from);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** fifo.c ***/
|
||||||
|
|
||||||
|
int fifo_make(const char *fn,int mode) { return mkfifo(fn,mode); }
|
||||||
|
|
||||||
|
|
||||||
|
/*** fmt_ptime.c ***/
|
||||||
|
|
||||||
|
unsigned fmt_ptime(char *s, struct taia *ta) {
|
||||||
|
struct tm *t;
|
||||||
|
unsigned long u;
|
||||||
|
|
||||||
|
if (ta->sec.x < 4611686018427387914ULL) return 0; /* impossible? */
|
||||||
|
u = ta->sec.x -4611686018427387914ULL;
|
||||||
|
if (!(t = gmtime((time_t*)&u))) return 0;
|
||||||
|
fmt_ulong(s, 1900 + t->tm_year);
|
||||||
|
s[4] = '-'; fmt_uint0(&s[5], t->tm_mon+1, 2);
|
||||||
|
s[7] = '-'; fmt_uint0(&s[8], t->tm_mday, 2);
|
||||||
|
s[10] = '_'; fmt_uint0(&s[11], t->tm_hour, 2);
|
||||||
|
s[13] = ':'; fmt_uint0(&s[14], t->tm_min, 2);
|
||||||
|
s[16] = ':'; fmt_uint0(&s[17], t->tm_sec, 2);
|
||||||
|
s[19] = '.'; fmt_uint0(&s[20], ta->nano, 9);
|
||||||
|
return 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned fmt_taia(char *s, struct taia *t) {
|
||||||
|
static char hex[16] = "0123456789abcdef";
|
||||||
|
static char pack[TAIA_PACK];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
taia_pack(pack, t);
|
||||||
|
s[0] = '@';
|
||||||
|
for (i = 0; i < 12; ++i) {
|
||||||
|
s[i*2+1] = hex[(pack[i] >> 4) &15];
|
||||||
|
s[i*2+2] = hex[pack[i] &15];
|
||||||
|
}
|
||||||
|
return 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** fmt_uint.c ***/
|
||||||
|
|
||||||
|
unsigned fmt_uint(char *s,unsigned u)
|
||||||
|
{
|
||||||
|
return fmt_ulong(s,u);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** fmt_uint0.c ***/
|
||||||
|
|
||||||
|
unsigned fmt_uint0(char *s,unsigned u,unsigned n)
|
||||||
|
{
|
||||||
|
unsigned len;
|
||||||
|
len = fmt_uint(FMT_LEN,u);
|
||||||
|
while (len < n) { if (s) *s++ = '0'; ++len; }
|
||||||
|
if (s) fmt_uint(s,u);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** fmt_ulong.c ***/
|
||||||
|
|
||||||
|
unsigned fmt_ulong(char *s,unsigned long u)
|
||||||
|
{
|
||||||
|
unsigned len; unsigned long q;
|
||||||
|
len = 1; q = u;
|
||||||
|
while (q > 9) { ++len; q /= 10; }
|
||||||
|
if (s) {
|
||||||
|
s += len;
|
||||||
|
do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** tai_now.c ***/
|
||||||
|
|
||||||
|
void tai_now(struct tai *t)
|
||||||
|
{
|
||||||
|
tai_unix(t,time((time_t *) 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** tai_pack.c ***/
|
||||||
|
|
||||||
|
void tai_pack(char *s,const struct tai *t)
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
|
||||||
|
x = t->x;
|
||||||
|
s[7] = x & 255; x >>= 8;
|
||||||
|
s[6] = x & 255; x >>= 8;
|
||||||
|
s[5] = x & 255; x >>= 8;
|
||||||
|
s[4] = x & 255; x >>= 8;
|
||||||
|
s[3] = x & 255; x >>= 8;
|
||||||
|
s[2] = x & 255; x >>= 8;
|
||||||
|
s[1] = x & 255; x >>= 8;
|
||||||
|
s[0] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** tai_sub.c ***/
|
||||||
|
|
||||||
|
void tai_sub(struct tai *t,const struct tai *u,const struct tai *v)
|
||||||
|
{
|
||||||
|
t->x = u->x - v->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** tai_unpack.c ***/
|
||||||
|
|
||||||
|
void tai_unpack(const char *s,struct tai *t)
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
|
||||||
|
x = (unsigned char) s[0];
|
||||||
|
x <<= 8; x += (unsigned char) s[1];
|
||||||
|
x <<= 8; x += (unsigned char) s[2];
|
||||||
|
x <<= 8; x += (unsigned char) s[3];
|
||||||
|
x <<= 8; x += (unsigned char) s[4];
|
||||||
|
x <<= 8; x += (unsigned char) s[5];
|
||||||
|
x <<= 8; x += (unsigned char) s[6];
|
||||||
|
x <<= 8; x += (unsigned char) s[7];
|
||||||
|
t->x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_add.c ***/
|
||||||
|
|
||||||
|
/* XXX: breaks tai encapsulation */
|
||||||
|
|
||||||
|
void taia_add(struct taia *t,const struct taia *u,const struct taia *v)
|
||||||
|
{
|
||||||
|
t->sec.x = u->sec.x + v->sec.x;
|
||||||
|
t->nano = u->nano + v->nano;
|
||||||
|
t->atto = u->atto + v->atto;
|
||||||
|
if (t->atto > 999999999UL) {
|
||||||
|
t->atto -= 1000000000UL;
|
||||||
|
++t->nano;
|
||||||
|
}
|
||||||
|
if (t->nano > 999999999UL) {
|
||||||
|
t->nano -= 1000000000UL;
|
||||||
|
++t->sec.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_approx.c ***/
|
||||||
|
|
||||||
|
double taia_approx(const struct taia *t)
|
||||||
|
{
|
||||||
|
return tai_approx(&t->sec) + taia_frac(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_frac.c ***/
|
||||||
|
|
||||||
|
double taia_frac(const struct taia *t)
|
||||||
|
{
|
||||||
|
return (t->atto * 0.000000001 + t->nano) * 0.000000001;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_less.c ***/
|
||||||
|
|
||||||
|
/* XXX: breaks tai encapsulation */
|
||||||
|
|
||||||
|
int taia_less(const struct taia *t,const struct taia *u)
|
||||||
|
{
|
||||||
|
if (t->sec.x < u->sec.x) return 1;
|
||||||
|
if (t->sec.x > u->sec.x) return 0;
|
||||||
|
if (t->nano < u->nano) return 1;
|
||||||
|
if (t->nano > u->nano) return 0;
|
||||||
|
return t->atto < u->atto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_now.c ***/
|
||||||
|
|
||||||
|
void taia_now(struct taia *t)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now,(struct timezone *) 0);
|
||||||
|
tai_unix(&t->sec,now.tv_sec);
|
||||||
|
t->nano = 1000 * now.tv_usec + 500;
|
||||||
|
t->atto = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_pack.c ***/
|
||||||
|
|
||||||
|
void taia_pack(char *s,const struct taia *t)
|
||||||
|
{
|
||||||
|
unsigned long x;
|
||||||
|
|
||||||
|
tai_pack(s,&t->sec);
|
||||||
|
s += 8;
|
||||||
|
|
||||||
|
x = t->atto;
|
||||||
|
s[7] = x & 255; x >>= 8;
|
||||||
|
s[6] = x & 255; x >>= 8;
|
||||||
|
s[5] = x & 255; x >>= 8;
|
||||||
|
s[4] = x;
|
||||||
|
x = t->nano;
|
||||||
|
s[3] = x & 255; x >>= 8;
|
||||||
|
s[2] = x & 255; x >>= 8;
|
||||||
|
s[1] = x & 255; x >>= 8;
|
||||||
|
s[0] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_sub.c ***/
|
||||||
|
|
||||||
|
/* XXX: breaks tai encapsulation */
|
||||||
|
|
||||||
|
void taia_sub(struct taia *t,const struct taia *u,const struct taia *v)
|
||||||
|
{
|
||||||
|
unsigned long unano = u->nano;
|
||||||
|
unsigned long uatto = u->atto;
|
||||||
|
|
||||||
|
t->sec.x = u->sec.x - v->sec.x;
|
||||||
|
t->nano = unano - v->nano;
|
||||||
|
t->atto = uatto - v->atto;
|
||||||
|
if (t->atto > uatto) {
|
||||||
|
t->atto += 1000000000UL;
|
||||||
|
--t->nano;
|
||||||
|
}
|
||||||
|
if (t->nano > unano) {
|
||||||
|
t->nano += 1000000000UL;
|
||||||
|
--t->sec.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia_uint.c ***/
|
||||||
|
|
||||||
|
/* XXX: breaks tai encapsulation */
|
||||||
|
|
||||||
|
void taia_uint(struct taia *t,unsigned s)
|
||||||
|
{
|
||||||
|
t->sec.x = s;
|
||||||
|
t->nano = 0;
|
||||||
|
t->atto = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_cat.c ***/
|
||||||
|
|
||||||
|
int stralloc_cat(stralloc *sato,const stralloc *safrom)
|
||||||
|
{
|
||||||
|
return stralloc_catb(sato,safrom->s,safrom->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_catb.c ***/
|
||||||
|
|
||||||
|
int stralloc_catb(stralloc *sa,const char *s,unsigned n)
|
||||||
|
{
|
||||||
|
if (!sa->s) return stralloc_copyb(sa,s,n);
|
||||||
|
if (!stralloc_readyplus(sa,n + 1)) return 0;
|
||||||
|
memcpy(sa->s + sa->len,s,n);
|
||||||
|
sa->len += n;
|
||||||
|
sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_cats.c ***/
|
||||||
|
|
||||||
|
int stralloc_cats(stralloc *sa,const char *s)
|
||||||
|
{
|
||||||
|
return stralloc_catb(sa,s,strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_eady.c ***/
|
||||||
|
|
||||||
|
GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
|
||||||
|
GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_opyb.c ***/
|
||||||
|
|
||||||
|
int stralloc_copyb(stralloc *sa,const char *s,unsigned n)
|
||||||
|
{
|
||||||
|
if (!stralloc_ready(sa,n + 1)) return 0;
|
||||||
|
memcpy(sa->s,s,n);
|
||||||
|
sa->len = n;
|
||||||
|
sa->s[n] = 'Z'; /* ``offensive programming'' */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_opys.c ***/
|
||||||
|
|
||||||
|
int stralloc_copys(stralloc *sa,const char *s)
|
||||||
|
{
|
||||||
|
return stralloc_copyb(sa,s,strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc_pend.c ***/
|
||||||
|
|
||||||
|
GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
|
||||||
|
|
||||||
|
|
||||||
|
/*** iopause.c ***/
|
||||||
|
|
||||||
|
void iopause(iopause_fd *x,unsigned len,struct taia *deadline,struct taia *stamp)
|
||||||
|
{
|
||||||
|
struct taia t;
|
||||||
|
int millisecs;
|
||||||
|
double d;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (taia_less(deadline,stamp))
|
||||||
|
millisecs = 0;
|
||||||
|
else {
|
||||||
|
t = *stamp;
|
||||||
|
taia_sub(&t,deadline,&t);
|
||||||
|
d = taia_approx(&t);
|
||||||
|
if (d > 1000.0) d = 1000.0;
|
||||||
|
millisecs = d * 1000.0 + 20.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0;i < len;++i)
|
||||||
|
x[i].revents = 0;
|
||||||
|
|
||||||
|
poll(x,len,millisecs);
|
||||||
|
/* XXX: some kernels apparently need x[0] even if len is 0 */
|
||||||
|
/* XXX: how to handle EAGAIN? are kernels really this dumb? */
|
||||||
|
/* XXX: how to handle EINVAL? when exactly can this happen? */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** lock_ex.c ***/
|
||||||
|
|
||||||
|
int lock_ex(int fd)
|
||||||
|
{
|
||||||
|
return flock(fd,LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** lock_exnb.c ***/
|
||||||
|
|
||||||
|
int lock_exnb(int fd)
|
||||||
|
{
|
||||||
|
return flock(fd,LOCK_EX | LOCK_NB);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** ndelay_off.c ***/
|
||||||
|
|
||||||
|
int ndelay_off(int fd)
|
||||||
|
{
|
||||||
|
return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** ndelay_on.c ***/
|
||||||
|
|
||||||
|
int ndelay_on(int fd)
|
||||||
|
{
|
||||||
|
return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** open_append.c ***/
|
||||||
|
|
||||||
|
int open_append(const char *fn)
|
||||||
|
{
|
||||||
|
return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** open_read.c ***/
|
||||||
|
|
||||||
|
int open_read(const char *fn)
|
||||||
|
{
|
||||||
|
return open(fn,O_RDONLY | O_NDELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** open_trunc.c ***/
|
||||||
|
|
||||||
|
int open_trunc(const char *fn)
|
||||||
|
{
|
||||||
|
return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** open_write.c ***/
|
||||||
|
|
||||||
|
int open_write(const char *fn)
|
||||||
|
{
|
||||||
|
return open(fn,O_WRONLY | O_NDELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** openreadclose.c ***/
|
||||||
|
|
||||||
|
int openreadclose(const char *fn,stralloc *sa,unsigned bufsize)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
fd = open_read(fn);
|
||||||
|
if (fd == -1) {
|
||||||
|
if (errno == ENOENT) return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (readclose(fd,sa,bufsize) == -1) return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** pathexec_env.c ***/
|
||||||
|
|
||||||
|
static stralloc plus;
|
||||||
|
static stralloc tmp;
|
||||||
|
|
||||||
|
int pathexec_env(const char *s,const char *t)
|
||||||
|
{
|
||||||
|
if (!s) return 1;
|
||||||
|
if (!stralloc_copys(&tmp,s)) return 0;
|
||||||
|
if (t) {
|
||||||
|
if (!stralloc_cats(&tmp,"=")) return 0;
|
||||||
|
if (!stralloc_cats(&tmp,t)) return 0;
|
||||||
|
}
|
||||||
|
if (!stralloc_0(&tmp)) return 0;
|
||||||
|
return stralloc_cat(&plus,&tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pathexec(char **argv)
|
||||||
|
{
|
||||||
|
char **e;
|
||||||
|
unsigned elen;
|
||||||
|
unsigned i;
|
||||||
|
unsigned j;
|
||||||
|
unsigned split;
|
||||||
|
unsigned t;
|
||||||
|
|
||||||
|
if (!stralloc_cats(&plus,"")) return;
|
||||||
|
|
||||||
|
elen = 0;
|
||||||
|
for (i = 0;environ[i];++i)
|
||||||
|
++elen;
|
||||||
|
for (i = 0;i < plus.len;++i)
|
||||||
|
if (!plus.s[i])
|
||||||
|
++elen;
|
||||||
|
|
||||||
|
e = malloc((elen + 1) * sizeof(char *));
|
||||||
|
if (!e) return;
|
||||||
|
|
||||||
|
elen = 0;
|
||||||
|
for (i = 0;environ[i];++i)
|
||||||
|
e[elen++] = environ[i];
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0;i < plus.len;++i)
|
||||||
|
if (!plus.s[i]) {
|
||||||
|
split = str_chr(plus.s + j,'=');
|
||||||
|
for (t = 0;t < elen;++t)
|
||||||
|
if (memcmp(plus.s + j,e[t],split) == 0)
|
||||||
|
if (e[t][split] == '=') {
|
||||||
|
--elen;
|
||||||
|
e[t] = e[elen];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (plus.s[j + split])
|
||||||
|
e[elen++] = plus.s + j;
|
||||||
|
j = i + 1;
|
||||||
|
}
|
||||||
|
e[elen] = 0;
|
||||||
|
|
||||||
|
pathexec_run(*argv,argv,e);
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** pathexec_run.c ***/
|
||||||
|
|
||||||
|
static stralloc tmp;
|
||||||
|
|
||||||
|
void pathexec_run(const char *file,char *const *argv,char *const *envp)
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
unsigned split;
|
||||||
|
int savederrno;
|
||||||
|
|
||||||
|
if (file[str_chr(file,'/')]) {
|
||||||
|
execve(file,argv,envp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = getenv("PATH");
|
||||||
|
if (!path) path = "/bin:/usr/bin";
|
||||||
|
|
||||||
|
savederrno = 0;
|
||||||
|
for (;;) {
|
||||||
|
split = str_chr(path,':');
|
||||||
|
if (!stralloc_copyb(&tmp,path,split)) return;
|
||||||
|
if (!split)
|
||||||
|
if (!stralloc_cats(&tmp,".")) return;
|
||||||
|
if (!stralloc_cats(&tmp,"/")) return;
|
||||||
|
if (!stralloc_cats(&tmp,file)) return;
|
||||||
|
if (!stralloc_0(&tmp)) return;
|
||||||
|
|
||||||
|
execve(tmp.s,argv,envp);
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
savederrno = errno;
|
||||||
|
if ((errno != EACCES) && (errno != EPERM) && (errno != EISDIR)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path[split]) {
|
||||||
|
if (savederrno) errno = savederrno;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
path += split;
|
||||||
|
path += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** pmatch.c ***/
|
||||||
|
|
||||||
|
unsigned pmatch(const char *p, const char *s, unsigned len) {
|
||||||
|
for (;;) {
|
||||||
|
char c = *p++;
|
||||||
|
if (!c) return !len;
|
||||||
|
switch (c) {
|
||||||
|
case '*':
|
||||||
|
if (!(c = *p)) return 1;
|
||||||
|
for (;;) {
|
||||||
|
if (!len) return 0;
|
||||||
|
if (*s == c) break;
|
||||||
|
++s; --len;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case '+':
|
||||||
|
if ((c = *p++) != *s) return 0;
|
||||||
|
for (;;) {
|
||||||
|
if (!len) return 1;
|
||||||
|
if (*s != c) break;
|
||||||
|
++s; --len;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
case '?':
|
||||||
|
if (*p == '?') {
|
||||||
|
if (*s != '?') return 0;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
++s; --len;
|
||||||
|
continue;
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
if (!len) return 0;
|
||||||
|
if (*s != c) return 0;
|
||||||
|
++s; --len;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** prot.c ***/
|
||||||
|
|
||||||
|
int prot_gid(int gid)
|
||||||
|
{
|
||||||
|
gid_t x = gid;
|
||||||
|
if (setgroups(1,&x) == -1) return -1;
|
||||||
|
return setgid(gid); /* _should_ be redundant, but on some systems it isn't */
|
||||||
|
}
|
||||||
|
|
||||||
|
int prot_uid(int uid)
|
||||||
|
{
|
||||||
|
return setuid(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** readclose.c ***/
|
||||||
|
|
||||||
|
int readclose_append(int fd,stralloc *sa,unsigned bufsize)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
for (;;) {
|
||||||
|
if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
|
||||||
|
r = read(fd,sa->s + sa->len,bufsize);
|
||||||
|
if (r == -1) if (errno == EINTR) continue;
|
||||||
|
if (r <= 0) { close(fd); return r; }
|
||||||
|
sa->len += r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int readclose(int fd,stralloc *sa,unsigned bufsize)
|
||||||
|
{
|
||||||
|
if (!stralloc_copys(sa,"")) { close(fd); return -1; }
|
||||||
|
return readclose_append(fd,sa,bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** scan_ulong.c ***/
|
||||||
|
|
||||||
|
unsigned scan_ulong(const char *s,unsigned long *u)
|
||||||
|
{
|
||||||
|
unsigned pos = 0;
|
||||||
|
unsigned long result = 0;
|
||||||
|
unsigned long c;
|
||||||
|
while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) {
|
||||||
|
result = result * 10 + c;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
*u = result;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** seek_set.c ***/
|
||||||
|
|
||||||
|
int seek_set(int fd,seek_pos pos)
|
||||||
|
{
|
||||||
|
if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** sig.c ***/
|
||||||
|
|
||||||
|
int sig_alarm = SIGALRM;
|
||||||
|
int sig_child = SIGCHLD;
|
||||||
|
int sig_cont = SIGCONT;
|
||||||
|
int sig_hangup = SIGHUP;
|
||||||
|
int sig_int = SIGINT;
|
||||||
|
int sig_pipe = SIGPIPE;
|
||||||
|
int sig_term = SIGTERM;
|
||||||
|
|
||||||
|
void (*sig_defaulthandler)(int) = SIG_DFL;
|
||||||
|
void (*sig_ignorehandler)(int) = SIG_IGN;
|
||||||
|
|
||||||
|
|
||||||
|
/*** sig_block.c ***/
|
||||||
|
|
||||||
|
void sig_block(int sig)
|
||||||
|
{
|
||||||
|
sigset_t ss;
|
||||||
|
sigemptyset(&ss);
|
||||||
|
sigaddset(&ss,sig);
|
||||||
|
sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sig_unblock(int sig)
|
||||||
|
{
|
||||||
|
sigset_t ss;
|
||||||
|
sigemptyset(&ss);
|
||||||
|
sigaddset(&ss,sig);
|
||||||
|
sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sig_blocknone(void)
|
||||||
|
{
|
||||||
|
sigset_t ss;
|
||||||
|
sigemptyset(&ss);
|
||||||
|
sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** sig_catch.c ***/
|
||||||
|
|
||||||
|
void sig_catch(int sig,void (*f)(int))
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = f;
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(sig,&sa,(struct sigaction *) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** sig_pause.c ***/
|
||||||
|
|
||||||
|
void sig_pause(void)
|
||||||
|
{
|
||||||
|
sigset_t ss;
|
||||||
|
sigemptyset(&ss);
|
||||||
|
sigsuspend(&ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** str_chr.c ***/
|
||||||
|
|
||||||
|
unsigned str_chr(const char *s,int c)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
const char *t;
|
||||||
|
|
||||||
|
ch = c;
|
||||||
|
t = s;
|
||||||
|
for (;;) {
|
||||||
|
if (!*t) break; if (*t == ch) break; ++t;
|
||||||
|
if (!*t) break; if (*t == ch) break; ++t;
|
||||||
|
if (!*t) break; if (*t == ch) break; ++t;
|
||||||
|
if (!*t) break; if (*t == ch) break; ++t;
|
||||||
|
}
|
||||||
|
return t - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** wait_nohang.c ***/
|
||||||
|
|
||||||
|
int wait_nohang(int *wstat)
|
||||||
|
{
|
||||||
|
return waitpid(-1,wstat,WNOHANG);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** wait_pid.c ***/
|
||||||
|
|
||||||
|
int wait_pid(int *wstat, int pid)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
do
|
||||||
|
r = waitpid(pid,wstat,0);
|
||||||
|
while ((r == -1) && (errno == EINTR));
|
||||||
|
return r;
|
||||||
|
}
|
403
runit/runit_lib.h
Normal file
403
runit/runit_lib.h
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2001-2006, Gerrit Pape
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** buffer.h ***/
|
||||||
|
|
||||||
|
typedef struct buffer {
|
||||||
|
char *x;
|
||||||
|
unsigned p;
|
||||||
|
unsigned n;
|
||||||
|
int fd;
|
||||||
|
int (*op)(int fd,char *buf,unsigned len);
|
||||||
|
} buffer;
|
||||||
|
|
||||||
|
#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) }
|
||||||
|
#define BUFFER_INSIZE 8192
|
||||||
|
#define BUFFER_OUTSIZE 8192
|
||||||
|
|
||||||
|
extern void buffer_init(buffer *,int (*)(int fd,char *buf,unsigned len),int,char *,unsigned);
|
||||||
|
|
||||||
|
extern int buffer_flush(buffer *);
|
||||||
|
extern int buffer_put(buffer *,const char *,unsigned);
|
||||||
|
extern int buffer_putalign(buffer *,const char *,unsigned);
|
||||||
|
extern int buffer_putflush(buffer *,const char *,unsigned);
|
||||||
|
extern int buffer_puts(buffer *,const char *);
|
||||||
|
extern int buffer_putsalign(buffer *,const char *);
|
||||||
|
extern int buffer_putsflush(buffer *,const char *);
|
||||||
|
|
||||||
|
#define buffer_PUTC(s,c) \
|
||||||
|
( ((s)->n != (s)->p) \
|
||||||
|
? ( (s)->x[(s)->p++] = (c), 0 ) \
|
||||||
|
: buffer_put((s),&(c),1) \
|
||||||
|
)
|
||||||
|
|
||||||
|
extern int buffer_get(buffer *,char *,unsigned);
|
||||||
|
extern int buffer_bget(buffer *,char *,unsigned);
|
||||||
|
extern int buffer_feed(buffer *);
|
||||||
|
|
||||||
|
extern char *buffer_peek(buffer *);
|
||||||
|
extern void buffer_seek(buffer *,unsigned);
|
||||||
|
|
||||||
|
#define buffer_PEEK(s) ( (s)->x + (s)->n )
|
||||||
|
#define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) )
|
||||||
|
|
||||||
|
#define buffer_GETC(s,c) \
|
||||||
|
( ((s)->p > 0) \
|
||||||
|
? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \
|
||||||
|
: buffer_get((s),(c),1) \
|
||||||
|
)
|
||||||
|
|
||||||
|
extern int buffer_copy(buffer *,buffer *);
|
||||||
|
|
||||||
|
extern int buffer_unixread(int,char *,unsigned);
|
||||||
|
/* Actually, int buffer_unixwrite(int,const char *,unsigned),
|
||||||
|
but that 'const' will produce warnings... oh well */
|
||||||
|
extern int buffer_unixwrite(int,char *,unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** byte.h ***/
|
||||||
|
|
||||||
|
extern unsigned byte_chr(char *s,unsigned n,int c);
|
||||||
|
|
||||||
|
|
||||||
|
/*** coe.h ***/
|
||||||
|
|
||||||
|
extern int coe(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** direntry.h ***/
|
||||||
|
|
||||||
|
#define direntry struct dirent
|
||||||
|
|
||||||
|
|
||||||
|
/*** fd.h ***/
|
||||||
|
|
||||||
|
extern int fd_copy(int,int);
|
||||||
|
extern int fd_move(int,int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** fifo.h ***/
|
||||||
|
|
||||||
|
extern int fifo_make(const char *,int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** fmt.h ***/
|
||||||
|
|
||||||
|
#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
|
||||||
|
#define FMT_LEN ((char *) 0) /* convenient abbreviation */
|
||||||
|
|
||||||
|
extern unsigned fmt_uint(char *,unsigned);
|
||||||
|
extern unsigned fmt_uint0(char *,unsigned,unsigned);
|
||||||
|
extern unsigned fmt_xint(char *,unsigned);
|
||||||
|
extern unsigned fmt_nbbint(char *,unsigned,unsigned,unsigned,unsigned);
|
||||||
|
extern unsigned fmt_ushort(char *,unsigned short);
|
||||||
|
extern unsigned fmt_xshort(char *,unsigned short);
|
||||||
|
extern unsigned fmt_nbbshort(char *,unsigned,unsigned,unsigned,unsigned short);
|
||||||
|
extern unsigned fmt_ulong(char *,unsigned long);
|
||||||
|
extern unsigned fmt_xlong(char *,unsigned long);
|
||||||
|
extern unsigned fmt_nbblong(char *,unsigned,unsigned,unsigned,unsigned long);
|
||||||
|
|
||||||
|
extern unsigned fmt_plusminus(char *,int);
|
||||||
|
extern unsigned fmt_minus(char *,int);
|
||||||
|
extern unsigned fmt_0x(char *,int);
|
||||||
|
|
||||||
|
extern unsigned fmt_str(char *,const char *);
|
||||||
|
extern unsigned fmt_strn(char *,const char *,unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** tai.h ***/
|
||||||
|
|
||||||
|
struct tai {
|
||||||
|
uint64_t x;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64_t) (u)))
|
||||||
|
|
||||||
|
extern void tai_now(struct tai *);
|
||||||
|
|
||||||
|
#define tai_approx(t) ((double) ((t)->x))
|
||||||
|
|
||||||
|
extern void tai_add(struct tai *,const struct tai *,const struct tai *);
|
||||||
|
extern void tai_sub(struct tai *,const struct tai *,const struct tai *);
|
||||||
|
#define tai_less(t,u) ((t)->x < (u)->x)
|
||||||
|
|
||||||
|
#define TAI_PACK 8
|
||||||
|
extern void tai_pack(char *,const struct tai *);
|
||||||
|
extern void tai_unpack(const char *,struct tai *);
|
||||||
|
|
||||||
|
extern void tai_uint(struct tai *,unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** taia.h ***/
|
||||||
|
|
||||||
|
struct taia {
|
||||||
|
struct tai sec;
|
||||||
|
unsigned long nano; /* 0...999999999 */
|
||||||
|
unsigned long atto; /* 0...999999999 */
|
||||||
|
} ;
|
||||||
|
|
||||||
|
extern void taia_tai(const struct taia *,struct tai *);
|
||||||
|
|
||||||
|
extern void taia_now(struct taia *);
|
||||||
|
|
||||||
|
extern double taia_approx(const struct taia *);
|
||||||
|
extern double taia_frac(const struct taia *);
|
||||||
|
|
||||||
|
extern void taia_add(struct taia *,const struct taia *,const struct taia *);
|
||||||
|
extern void taia_addsec(struct taia *,const struct taia *,int);
|
||||||
|
extern void taia_sub(struct taia *,const struct taia *,const struct taia *);
|
||||||
|
extern void taia_half(struct taia *,const struct taia *);
|
||||||
|
extern int taia_less(const struct taia *,const struct taia *);
|
||||||
|
|
||||||
|
#define TAIA_PACK 16
|
||||||
|
extern void taia_pack(char *,const struct taia *);
|
||||||
|
extern void taia_unpack(const char *,struct taia *);
|
||||||
|
|
||||||
|
#define TAIA_FMTFRAC 19
|
||||||
|
extern unsigned taia_fmtfrac(char *,const struct taia *);
|
||||||
|
|
||||||
|
extern void taia_uint(struct taia *,unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** fmt_ptime.h ***/
|
||||||
|
|
||||||
|
#define FMT_PTIME 30
|
||||||
|
|
||||||
|
extern unsigned fmt_ptime(char *, struct taia *);
|
||||||
|
extern unsigned fmt_taia(char *, struct taia *);
|
||||||
|
|
||||||
|
|
||||||
|
/*** gen_alloc.h ***/
|
||||||
|
|
||||||
|
#define GEN_ALLOC_typedef(ta,type,field,len,a) \
|
||||||
|
typedef struct ta { type *field; unsigned len; unsigned a; } ta;
|
||||||
|
|
||||||
|
|
||||||
|
/*** gen_allocdefs.h ***/
|
||||||
|
|
||||||
|
#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \
|
||||||
|
int ta_ready(ta *x,unsigned n) \
|
||||||
|
{ unsigned i; \
|
||||||
|
if (x->field) { \
|
||||||
|
i = x->a; \
|
||||||
|
if (n > i) { \
|
||||||
|
x->a = base + n + (n >> 3); \
|
||||||
|
x->field = realloc(x->field,x->a * sizeof(type)); \
|
||||||
|
if (x->field) return 1; \
|
||||||
|
x->a = i; return 0; } \
|
||||||
|
return 1; } \
|
||||||
|
x->len = 0; \
|
||||||
|
return !!(x->field = malloc((x->a = n) * sizeof(type))); }
|
||||||
|
|
||||||
|
#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \
|
||||||
|
int ta_rplus(ta *x,unsigned n) \
|
||||||
|
{ unsigned i; \
|
||||||
|
if (x->field) { \
|
||||||
|
i = x->a; n += x->len; \
|
||||||
|
if (n > i) { \
|
||||||
|
x->a = base + n + (n >> 3); \
|
||||||
|
x->field = realloc(x->field,x->a * sizeof(type)); \
|
||||||
|
if (x->field) return 1; \
|
||||||
|
x->a = i; return 0; } \
|
||||||
|
return 1; } \
|
||||||
|
x->len = 0; \
|
||||||
|
return !!(x->field = malloc((x->a = n) * sizeof(type))); }
|
||||||
|
|
||||||
|
#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \
|
||||||
|
int ta_append(ta *x,const type *i) \
|
||||||
|
{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
|
||||||
|
|
||||||
|
|
||||||
|
/*** stralloc.h ***/
|
||||||
|
|
||||||
|
GEN_ALLOC_typedef(stralloc,char,s,len,a)
|
||||||
|
|
||||||
|
extern int stralloc_ready(stralloc *,unsigned);
|
||||||
|
extern int stralloc_readyplus(stralloc *,unsigned);
|
||||||
|
extern int stralloc_copy(stralloc *,const stralloc *);
|
||||||
|
extern int stralloc_cat(stralloc *,const stralloc *);
|
||||||
|
extern int stralloc_copys(stralloc *,const char *);
|
||||||
|
extern int stralloc_cats(stralloc *,const char *);
|
||||||
|
extern int stralloc_copyb(stralloc *,const char *,unsigned);
|
||||||
|
extern int stralloc_catb(stralloc *,const char *,unsigned);
|
||||||
|
extern int stralloc_append(stralloc *,const char *); /* beware: this takes a pointer to 1 char */
|
||||||
|
extern int stralloc_starts(stralloc *,const char *);
|
||||||
|
|
||||||
|
#define stralloc_0(sa) stralloc_append(sa,"")
|
||||||
|
|
||||||
|
extern int stralloc_catulong0(stralloc *,unsigned long,unsigned);
|
||||||
|
extern int stralloc_catlong0(stralloc *,long,unsigned);
|
||||||
|
|
||||||
|
#define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0))
|
||||||
|
#define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n)))
|
||||||
|
#define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n)))
|
||||||
|
#define stralloc_catint(sa,i) (stralloc_catlong0((sa),(i),0))
|
||||||
|
|
||||||
|
|
||||||
|
/*** iopause.h ***/
|
||||||
|
|
||||||
|
typedef struct pollfd iopause_fd;
|
||||||
|
#define IOPAUSE_READ POLLIN
|
||||||
|
#define IOPAUSE_WRITE POLLOUT
|
||||||
|
|
||||||
|
extern void iopause(iopause_fd *,unsigned,struct taia *,struct taia *);
|
||||||
|
|
||||||
|
|
||||||
|
/*** lock.h ***/
|
||||||
|
|
||||||
|
extern int lock_ex(int);
|
||||||
|
extern int lock_un(int);
|
||||||
|
extern int lock_exnb(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** ndelay.h ***/
|
||||||
|
|
||||||
|
extern int ndelay_on(int);
|
||||||
|
extern int ndelay_off(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** open.h ***/
|
||||||
|
|
||||||
|
extern int open_read(const char *);
|
||||||
|
extern int open_excl(const char *);
|
||||||
|
extern int open_append(const char *);
|
||||||
|
extern int open_trunc(const char *);
|
||||||
|
extern int open_write(const char *);
|
||||||
|
|
||||||
|
|
||||||
|
/*** openreadclose.h ***/
|
||||||
|
|
||||||
|
extern int openreadclose(const char *,stralloc *,unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** pathexec.h ***/
|
||||||
|
|
||||||
|
extern void pathexec_run(const char *,char *const *,char *const *);
|
||||||
|
extern int pathexec_env(const char *,const char *);
|
||||||
|
extern void pathexec(char **);
|
||||||
|
|
||||||
|
|
||||||
|
/*** pmatch.h ***/
|
||||||
|
|
||||||
|
extern unsigned pmatch(const char *, const char *, unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** prot.h ***/
|
||||||
|
|
||||||
|
extern int prot_gid(int);
|
||||||
|
extern int prot_uid(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** readclose.h ***/
|
||||||
|
|
||||||
|
extern int readclose_append(int,stralloc *,unsigned);
|
||||||
|
extern int readclose(int,stralloc *,unsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/*** scan.h ***/
|
||||||
|
|
||||||
|
extern unsigned scan_uint(const char *,unsigned *);
|
||||||
|
extern unsigned scan_xint(const char *,unsigned *);
|
||||||
|
extern unsigned scan_nbbint(const char *,unsigned,unsigned,unsigned,unsigned *);
|
||||||
|
extern unsigned scan_ushort(const char *,unsigned short *);
|
||||||
|
extern unsigned scan_xshort(const char *,unsigned short *);
|
||||||
|
extern unsigned scan_nbbshort(const char *,unsigned,unsigned,unsigned,unsigned short *);
|
||||||
|
extern unsigned scan_ulong(const char *,unsigned long *);
|
||||||
|
extern unsigned scan_xlong(const char *,unsigned long *);
|
||||||
|
extern unsigned scan_nbblong(const char *,unsigned,unsigned,unsigned,unsigned long *);
|
||||||
|
|
||||||
|
extern unsigned scan_plusminus(const char *,int *);
|
||||||
|
extern unsigned scan_0x(const char *,unsigned *);
|
||||||
|
|
||||||
|
extern unsigned scan_whitenskip(const char *,unsigned);
|
||||||
|
extern unsigned scan_nonwhitenskip(const char *,unsigned);
|
||||||
|
extern unsigned scan_charsetnskip(const char *,const char *,unsigned);
|
||||||
|
extern unsigned scan_noncharsetnskip(const char *,const char *,unsigned);
|
||||||
|
|
||||||
|
extern unsigned scan_strncmp(const char *,const char *,unsigned);
|
||||||
|
extern unsigned scan_memcmp(const char *,const char *,unsigned);
|
||||||
|
|
||||||
|
extern unsigned scan_long(const char *,long *);
|
||||||
|
extern unsigned scan_8long(const char *,unsigned long *);
|
||||||
|
|
||||||
|
|
||||||
|
/*** seek.h ***/
|
||||||
|
|
||||||
|
typedef unsigned long seek_pos;
|
||||||
|
|
||||||
|
extern seek_pos seek_cur(int);
|
||||||
|
|
||||||
|
extern int seek_set(int,seek_pos);
|
||||||
|
extern int seek_end(int);
|
||||||
|
|
||||||
|
extern int seek_trunc(int,seek_pos);
|
||||||
|
|
||||||
|
#define seek_begin(fd) (seek_set((fd),(seek_pos) 0))
|
||||||
|
|
||||||
|
|
||||||
|
/*** sig.h ***/
|
||||||
|
|
||||||
|
extern int sig_alarm;
|
||||||
|
extern int sig_child;
|
||||||
|
extern int sig_cont;
|
||||||
|
extern int sig_hangup;
|
||||||
|
extern int sig_int;
|
||||||
|
extern int sig_pipe;
|
||||||
|
extern int sig_term;
|
||||||
|
|
||||||
|
extern void (*sig_defaulthandler)(int);
|
||||||
|
extern void (*sig_ignorehandler)(int);
|
||||||
|
|
||||||
|
extern void sig_catch(int,void (*)(int));
|
||||||
|
#define sig_ignore(s) (sig_catch((s),sig_ignorehandler))
|
||||||
|
#define sig_uncatch(s) (sig_catch((s),sig_defaulthandler))
|
||||||
|
|
||||||
|
extern void sig_block(int);
|
||||||
|
extern void sig_unblock(int);
|
||||||
|
extern void sig_blocknone(void);
|
||||||
|
extern void sig_pause(void);
|
||||||
|
|
||||||
|
extern void sig_dfl(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*** str.h ***/
|
||||||
|
|
||||||
|
extern unsigned str_chr(const char *,int); /* never returns NULL */
|
||||||
|
|
||||||
|
#define str_diff(s,t) strcmp((s),(t))
|
||||||
|
#define str_equal(s,t) (!strcmp((s),(t)))
|
||||||
|
|
||||||
|
|
||||||
|
/*** wait.h ***/
|
||||||
|
|
||||||
|
extern int wait_pid(int *wstat, int pid);
|
||||||
|
extern int wait_nohang(int *wstat);
|
||||||
|
|
||||||
|
#define wait_crashed(w) ((w) & 127)
|
||||||
|
#define wait_exitcode(w) ((w) >> 8)
|
||||||
|
#define wait_stopsig(w) ((w) >> 8)
|
||||||
|
#define wait_stopped(w) (((w) & 127) == 127)
|
880
runit/svlogd.c
Normal file
880
runit/svlogd.c
Normal file
@ -0,0 +1,880 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2001-2006, Gerrit Pape
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
|
||||||
|
/* TODO: depends on runit_lib.c - review and reduce/eliminate */
|
||||||
|
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include "busybox.h"
|
||||||
|
#include "runit_lib.h"
|
||||||
|
|
||||||
|
static unsigned verbose;
|
||||||
|
static int linemax = 1000;
|
||||||
|
static int buflen = 1024;
|
||||||
|
static int linelen;
|
||||||
|
|
||||||
|
static char **fndir;
|
||||||
|
static int fdwdir;
|
||||||
|
static int wstat;
|
||||||
|
static struct taia trotate;
|
||||||
|
|
||||||
|
static char *line;
|
||||||
|
static unsigned exitasap;
|
||||||
|
static unsigned rotateasap;
|
||||||
|
static unsigned reopenasap;
|
||||||
|
static unsigned linecomplete = 1;
|
||||||
|
static unsigned tmaxflag;
|
||||||
|
static iopause_fd in;
|
||||||
|
|
||||||
|
static const char *replace = "";
|
||||||
|
static char repl;
|
||||||
|
|
||||||
|
static struct logdir {
|
||||||
|
char *btmp;
|
||||||
|
/* pattern list to match, in "aa\0bb\0\cc\0\0" form */
|
||||||
|
char *inst;
|
||||||
|
char *processor;
|
||||||
|
char *name;
|
||||||
|
unsigned size;
|
||||||
|
unsigned sizemax;
|
||||||
|
unsigned nmax;
|
||||||
|
unsigned nmin;
|
||||||
|
/* int (not long) because of taia_uint() usage: */
|
||||||
|
unsigned tmax;
|
||||||
|
int ppid;
|
||||||
|
int fddir;
|
||||||
|
int fdcur;
|
||||||
|
int fdlock;
|
||||||
|
struct taia trotate;
|
||||||
|
char fnsave[FMT_PTIME];
|
||||||
|
char match;
|
||||||
|
char matcherr;
|
||||||
|
} *dir;
|
||||||
|
static unsigned dirn = 0;
|
||||||
|
|
||||||
|
#define FATAL "fatal: "
|
||||||
|
#define WARNING "warning: "
|
||||||
|
#define PAUSE "pausing: "
|
||||||
|
#define INFO "info: "
|
||||||
|
|
||||||
|
#define usage() bb_show_usage()
|
||||||
|
static void fatalx(char *m0)
|
||||||
|
{
|
||||||
|
bb_error_msg_and_die(FATAL"%s", m0);
|
||||||
|
}
|
||||||
|
static void warn(char *m0) {
|
||||||
|
bb_perror_msg(WARNING"%s", m0);
|
||||||
|
}
|
||||||
|
static void warn2(char *m0, char *m1)
|
||||||
|
{
|
||||||
|
bb_perror_msg(WARNING"%s: %s", m0, m1);
|
||||||
|
}
|
||||||
|
static void warnx(char *m0, char *m1)
|
||||||
|
{
|
||||||
|
bb_error_msg(WARNING"%s: %s", m0, m1);
|
||||||
|
}
|
||||||
|
static void pause_nomem(void)
|
||||||
|
{
|
||||||
|
bb_error_msg(PAUSE"out of memory"); sleep(3);
|
||||||
|
}
|
||||||
|
static void pause1cannot(char *m0)
|
||||||
|
{
|
||||||
|
bb_perror_msg(PAUSE"cannot %s", m0); sleep(3);
|
||||||
|
}
|
||||||
|
static void pause2cannot(char *m0, char *m1)
|
||||||
|
{
|
||||||
|
bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
|
||||||
|
sleep(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* wstrdup(const char *str)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
while (!(s = strdup(str))) pause_nomem();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned processorstart(struct logdir *ld)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
if (!ld->processor) return 0;
|
||||||
|
if (ld->ppid) {
|
||||||
|
warnx("processor already running", ld->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while ((pid = fork()) == -1)
|
||||||
|
pause2cannot("fork for processor", ld->name);
|
||||||
|
if (!pid) {
|
||||||
|
char *prog[4];
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* child */
|
||||||
|
sig_uncatch(sig_term);
|
||||||
|
sig_uncatch(sig_alarm);
|
||||||
|
sig_uncatch(sig_hangup);
|
||||||
|
sig_unblock(sig_term);
|
||||||
|
sig_unblock(sig_alarm);
|
||||||
|
sig_unblock(sig_hangup);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
|
||||||
|
fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
|
||||||
|
if (fd_move(0, fd) == -1)
|
||||||
|
bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name);
|
||||||
|
ld->fnsave[26] = 't';
|
||||||
|
fd = xopen3(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT, 0644);
|
||||||
|
if (fd_move(1, fd) == -1)
|
||||||
|
bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name);
|
||||||
|
fd = open_read("state");
|
||||||
|
if (fd == -1) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
|
||||||
|
close(xopen3("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT, 0644));
|
||||||
|
fd = xopen("state", O_RDONLY|O_NDELAY);
|
||||||
|
}
|
||||||
|
if (fd_move(4, fd) == -1)
|
||||||
|
bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name);
|
||||||
|
fd = xopen3("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT, 0644);
|
||||||
|
if (fd_move(5, fd) == -1)
|
||||||
|
bb_perror_msg_and_die(FATAL"cannot %s processor %s", "move filedescriptor for", ld->name);
|
||||||
|
|
||||||
|
prog[0] = "sh";
|
||||||
|
prog[1] = "-c";
|
||||||
|
prog[2] = ld->processor;
|
||||||
|
prog[3] = '\0';
|
||||||
|
execve("/bin/sh", prog, environ);
|
||||||
|
bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
|
||||||
|
}
|
||||||
|
ld->ppid = pid;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned processorstop(struct logdir *ld)
|
||||||
|
{
|
||||||
|
char f[28];
|
||||||
|
|
||||||
|
if (ld->ppid) {
|
||||||
|
sig_unblock(sig_hangup);
|
||||||
|
while (wait_pid(&wstat, ld->ppid) == -1)
|
||||||
|
pause2cannot("wait for processor", ld->name);
|
||||||
|
sig_block(sig_hangup);
|
||||||
|
ld->ppid = 0;
|
||||||
|
}
|
||||||
|
if (ld->fddir == -1) return 1;
|
||||||
|
while (fchdir(ld->fddir) == -1)
|
||||||
|
pause2cannot("change directory, want processor", ld->name);
|
||||||
|
if (wait_exitcode(wstat) != 0) {
|
||||||
|
warnx("processor failed, restart", ld->name);
|
||||||
|
ld->fnsave[26] = 't';
|
||||||
|
unlink(ld->fnsave);
|
||||||
|
ld->fnsave[26] = 'u';
|
||||||
|
processorstart(ld);
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
return ld->processor ? 0 : 1;
|
||||||
|
}
|
||||||
|
ld->fnsave[26] = 't';
|
||||||
|
memcpy(f, ld->fnsave, 26);
|
||||||
|
f[26] = 's';
|
||||||
|
f[27] = '\0';
|
||||||
|
while (rename(ld->fnsave, f) == -1)
|
||||||
|
pause2cannot("rename processed", ld->name);
|
||||||
|
while (chmod(f, 0744) == -1)
|
||||||
|
pause2cannot("set mode of processed", ld->name);
|
||||||
|
ld->fnsave[26] = 'u';
|
||||||
|
if (unlink(ld->fnsave) == -1)
|
||||||
|
bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
|
||||||
|
while (rename("newstate", "state") == -1)
|
||||||
|
pause2cannot("rename state", ld->name);
|
||||||
|
if (verbose) bb_error_msg(INFO"processed: %s/%s", ld->name, f);
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rmoldest(struct logdir *ld)
|
||||||
|
{
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *f;
|
||||||
|
char oldest[FMT_PTIME];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
|
||||||
|
while (!(d = opendir(".")))
|
||||||
|
pause2cannot("open directory, want rotate", ld->name);
|
||||||
|
errno = 0;
|
||||||
|
while ((f = readdir(d))) {
|
||||||
|
if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
|
||||||
|
if (f->d_name[26] == 't') {
|
||||||
|
if (unlink(f->d_name) == -1)
|
||||||
|
warn2("cannot unlink processor leftover", f->d_name);
|
||||||
|
} else {
|
||||||
|
++n;
|
||||||
|
if (strcmp(f->d_name, oldest) < 0)
|
||||||
|
memcpy(oldest, f->d_name, 27);
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errno) warn2("cannot read directory", ld->name);
|
||||||
|
closedir(d);
|
||||||
|
|
||||||
|
if (ld->nmax && (n > ld->nmax)) {
|
||||||
|
if (verbose) bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
|
||||||
|
if ((*oldest == '@') && (unlink(oldest) == -1))
|
||||||
|
warn2("cannot unlink oldest logfile", ld->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned rotate(struct logdir *ld)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
struct taia now;
|
||||||
|
|
||||||
|
if (ld->fddir == -1) {
|
||||||
|
ld->tmax = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ld->ppid)
|
||||||
|
while(!processorstop(ld))
|
||||||
|
/* wait */;
|
||||||
|
|
||||||
|
while (fchdir(ld->fddir) == -1)
|
||||||
|
pause2cannot("change directory, want rotate", ld->name);
|
||||||
|
|
||||||
|
/* create new filename */
|
||||||
|
ld->fnsave[25] = '.';
|
||||||
|
ld->fnsave[26] = 's';
|
||||||
|
if (ld->processor)
|
||||||
|
ld->fnsave[26] = 'u';
|
||||||
|
ld->fnsave[27] = '\0';
|
||||||
|
do {
|
||||||
|
taia_now(&now);
|
||||||
|
fmt_taia(ld->fnsave, &now);
|
||||||
|
errno = 0;
|
||||||
|
} while ((stat(ld->fnsave, &st) != -1) || (errno != ENOENT));
|
||||||
|
|
||||||
|
if (ld->tmax && taia_less(&ld->trotate, &now)) {
|
||||||
|
taia_uint(&ld->trotate, ld->tmax);
|
||||||
|
taia_add(&ld->trotate, &now, &ld->trotate);
|
||||||
|
if (taia_less(&ld->trotate, &trotate))
|
||||||
|
trotate = ld->trotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ld->size > 0) {
|
||||||
|
while (fsync(ld->fdcur) == -1)
|
||||||
|
pause2cannot("fsync current logfile", ld->name);
|
||||||
|
while (fchmod(ld->fdcur, 0744) == -1)
|
||||||
|
pause2cannot("set mode of current", ld->name);
|
||||||
|
close(ld->fdcur);
|
||||||
|
if (verbose) {
|
||||||
|
bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
|
||||||
|
ld->fnsave, ld->size);
|
||||||
|
}
|
||||||
|
while (rename("current", ld->fnsave) == -1)
|
||||||
|
pause2cannot("rename current", ld->name);
|
||||||
|
while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
|
||||||
|
pause2cannot("create new current", ld->name);
|
||||||
|
coe(ld->fdcur);
|
||||||
|
ld->size = 0;
|
||||||
|
while (fchmod(ld->fdcur, 0644) == -1)
|
||||||
|
pause2cannot("set mode of current", ld->name);
|
||||||
|
rmoldest(ld);
|
||||||
|
processorstart(ld);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int buffer_pwrite(int n, char *s, unsigned len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct logdir *ld = &dir[n];
|
||||||
|
|
||||||
|
if (ld->sizemax) {
|
||||||
|
if (ld->size >= ld->sizemax)
|
||||||
|
rotate(ld);
|
||||||
|
if (len > (ld->sizemax - ld->size))
|
||||||
|
len = ld->sizemax - ld->size;
|
||||||
|
}
|
||||||
|
while ((i = write(ld->fdcur, s, len)) == -1) {
|
||||||
|
if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *f;
|
||||||
|
char oldest[FMT_PTIME];
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
while (fchdir(ld->fddir) == -1)
|
||||||
|
pause2cannot("change directory, want remove old logfile",
|
||||||
|
ld->name);
|
||||||
|
oldest[0] = 'A';
|
||||||
|
oldest[1] = oldest[27] = '\0';
|
||||||
|
while (!(d = opendir(".")))
|
||||||
|
pause2cannot("open directory, want remove old logfile",
|
||||||
|
ld->name);
|
||||||
|
errno = 0;
|
||||||
|
while ((f = readdir(d)))
|
||||||
|
if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
|
||||||
|
++j;
|
||||||
|
if (strcmp(f->d_name, oldest) < 0)
|
||||||
|
memcpy(oldest, f->d_name, 27);
|
||||||
|
}
|
||||||
|
if (errno) warn2("cannot read directory, want remove old logfile",
|
||||||
|
ld->name);
|
||||||
|
closedir(d);
|
||||||
|
errno = ENOSPC;
|
||||||
|
if (j > ld->nmin) {
|
||||||
|
if (*oldest == '@') {
|
||||||
|
bb_error_msg(WARNING"out of disk space, delete: %s/%s",
|
||||||
|
ld->name, oldest);
|
||||||
|
errno = 0;
|
||||||
|
if (unlink(oldest) == -1) {
|
||||||
|
warn2("cannot unlink oldest logfile", ld->name);
|
||||||
|
errno = ENOSPC;
|
||||||
|
}
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errno) pause2cannot("write to current", ld->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ld->size += i;
|
||||||
|
if (ld->sizemax)
|
||||||
|
if (s[i-1] == '\n')
|
||||||
|
if (ld->size >= (ld->sizemax - linemax))
|
||||||
|
rotate(ld);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logdir_close(struct logdir *ld)
|
||||||
|
{
|
||||||
|
if (ld->fddir == -1)
|
||||||
|
return;
|
||||||
|
if (verbose)
|
||||||
|
bb_error_msg(INFO"close: %s", ld->name);
|
||||||
|
close(ld->fddir);
|
||||||
|
ld->fddir = -1;
|
||||||
|
if (ld->fdcur == -1)
|
||||||
|
return; /* impossible */
|
||||||
|
while (fsync(ld->fdcur) == -1)
|
||||||
|
pause2cannot("fsync current logfile", ld->name);
|
||||||
|
while (fchmod(ld->fdcur, 0744) == -1)
|
||||||
|
pause2cannot("set mode of current", ld->name);
|
||||||
|
close(ld->fdcur);
|
||||||
|
ld->fdcur = -1;
|
||||||
|
if (ld->fdlock == -1)
|
||||||
|
return; /* impossible */
|
||||||
|
close(ld->fdlock);
|
||||||
|
ld->fdlock = -1;
|
||||||
|
free(ld->processor);
|
||||||
|
ld->processor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned logdir_open(struct logdir *ld, const char *fn)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
struct taia now;
|
||||||
|
char *new, *s, *np;
|
||||||
|
int i;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
ld->fddir = open(fn, O_RDONLY|O_NDELAY);
|
||||||
|
if (ld->fddir == -1) {
|
||||||
|
warn2("cannot open log directory", (char*)fn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
coe(ld->fddir);
|
||||||
|
if (fchdir(ld->fddir) == -1) {
|
||||||
|
logdir_close(ld);
|
||||||
|
warn2("cannot change directory", (char*)fn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
|
||||||
|
if ((ld->fdlock == -1)
|
||||||
|
|| (lock_exnb(ld->fdlock) == -1)
|
||||||
|
) {
|
||||||
|
logdir_close(ld);
|
||||||
|
warn2("cannot lock directory", (char*)fn);
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
coe(ld->fdlock);
|
||||||
|
|
||||||
|
ld->size = 0;
|
||||||
|
ld->sizemax = 1000000;
|
||||||
|
ld->nmax = ld->nmin = 10;
|
||||||
|
ld->tmax = 0;
|
||||||
|
ld->name = (char*)fn;
|
||||||
|
ld->ppid = 0;
|
||||||
|
ld->match = '+';
|
||||||
|
free(ld->inst); ld->inst = NULL;
|
||||||
|
free(ld->processor); ld->processor = NULL;
|
||||||
|
|
||||||
|
/* read config */
|
||||||
|
i = open_read_close("config", buf, sizeof(buf));
|
||||||
|
if (i < 0)
|
||||||
|
warn2("cannot read config", ld->name);
|
||||||
|
if (i > 0) {
|
||||||
|
if (verbose) bb_error_msg(INFO"read: %s/config", ld->name);
|
||||||
|
s = buf;
|
||||||
|
while (s) {
|
||||||
|
np = strchr(s, '\n');
|
||||||
|
if (np) *np++ = '\0';
|
||||||
|
switch (s[0]) {
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
while (1) {
|
||||||
|
int l = asprintf(&new, "%s%s\n", ld->inst?:"", s);
|
||||||
|
if (l >= 0 && new) break;
|
||||||
|
pause_nomem();
|
||||||
|
}
|
||||||
|
free(ld->inst);
|
||||||
|
ld->inst = new;
|
||||||
|
break;
|
||||||
|
case 's': {
|
||||||
|
static const struct suffix_mult km_suffixes[] = {
|
||||||
|
{ "k", 1024 },
|
||||||
|
{ "m", 1024*1024 },
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
ld->sizemax = xatou_sfx(&s[1], km_suffixes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'n':
|
||||||
|
ld->nmax = xatoi_u(&s[1]);
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
ld->nmin = xatoi_u(&s[1]);
|
||||||
|
break;
|
||||||
|
case 't': {
|
||||||
|
static const struct suffix_mult mh_suffixes[] = {
|
||||||
|
{ "m", 60 },
|
||||||
|
{ "h", 60*60 },
|
||||||
|
/*{ "d", 24*60*60 },*/
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
ld->tmax = xatou_sfx(&s[1], mh_suffixes);
|
||||||
|
if (ld->tmax) {
|
||||||
|
taia_uint(&ld->trotate, ld->tmax);
|
||||||
|
taia_add(&ld->trotate, &now, &ld->trotate);
|
||||||
|
if (!tmaxflag || taia_less(&ld->trotate, &trotate))
|
||||||
|
trotate = ld->trotate;
|
||||||
|
tmaxflag = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '!':
|
||||||
|
if (s[1]) {
|
||||||
|
free(ld->processor);
|
||||||
|
ld->processor = wstrdup(s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s = np;
|
||||||
|
}
|
||||||
|
/* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
|
||||||
|
s = ld->inst;
|
||||||
|
while (s) {
|
||||||
|
np = strchr(s, '\n');
|
||||||
|
if (np) *np++ = '\0';
|
||||||
|
s = np;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open current */
|
||||||
|
i = stat("current", &st);
|
||||||
|
if (i != -1) {
|
||||||
|
if (st.st_size && ! (st.st_mode & S_IXUSR)) {
|
||||||
|
ld->fnsave[25] = '.';
|
||||||
|
ld->fnsave[26] = 'u';
|
||||||
|
ld->fnsave[27] = '\0';
|
||||||
|
do {
|
||||||
|
taia_now(&now);
|
||||||
|
fmt_taia(ld->fnsave, &now);
|
||||||
|
errno = 0;
|
||||||
|
} while ((stat(ld->fnsave, &st) != -1) || (errno != ENOENT));
|
||||||
|
while (rename("current", ld->fnsave) == -1)
|
||||||
|
pause2cannot("rename current", ld->name);
|
||||||
|
rmoldest(ld);
|
||||||
|
i = -1;
|
||||||
|
} else {
|
||||||
|
/* Be paranoid: st.st_size can be not just bigger, but WIDER! */
|
||||||
|
/* (bug in original svlogd. remove this comment when fixed there) */
|
||||||
|
ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
logdir_close(ld);
|
||||||
|
warn2("cannot stat current", ld->name);
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
|
||||||
|
pause2cannot("open current", ld->name);
|
||||||
|
coe(ld->fdcur);
|
||||||
|
while (fchmod(ld->fdcur, 0644) == -1)
|
||||||
|
pause2cannot("set mode of current", ld->name);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
|
||||||
|
else bb_error_msg(INFO"new: %s/current", ld->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fchdir(fdwdir) == -1)
|
||||||
|
pause1cannot("change to initial working directory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logdirs_reopen(void)
|
||||||
|
{
|
||||||
|
struct taia now;
|
||||||
|
int l;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
tmaxflag = 0;
|
||||||
|
taia_now(&now);
|
||||||
|
for (l = 0; l < dirn; ++l) {
|
||||||
|
logdir_close(&dir[l]);
|
||||||
|
if (logdir_open(&dir[l], fndir[l])) ok = 1;
|
||||||
|
}
|
||||||
|
if (!ok) fatalx("no functional log directories");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for reading stdin */
|
||||||
|
static int buffer_pread(int fd, char *s, unsigned len)
|
||||||
|
{
|
||||||
|
struct taia now;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (rotateasap) {
|
||||||
|
for (i = 0; i < dirn; ++i)
|
||||||
|
rotate(dir+i);
|
||||||
|
rotateasap = 0;
|
||||||
|
}
|
||||||
|
if (exitasap) {
|
||||||
|
if (linecomplete)
|
||||||
|
return 0;
|
||||||
|
len = 1;
|
||||||
|
}
|
||||||
|
if (reopenasap) {
|
||||||
|
logdirs_reopen();
|
||||||
|
reopenasap = 0;
|
||||||
|
}
|
||||||
|
taia_now(&now);
|
||||||
|
taia_uint(&trotate, 2744);
|
||||||
|
taia_add(&trotate, &now, &trotate);
|
||||||
|
for (i = 0; i < dirn; ++i)
|
||||||
|
if (dir[i].tmax) {
|
||||||
|
if (taia_less(&dir[i].trotate, &now))
|
||||||
|
rotate(dir+i);
|
||||||
|
if (taia_less(&dir[i].trotate, &trotate))
|
||||||
|
trotate = dir[i].trotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* Comment? */
|
||||||
|
sig_unblock(sig_term);
|
||||||
|
sig_unblock(sig_child);
|
||||||
|
sig_unblock(sig_alarm);
|
||||||
|
sig_unblock(sig_hangup);
|
||||||
|
iopause(&in, 1, &trotate, &now);
|
||||||
|
sig_block(sig_term);
|
||||||
|
sig_block(sig_child);
|
||||||
|
sig_block(sig_alarm);
|
||||||
|
sig_block(sig_hangup);
|
||||||
|
i = safe_read(fd, s, len);
|
||||||
|
if (i >= 0) break;
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
warn("cannot read standard input");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* else: EAGAIN - normal, repeat silently */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
int cnt;
|
||||||
|
linecomplete = (s[i-1] == '\n');
|
||||||
|
if (!repl) return i;
|
||||||
|
|
||||||
|
cnt = i;
|
||||||
|
while (--cnt >= 0) {
|
||||||
|
char ch = *s;
|
||||||
|
if (ch != '\n') {
|
||||||
|
if (ch < 32 || ch > 126)
|
||||||
|
*s = repl;
|
||||||
|
else {
|
||||||
|
int j;
|
||||||
|
for (j = 0; replace[j]; ++j) {
|
||||||
|
if (ch == replace[j]) {
|
||||||
|
*s = repl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sig_term_handler(int sig_no)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
bb_error_msg(INFO"sig%s received", "term");
|
||||||
|
exitasap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sig_child_handler(int sig_no)
|
||||||
|
{
|
||||||
|
int pid, l;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
bb_error_msg(INFO"sig%s received", "child");
|
||||||
|
while ((pid = wait_nohang(&wstat)) > 0)
|
||||||
|
for (l = 0; l < dirn; ++l)
|
||||||
|
if (dir[l].ppid == pid) {
|
||||||
|
dir[l].ppid = 0;
|
||||||
|
processorstop(&dir[l]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sig_alarm_handler(int sig_no)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
bb_error_msg(INFO"sig%s received", "alarm");
|
||||||
|
rotateasap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sig_hangup_handler(int sig_no)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
bb_error_msg(INFO"sig%s received", "hangup");
|
||||||
|
reopenasap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logmatch(struct logdir *ld)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
ld->match = '+';
|
||||||
|
ld->matcherr = 'E';
|
||||||
|
s = ld->inst;
|
||||||
|
while (s && s[0]) {
|
||||||
|
switch (s[0]) {
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
if (pmatch(s+1, line, linelen))
|
||||||
|
ld->match = s[0];
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
if (pmatch(s+1, line, linelen))
|
||||||
|
ld->matcherr = s[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s += strlen(s) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int svlogd_main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct taia now;
|
||||||
|
char *r,*l,*b;
|
||||||
|
ssize_t stdin_cnt = 0;
|
||||||
|
int i;
|
||||||
|
unsigned opt;
|
||||||
|
unsigned timestamp = 0;
|
||||||
|
|
||||||
|
opt_complementary = "tt:vv";
|
||||||
|
opt = getopt32(argc, argv, "r:R:l:b:tv",
|
||||||
|
&r, &replace, &l, &b, ×tamp, &verbose);
|
||||||
|
if (opt & 1) { // -r
|
||||||
|
repl = r[0];
|
||||||
|
if (!repl || r[1]) usage();
|
||||||
|
}
|
||||||
|
if (opt & 2) if (!repl) repl = '_'; // -R
|
||||||
|
if (opt & 4) { // -l
|
||||||
|
linemax = xatou_range(l, 0, 1000);
|
||||||
|
if (linemax == 0) linemax = 1000;
|
||||||
|
if (linemax < 256) linemax = 256;
|
||||||
|
}
|
||||||
|
if (opt & 8) { // -b
|
||||||
|
buflen = xatoi_u(b);
|
||||||
|
if (buflen == 0) buflen = 1024;
|
||||||
|
}
|
||||||
|
//if (opt & 0x10) timestamp++; // -t
|
||||||
|
//if (opt & 0x20) verbose++; // -v
|
||||||
|
if (timestamp > 2) timestamp = 2;
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
dirn = argc;
|
||||||
|
if (dirn <= 0) usage();
|
||||||
|
if (buflen <= linemax) usage();
|
||||||
|
fdwdir = xopen(".", O_RDONLY|O_NDELAY);
|
||||||
|
coe(fdwdir);
|
||||||
|
dir = xmalloc(dirn * sizeof(struct logdir));
|
||||||
|
for (i = 0; i < dirn; ++i) {
|
||||||
|
dir[i].fddir = -1;
|
||||||
|
dir[i].fdcur = -1;
|
||||||
|
dir[i].btmp = xmalloc(buflen);
|
||||||
|
dir[i].ppid = 0;
|
||||||
|
}
|
||||||
|
line = xmalloc(linemax + (timestamp ? 26 : 0));
|
||||||
|
fndir = argv;
|
||||||
|
in.fd = 0;
|
||||||
|
in.events = IOPAUSE_READ;
|
||||||
|
ndelay_on(in.fd);
|
||||||
|
|
||||||
|
sig_block(sig_term);
|
||||||
|
sig_block(sig_child);
|
||||||
|
sig_block(sig_alarm);
|
||||||
|
sig_block(sig_hangup);
|
||||||
|
sig_catch(sig_term, sig_term_handler);
|
||||||
|
sig_catch(sig_child, sig_child_handler);
|
||||||
|
sig_catch(sig_alarm, sig_alarm_handler);
|
||||||
|
sig_catch(sig_hangup, sig_hangup_handler);
|
||||||
|
|
||||||
|
logdirs_reopen();
|
||||||
|
|
||||||
|
/* Each iteration processes one line */
|
||||||
|
while (1) {
|
||||||
|
int printlen;
|
||||||
|
char *lineptr = line;
|
||||||
|
char *np;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
/* Prepare timestamp if needed */
|
||||||
|
if (timestamp) {
|
||||||
|
char stamp[FMT_PTIME];
|
||||||
|
taia_now(&now);
|
||||||
|
switch (timestamp) {
|
||||||
|
case 1:
|
||||||
|
fmt_taia(stamp, &now);
|
||||||
|
break;
|
||||||
|
default: /* case 2: */
|
||||||
|
fmt_ptime(stamp, &now);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(line, stamp, 25);
|
||||||
|
line[25] = ' ';
|
||||||
|
lineptr += 26;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lineptr[0..linemax-1] - buffer for stdin */
|
||||||
|
/* (possibly has some unprocessed data from prev loop) */
|
||||||
|
|
||||||
|
/* Refill the buffer if needed */
|
||||||
|
np = memchr(lineptr, '\n', stdin_cnt);
|
||||||
|
i = linemax - stdin_cnt; /* avail. bytes at tail */
|
||||||
|
if (i >= 128 && !exitasap && !np) {
|
||||||
|
int sz = buffer_pread(0, lineptr + stdin_cnt, i);
|
||||||
|
if (sz <= 0) /* EOF or error on stdin */
|
||||||
|
exitasap = 1;
|
||||||
|
else {
|
||||||
|
stdin_cnt += sz;
|
||||||
|
np = memchr(lineptr, '\n', stdin_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stdin_cnt <= 0 && exitasap)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Search for '\n' (in fact, np already holds the result) */
|
||||||
|
linelen = stdin_cnt;
|
||||||
|
if (np) linelen = np - lineptr + 1;
|
||||||
|
/* linelen == no of chars incl. '\n' (or == stdin_cnt) */
|
||||||
|
ch = lineptr[linelen-1];
|
||||||
|
|
||||||
|
printlen = linelen + (timestamp ? 26 : 0);
|
||||||
|
/* write out line[0..printlen-1] to each log destination */
|
||||||
|
for (i = 0; i < dirn; ++i) {
|
||||||
|
struct logdir *ld = &dir[i];
|
||||||
|
if (ld->fddir == -1) continue;
|
||||||
|
if (ld->inst)
|
||||||
|
logmatch(ld);
|
||||||
|
if (ld->matcherr == 'e') {
|
||||||
|
fprintf(stderr, "%.*s%s",
|
||||||
|
printlen, line,
|
||||||
|
(ch != '\n') ? "...\n" : ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (ld->match != '+') continue;
|
||||||
|
buffer_pwrite(i, line, printlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't see '\n' (long input line), */
|
||||||
|
/* read/write repeatedly until we see it */
|
||||||
|
while (ch != '\n') {
|
||||||
|
/* lineptr is emptied now, safe to use as buffer */
|
||||||
|
stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax);
|
||||||
|
if (stdin_cnt <= 0) { /* EOF or error on stdin */
|
||||||
|
lineptr[0] = ch = '\n';
|
||||||
|
linelen = 1;
|
||||||
|
exitasap = 1;
|
||||||
|
stdin_cnt = 1;
|
||||||
|
} else {
|
||||||
|
linelen = stdin_cnt;
|
||||||
|
np = memchr(lineptr, '\n', stdin_cnt);
|
||||||
|
if (np) linelen = np - lineptr + 1;
|
||||||
|
ch = lineptr[linelen-1];
|
||||||
|
}
|
||||||
|
/* linelen == no of chars incl. '\n' (or == stdin_cnt) */
|
||||||
|
for (i = 0; i < dirn; ++i) {
|
||||||
|
if (dir[i].fddir == -1) continue;
|
||||||
|
if (dir[i].match != '+') continue;
|
||||||
|
buffer_pwrite(i, lineptr, linelen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move unprocessed data to the front of line */
|
||||||
|
stdin_cnt -= linelen;
|
||||||
|
if (stdin_cnt > 0) /* TODO: slow if buffer is big */
|
||||||
|
memmove(lineptr, &lineptr[linelen], stdin_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dirn; ++i) {
|
||||||
|
if (dir[i].ppid)
|
||||||
|
while (!processorstop(&dir[i]))
|
||||||
|
/* repeat */;
|
||||||
|
logdir_close(&dir[i]);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user