introduce bb_putchar(). saves ~1800 on uclibc (less on glibc).
[oweals/busybox.git] / networking / inetd.c
index 7c89be28f11a807e82c67c18e9b02dff981ecaee..b164278820a09b044ef9438e0eac78943bb312ee 100644 (file)
@@ -23,7 +23,7 @@
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "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 REGENTS OR CONTRIBUTORS BE LIABLE
@@ -36,8 +36,7 @@
  * SUCH DAMAGE.
  */
 
-/*
- * Inetd - Internet super-server
+/* Inetd - Internet super-server
  *
  * This program invokes all internet services as needed.
  * connection-oriented services are invoked each time a
  * arrives; a process is created and passed a pending message
  * on file descriptor 0.  Datagram servers may either connect
  * to their peer, freeing up the original socket for inetd
- * to receive further messages on, or ``take over the socket'',
+ * to receive further messages on, or "take over the socket",
  * processing all arriving datagrams and, eventually, timing
- * out.  The first type of server is said to be ``multi-threaded'';
- * the second type of server ``single-threaded''.
+ * out.  The first type of server is said to be "multi-threaded";
+ * the second type of server "single-threaded".
  *
  * Inetd uses a configuration file which is read at startup
  * and, possibly, at some later time in response to a hangup signal.
- * The configuration file is ``free format'' with fields given in the
+ * The configuration file is "free format" with fields given in the
  * order shown below.  Continuation lines for an entry must begin with
  * a space or tab.  All fields must be present in each entry.
  *
  * Comment lines are indicated by a `#' in column 1.
  */
 
-/*
- * Here's the scoop concerning the user[.:]group feature:
+/* inetd rules for passing file descriptors to children
+ * (http://www.freebsd.org/cgi/man.cgi?query=inetd):
+ *
+ * The wait/nowait entry specifies whether the server that is invoked by
+ * inetd will take over the socket associated with the service access point,
+ * and thus whether inetd should wait for the server to exit before listen-
+ * ing for new service requests.  Datagram servers must use "wait", as
+ * they are always invoked with the original datagram socket bound to the
+ * specified service address.  These servers must read at least one datagram
+ * from the socket before exiting.  If a datagram server connects to its
+ * peer, freeing the socket so inetd can receive further messages on the
+ * socket, it is said to be a "multi-threaded" server; it should read one
+ * datagram from the socket and create a new socket connected to the peer.
+ * It should fork, and the parent should then exit to allow inetd to check
+ * for new service requests to spawn new servers.  Datagram servers which
+ * process all incoming datagrams on a socket and eventually time out are
+ * said to be "single-threaded".  The comsat(8), (biff(1)) and talkd(8)
+ * utilities are both examples of the latter type of datagram server.  The
+ * tftpd(8) utility is an example of a multi-threaded datagram server.
+ *
+ * Servers using stream sockets generally are multi-threaded and use the
+ * "nowait" entry. Connection requests for these services are accepted by
+ * inetd, and the server is given only the newly-accepted socket connected
+ * to a client of the service.  Most stream-based services operate in this
+ * manner.  Stream-based servers that use "wait" are started with the lis-
+ * tening service socket, and must accept at least one connection request
+ * before exiting.  Such a server would normally accept and process incoming
+ * connection requests until a timeout.
+ */
+
+/* Here's the scoop concerning the user[.:]group feature:
  *
  * 1) set-group-option off.
  *
  *      b) other:       setgid(specified group)
  *                      initgroups(name, specified group)
  *                      setuid()
- *
  */
 
-#include "busybox.h"
+#include "libbb.h"
 #include <syslog.h>
 #include <sys/un.h>
 
-//#define CONFIG_FEATURE_INETD_RPC
-//#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
-//#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
-//#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
-//#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
-//#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
-//#define CONFIG_FEATURE_IPV6
+//#define ENABLE_FEATURE_INETD_RPC 1
+//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1
+//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1
+//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1
+//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1
+//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1
+//#define ENABLE_FEATURE_IPV6 1
 
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #endif
 
-#define _PATH_INETDCONF "/etc/inetd.conf"
-#define _PATH_INETDPID  "/var/run/inetd.pid"
+extern char **environ;
 
 
+#define _PATH_INETDPID  "/var/run/inetd.pid"
+
 #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
 #define RETRYTIME       (60*10)         /* retry after bind or server fail */
 
 #endif
 
 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
-#define FD_MARGIN       (8)
-static rlim_t rlim_ofile_cur = OPEN_MAX;
-static struct rlimit rlim_ofile;
-
+#define FD_MARGIN       8
 
 /* Check unsupporting builtin */
-#if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
-               defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
-               defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
-               defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
-               defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 # define INETD_FEATURE_ENABLED
 #endif
 
-#if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
-               defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
-               defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 # define INETD_SETPROCTITLE
 #endif
 
-typedef struct servtab {
+typedef int8_t socktype_t;
+typedef int8_t family_t;
+struct BUG_too_small {
+       char BUG_socktype_t_too_small[(0
+                       | SOCK_STREAM
+                       | SOCK_DGRAM
+                       | SOCK_RDM
+                       | SOCK_SEQPACKET
+                       | SOCK_RAW) <= 127 ? 1 : -1];
+       char BUG_family_t_too_small[(0
+                       | AF_INET
+                       | AF_INET6
+                       | AF_UNIX) <= 127 ? 1 : -1];
+};
+
+typedef struct servtab_t {
+       /* The most frequently referenced one: */
+       int se_fd;                            /* open descriptor */
+       /* NB: 'biggest fields last' saves on code size (~250 bytes) */
        char *se_hostaddr;                    /* host address to listen on */
        char *se_service;                     /* name of service */
-       int se_socktype;                      /* type of socket to use */
-       int se_family;                        /* address family */
        char *se_proto;                       /* protocol used */
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
        int se_rpcprog;                       /* rpc program number */
        int se_rpcversl;                      /* rpc program lowest version */
        int se_rpcversh;                      /* rpc program highest version */
@@ -196,20 +237,26 @@ typedef struct servtab {
 #define isrpcservice(sep)       0
 #endif
        pid_t se_wait;                        /* single threaded server */
-       short se_checked;                     /* looked at during merge */
+       socktype_t se_socktype;               /* type of socket to use */
+       family_t se_family;                   /* address family */
+       smallint se_checked;                  /* looked at during merge */
        char *se_user;                        /* user name to run as */
        char *se_group;                       /* group name to run as */
 #ifdef INETD_FEATURE_ENABLED
        const struct builtin *se_bi;          /* if built-in, description */
 #endif
+       int se_ctrladdr_size;
+       int se_max;                           /* max # of instances of this service */
+       int se_count;                         /* number started since se_time */
+       struct servtab_t *se_next;
+       struct timeval se_time;               /* start of se_count */
        char *se_server;                      /* server program */
 #define MAXARGV 20
        char *se_argv[MAXARGV + 1];           /* program arguments */
-       int se_fd;                            /* open descriptor */
        union {
                struct sockaddr se_un_ctrladdr;
                struct sockaddr_in se_un_ctrladdr_in;
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
                struct sockaddr_in6 se_un_ctrladdr_in6;
 #endif
                struct sockaddr_un se_un_ctrladdr_un;
@@ -218,93 +265,131 @@ typedef struct servtab {
 #define se_ctrladdr_in  se_un.se_un_ctrladdr_in
 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
 #define se_ctrladdr_un  se_un.se_un_ctrladdr_un
-       int se_ctrladdr_size;
-       int se_max;                           /* max # of instances of this service */
-       int se_count;                         /* number started since se_time */
-       struct timeval se_time;               /* start of se_count */
-       struct servtab *se_next;
 } servtab_t;
 
-static servtab_t *servtab;
-
 #ifdef INETD_FEATURE_ENABLED
 struct builtin {
        const char *bi_service;               /* internally provided service name */
-       int bi_socktype;                      /* type of socket supported */
-       short bi_fork;                        /* 1 if should fork before call */
-       short bi_wait;                        /* 1 if should wait for child */
+       socktype_t bi_socktype;               /* type of socket supported */
+       uint8_t bi_fork;                      /* 1 if should fork before call */
+// Commented since it is always 0
+//     uint8_t bi_wait;                      /* 1 if should wait for child */
        void (*bi_fn) (int, servtab_t *);
 };
 
                /* Echo received data */
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
 static void echo_stream(int, servtab_t *);
 static void echo_dg(int, servtab_t *);
 #endif
                /* Internet /dev/null */
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
 static void discard_stream(int, servtab_t *);
 static void discard_dg(int, servtab_t *);
 #endif
                /* Return 32 bit time since 1900 */
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
 static void machtime_stream(int, servtab_t *);
 static void machtime_dg(int, servtab_t *);
 #endif
                /* Return human-readable time */
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
 static void daytime_stream(int, servtab_t *);
 static void daytime_dg(int, servtab_t *);
 #endif
                /* Familiar character generator */
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 static void chargen_stream(int, servtab_t *);
 static void chargen_dg(int, servtab_t *);
 #endif
 
 static const struct builtin builtins[] = {
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
        /* Echo received data */
-       {"echo", SOCK_STREAM, 1, 0, echo_stream,},
-       {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
+       {"echo", SOCK_STREAM, 1, echo_stream,},
+       {"echo", SOCK_DGRAM, 0, echo_dg,},
 #endif
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
        /* Internet /dev/null */
-       {"discard", SOCK_STREAM, 1, 0, discard_stream,},
-       {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
+       {"discard", SOCK_STREAM, 1, discard_stream,},
+       {"discard", SOCK_DGRAM, 0, discard_dg,},
 #endif
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
        /* Return 32 bit time since 1900 */
-       {"time", SOCK_STREAM, 0, 0, machtime_stream,},
-       {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
+       {"time", SOCK_STREAM, 0, machtime_stream,},
+       {"time", SOCK_DGRAM, 0, machtime_dg,},
 #endif
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
        /* Return human-readable time */
-       {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
-       {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
+       {"daytime", SOCK_STREAM, 0, daytime_stream,},
+       {"daytime", SOCK_DGRAM, 0, daytime_dg,},
 #endif
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
        /* Familiar character generator */
-       {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
-       {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
+       {"chargen", SOCK_STREAM, 1, chargen_stream,},
+       {"chargen", SOCK_DGRAM, 0, chargen_dg,},
 #endif
-       {NULL, 0, 0, 0, NULL}
+       { /* zero filled */ }
 };
 #endif /* INETD_FEATURE_ENABLED */
 
-static int global_queuelen = 128;
-static int nsock, maxsock;
-static fd_set allsock;
-static int toomany;
-static int timingout;
-static struct servent *sp;
-static uid_t uid;
-
-static char *CONFIG = _PATH_INETDCONF;
-
-static FILE *fconfig;
-static char line[1024];
-static char *defhost;
+struct globals {
+       rlim_t rlim_ofile_cur;
+       struct rlimit rlim_ofile;
+       servtab_t *servtab;
+       int global_queuelen;
+       int nsock;
+       int maxsock;
+       int toomany;
+       int timingout;
+       struct servent *sp;
+       uid_t uid;
+       const char *config_filename;
+       FILE *fconfig;
+       char *defhost;
+#ifdef INETD_SETPROCTITLE
+       char **Argv;
+       char *LastArg;
+#endif
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+       char *endring;
+       char *ringpos;
+       char ring[128];
+#endif
+       fd_set allsock;
+       /* Used only in nextline() */
+       char line[80];          /* at least 80, see LINE_SIZE */
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) };
+struct BUG_G_too_big {
+       char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+};
+#define rlim_ofile_cur  (G.rlim_ofile_cur )
+#define rlim_ofile      (G.rlim_ofile     )
+#define servtab         (G.servtab        )
+#define global_queuelen (G.global_queuelen)
+#define nsock           (G.nsock          )
+#define maxsock         (G.maxsock        )
+#define toomany         (G.toomany        )
+#define timingout       (G.timingout      )
+#define sp              (G.sp             )
+#define uid             (G.uid            )
+#define config_filename (G.config_filename)
+#define fconfig         (G.fconfig        )
+#define defhost         (G.defhost        )
+#define Argv            (G.Argv           )
+#define LastArg         (G.LastArg        )
+#define endring         (G.endring        )
+#define ringpos         (G.ringpos        )
+#define ring            (G.ring           )
+#define allsock         (G.allsock        )
+#define line            (G.line           )
+#define INIT_G() do { \
+       rlim_ofile_cur = OPEN_MAX; \
+       global_queuelen = 128; \
+       config_filename = "/etc/inetd.conf"; \
+} while (0)
 
 /* xstrdup(NULL) returns NULL, but this one
  * will return newly-allocated "" if called with NULL arg
@@ -323,7 +408,7 @@ static int setconfig(void)
                fseek(fconfig, 0L, SEEK_SET);
                return 1;
        }
-       fconfig = fopen(CONFIG, "r");
+       fconfig = fopen(config_filename, "r");
        return (fconfig != NULL);
 }
 
@@ -337,7 +422,7 @@ static void endconfig(void)
        defhost = 0;
 }
 
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
 static void register_rpc(servtab_t *sep)
 {
        int n;
@@ -374,7 +459,7 @@ static void unregister_rpc(servtab_t *sep)
                        bb_error_msg("pmap_unset(%u, %u)", sep->se_rpcprog, n);
        }
 }
-#endif /* CONFIG_FEATURE_INETD_RPC */
+#endif /* FEATURE_INETD_RPC */
 
 static void freeconfig(servtab_t *cp)
 {
@@ -390,13 +475,13 @@ static void freeconfig(servtab_t *cp)
                free(cp->se_argv[i]);
 }
 
-static int bump_nofile (void)
+static int bump_nofile(void)
 {
 #define FD_CHUNK        32
 
        struct rlimit rl;
 
-       if (getrlimit (RLIMIT_NOFILE, &rl) < 0) {
+       if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
                bb_perror_msg("getrlimit");
                return -1;
        }
@@ -426,10 +511,9 @@ static void setup(servtab_t *sep)
                bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto);
                return;
        }
-       if (setsockopt_reuseaddr(sep->se_fd) < 0)
-               bb_perror_msg("setsockopt(SO_REUSEADDR)");
+       setsockopt_reuseaddr(sep->se_fd);
 
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
        if (isrpcservice(sep)) {
                struct passwd *pwd;
 
@@ -487,7 +571,7 @@ static char *nextline(void)
        char *cp;
        FILE *fd = fconfig;
 
-       if (fgets(line, sizeof(line), fd) == NULL)
+       if (fgets(line, LINE_SIZE, fd) == NULL)
                return NULL;
        cp = strchr(line, '\n');
        if (cp)
@@ -507,17 +591,19 @@ static char *skip(char **cpp) /* int report; */
                return NULL;
        }
 
-again:
+ again:
        while (*cp == ' ' || *cp == '\t')
                cp++;
        if (*cp == '\0') {
                int c;
 
                c = getc(fconfig);
-               (void) ungetc(c, fconfig);
-               if (c == ' ' || c == '\t')
-                       if ((cp = nextline()))
+               ungetc(c, fconfig);
+               if (c == ' ' || c == '\t') {
+                       cp = nextline();
+                       if (cp)
                                goto again;
+               }
                *cpp = NULL;
                /* goto erp; */
                return NULL;
@@ -550,7 +636,7 @@ static servtab_t *dupconfig(servtab_t *sep)
        newtab->se_socktype = sep->se_socktype;
        newtab->se_family = sep->se_family;
        newtab->se_proto = xstrdup(sep->se_proto);
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
        newtab->se_rpcprog = sep->se_rpcprog;
        newtab->se_rpcversl = sep->se_rpcversl;
        newtab->se_rpcversh = sep->se_rpcversh;
@@ -642,13 +728,13 @@ static servtab_t *getconfigent(void)
        } else {
                sep->se_family = AF_INET;
                if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
                        sep->se_family = AF_INET6;
 #else
                        bb_error_msg("%s: IPV6 not supported", sep->se_proto);
 #endif
                if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                        char *p, *ccp;
                        long l;
 
@@ -660,7 +746,7 @@ static servtab_t *getconfigent(void)
                        *p++ = '\0';
                        l = strtol(p, &ccp, 0);
                        if (ccp == p || l < 0 || l > INT_MAX) {
                      badafterall:
+ badafterall:
                                bb_error_msg("%s/%s: bad rpc version", sep->se_service, p);
                                goto more;
                        }
@@ -710,15 +796,15 @@ static servtab_t *getconfigent(void)
                const struct builtin *bi;
 
                for (bi = builtins; bi->bi_service; bi++)
-                       if (bi->bi_socktype == sep->se_socktype &&
-                                       strcmp(bi->bi_service, sep->se_service) == 0)
+                       if (bi->bi_socktype == sep->se_socktype
+                        && strcmp(bi->bi_service, sep->se_service) == 0)
                                break;
                if (bi->bi_service == 0) {
                        bb_error_msg("internal service %s unknown", sep->se_service);
                        goto more;
                }
                sep->se_bi = bi;
-               sep->se_wait = bi->bi_wait;
+               sep->se_wait = 0; /* = bi->bi_wait; - always 0 */
 #else
                bb_perror_msg("internal service %s unknown", sep->se_service);
                goto more;
@@ -762,41 +848,41 @@ static servtab_t *getconfigent(void)
                        if (LONE_CHAR(nsep->se_hostaddr, '*'))
                                nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
                        else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
+                               int i;
                                struct hostent *hp;
 
                                hp = gethostbyname(nsep->se_hostaddr);
-                               if (hp == 0) {
+                               if (hp == NULL) {
                                        bb_error_msg("%s: unknown host", nsep->se_hostaddr);
                                        nsep->se_checked = 0;
                                        goto skip;
-                               } else if (hp->h_addrtype != AF_INET) {
+                               }
+                               if (hp->h_addrtype != AF_INET) {
                                        bb_error_msg("%s: address isn't an Internet "
                                                                  "address", nsep->se_hostaddr);
                                        nsep->se_checked = 0;
                                        goto skip;
-                               } else {
-                                       int i = 1;
-
-                                       memmove(&nsep->se_ctrladdr_in.sin_addr,
-                                                                  hp->h_addr_list[0], sizeof(struct in_addr));
-                                       while (hp->h_addr_list[i] != NULL) {
-                                               psep = dupconfig(nsep);
-                                               psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
-                                               psep->se_checked = 1;
-                                               memmove(&psep->se_ctrladdr_in.sin_addr,
-                                                                    hp->h_addr_list[i], sizeof(struct in_addr));
-                                               psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
-                                               i++;
-                                               /* Prepend to list, don't want to look up */
-                                               /* its hostname again. */
-                                               psep->se_next = sep;
-                                               sep = psep;
-                                       }
+                               }
+                               i = 1;
+                               memmove(&nsep->se_ctrladdr_in.sin_addr,
+                                                          hp->h_addr_list[0], sizeof(struct in_addr));
+                               while (hp->h_addr_list[i] != NULL) {
+                                       psep = dupconfig(nsep);
+                                       psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
+                                       psep->se_checked = 1;
+                                       memmove(&psep->se_ctrladdr_in.sin_addr,
+                                                            hp->h_addr_list[i], sizeof(struct in_addr));
+                                       psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
+                                       i++;
+                                       /* Prepend to list, don't want to look up */
+                                       /* its hostname again. */
+                                       psep->se_next = sep;
+                                       sep = psep;
                                }
                        }
                }
 /* XXX BUG?: is this skip: label supposed to remain? */
      skip:
+ skip:
                nsep = nsep->se_next;
        }
 
@@ -835,7 +921,7 @@ static servtab_t *getconfigent(void)
        sigaddset(&m, SIGHUP); \
        sigaddset(&m, SIGALRM); \
        sigprocmask(SIG_BLOCK, &m, NULL); \
-} while(0)
+} while (0)
 
 static servtab_t *enter(servtab_t *cp)
 {
@@ -845,7 +931,7 @@ static servtab_t *enter(servtab_t *cp)
        sep = new_servtab();
        *sep = *cp;
        sep->se_fd = -1;
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
        sep->se_rpcprog = -1;
 #endif
        Block_Using_Signals(omask);
@@ -879,7 +965,7 @@ static int matchconf(servtab_t *old, servtab_t *new)
                                        sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
                return 0;
 
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
        if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
                        memcmp(&old->se_ctrladdr_in6.sin6_addr,
                                        &new->se_ctrladdr_in6.sin6_addr,
@@ -897,7 +983,7 @@ static void config(int sig ATTRIBUTE_UNUSED)
        char protoname[10];
 
        if (!setconfig()) {
-               bb_perror_msg("%s", CONFIG);
+               bb_perror_msg("%s", config_filename);
                return;
        }
        for (sep = servtab; sep; sep = sep->se_next)
@@ -934,7 +1020,7 @@ static void config(int sig ATTRIBUTE_UNUSED)
                                SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
 #undef SWAP
 
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                        if (isrpcservice(sep))
                                unregister_rpc(sep);
                        sep->se_rpcversl = cp->se_rpcversl;
@@ -965,7 +1051,7 @@ static void config(int sig ATTRIBUTE_UNUSED)
                        /* se_ctrladdr_in was set in getconfigent */
                        sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
 
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                        if (isrpcservice(sep)) {
                                struct rpcent *rp;
                                // FIXME: atoi_or_else(str, 0) would be handy here
@@ -1012,13 +1098,13 @@ static void config(int sig ATTRIBUTE_UNUSED)
                                        setup(sep);
                        }
                        break;
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
                case AF_INET6:
                        sep->se_ctrladdr_in6.sin6_family = AF_INET6;
                        /* se_ctrladdr_in was set in getconfigent */
                        sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
 
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                        if (isrpcservice(sep)) {
                                struct rpcent *rp;
 
@@ -1065,9 +1151,9 @@ static void config(int sig ATTRIBUTE_UNUSED)
                                        setup(sep);
                        }
                        break;
-#endif /* CONFIG_FEATURE_IPV6 */
+#endif /* FEATURE_IPV6 */
                }
      serv_unknown:
+ serv_unknown:
                if (cp->se_next != NULL) {
                        servtab_t *tmp = cp;
 
@@ -1095,7 +1181,7 @@ static void config(int sig ATTRIBUTE_UNUSED)
                        nsock--;
                        (void) close(sep->se_fd);
                }
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                if (isrpcservice(sep))
                        unregister_rpc(sep);
 #endif
@@ -1144,11 +1230,11 @@ static void retry(int sig ATTRIBUTE_UNUSED)
                        switch (sep->se_family) {
                        case AF_UNIX:
                        case AF_INET:
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
                        case AF_INET6:
 #endif
                                setup(sep);
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                                if (sep->se_fd != -1 && isrpcservice(sep))
                                        register_rpc(sep);
 #endif
@@ -1172,10 +1258,10 @@ static void goaway(int sig ATTRIBUTE_UNUSED)
                        (void) unlink(sep->se_service);
                        break;
                case AF_INET:
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
                case AF_INET6:
 #endif
-#ifdef CONFIG_FEATURE_INETD_RPC
+#if ENABLE_FEATURE_INETD_RPC
                        if (sep->se_wait == 1 && isrpcservice(sep))
                                unregister_rpc(sep);   /* XXX signal race */
 #endif
@@ -1183,14 +1269,12 @@ static void goaway(int sig ATTRIBUTE_UNUSED)
                }
                (void) close(sep->se_fd);
        }
-       (void) unlink(_PATH_INETDPID);
+       remove_pidfile(_PATH_INETDPID);
        exit(0);
 }
 
 
 #ifdef INETD_SETPROCTITLE
-static char **Argv;
-static char *LastArg;
 
 static void
 inetd_setproctitle(char *a, int s)
@@ -1219,8 +1303,8 @@ inetd_setproctitle(char *a, int s)
 #endif
 
 
-int
-inetd_main(int argc, char *argv[])
+int inetd_main(int argc, char **argv);
+int inetd_main(int argc, char **argv)
 {
        servtab_t *sep;
        struct passwd *pwd;
@@ -1232,11 +1316,14 @@ inetd_main(int argc, char *argv[])
        char buf[50];
        char *stoomany;
        sigset_t omask, wait_mask;
-
 #ifdef INETD_SETPROCTITLE
-       extern char **environ;
-       char **envp = environ;
+       char **envp;
+#endif
+
+       INIT_G();
 
+#ifdef INETD_SETPROCTITLE
+       envp = environ;
        Argv = argv;
        if (envp == 0 || *envp == 0)
                envp = argv;
@@ -1245,50 +1332,34 @@ inetd_main(int argc, char *argv[])
        LastArg = envp[-1] + strlen(envp[-1]);
 #endif
 
-       openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+       uid = getuid();
+       if (uid != 0)
+               config_filename = NULL;
 
-       opt = getopt32(argc, argv, "R:f", &stoomany);
-       if(opt & 1) {
+       opt = getopt32(argv, "R:f", &stoomany);
+       if (opt & 1)
                toomany = xatoi_u(stoomany);
-       }
-       argc -= optind;
        argv += optind;
-
-       uid = getuid();
-       if (uid != 0)
-               CONFIG = NULL;
-       if (argc > 0)
-               CONFIG = argv[0];
-       if (CONFIG == NULL)
+       argc -= optind;
+       if (argc)
+               config_filename = argv[0];
+       if (config_filename == NULL)
                bb_error_msg_and_die("non-root must specify a config file");
 
-       if (!(opt & 2)) {
-#ifdef BB_NOMMU
-               /* reexec for vfork() do continue parent */
-               vfork_daemon_rexec(0, 0, argc, argv, "-f");
-#else
-               xdaemon(0, 0);
-#endif
-       } else {
-               setsid();
-       }
+       if (!(opt & 2))
+               bb_daemonize_or_rexec(0, argv - optind);
+       else
+               bb_sanitize_stdio();
+       openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
        logmode = LOGMODE_SYSLOG;
 
        if (uid == 0) {
-               gid_t gid = getgid();
-
                /* If run by hand, ensure groups vector gets trashed */
+               gid_t gid = getgid();
                setgroups(1, &gid);
        }
 
-       {
-               FILE *fp = fopen(_PATH_INETDPID, "w");
-
-               if (fp != NULL) {
-                       fprintf(fp, "%u\n", getpid());
-                       (void) fclose(fp);
-               }
-       }
+       write_pidfile(_PATH_INETDPID);
 
        if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
                bb_perror_msg("getrlimit");
@@ -1447,7 +1518,7 @@ inetd_main(int argc, char *argv[])
                                        (*sep->se_bi->bi_fn)(ctrl, sep);
                                } else
 #endif
-                                       {
+                               {
                                        pwd = getpwnam(sep->se_user);
                                        if (pwd == NULL) {
                                                bb_error_msg("getpwnam: %s: no such user", sep->se_user);
@@ -1486,7 +1557,7 @@ inetd_main(int argc, char *argv[])
                                        sigaction(SIGPIPE, &sapipe, NULL);
                                        execv(sep->se_server, sep->se_argv);
                                        bb_perror_msg("execv %s", sep->se_server);
-do_exit1:
+ do_exit1:
                                        if (sep->se_socktype != SOCK_STREAM)
                                                recv(0, buf, sizeof(buf), 0);
                                        _exit(1);
@@ -1495,7 +1566,7 @@ do_exit1:
                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
                                close(ctrl);
                } /* for (sep = servtab...) */
-       } /* for(;;) */
+       } /* for (;;) */
 }
 
 /*
@@ -1503,9 +1574,9 @@ do_exit1:
  */
 #define BUFSIZE 4096
 
-#if defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO) || \
-               defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN) || \
-               defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME)
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
+       ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
 static int dg_badinput(struct sockaddr_in *dg_sin)
 {
        if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
@@ -1517,7 +1588,7 @@ static int dg_badinput(struct sockaddr_in *dg_sin)
 }
 #endif
 
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
 /* Echo service -- echo data back */
 /* ARGSUSED */
 static void
@@ -1555,9 +1626,9 @@ echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
                return;
        (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
 }
-#endif  /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
+#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
 
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
 /* Discard service -- ignore data */
 /* ARGSUSED */
 static void
@@ -1582,13 +1653,11 @@ discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
 
        (void) read(s, buffer, sizeof(buffer));
 }
-#endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
+#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
 
 
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 #define LINESIZ 72
-static char ring[128];
-static char *endring;
 
 static void
 initring(void)
@@ -1596,7 +1665,6 @@ initring(void)
        int i;
 
        endring = ring;
-
        for (i = 0; i <= 128; ++i)
                if (isprint(i))
                        *endring++ = i;
@@ -1644,14 +1712,13 @@ chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
 {
        /* struct sockaddr_storage ss; */
        struct sockaddr sa;
-       static char *rs;
        int len;
        char text[LINESIZ + 2];
        socklen_t size;
 
-       if (endring == 0) {
+       if (!endring) {
                initring();
-               rs = ring;
+               ringpos = ring;
        }
 
        size = sizeof(sa);
@@ -1660,22 +1727,23 @@ chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
        if (dg_badinput((struct sockaddr_in *) &sa))
                return;
 
-       if ((len = endring - rs) >= LINESIZ)
-               memmove(text, rs, LINESIZ);
+       len = endring - ringpos;
+       if (len >= LINESIZ)
+               memmove(text, ringpos, LINESIZ);
        else {
-               memmove(text, rs, len);
+               memmove(text, ringpos, len);
                memmove(text + len, ring, LINESIZ - len);
        }
-       if (++rs == endring)
-               rs = ring;
+       if (++ringpos == endring)
+               ringpos = ring;
        text[LINESIZ] = '\r';
        text[LINESIZ + 1] = '\n';
        (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
 }
-#endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
+#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
 
 
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
 /*
  * Return a machine readable date and time, in the form of the
  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
@@ -1684,7 +1752,7 @@ chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
  * some seventy years Bell Labs was asleep.
  */
 
-static u_int machtime(void)
+static unsigned machtime(void)
 {
        struct timeval tv;
 
@@ -1692,14 +1760,14 @@ static u_int machtime(void)
                fprintf(stderr, "Unable to get time of day\n");
                return 0L;
        }
-       return htonl((u_int) tv.tv_sec + 2208988800UL);
+       return htonl((unsigned) tv.tv_sec + 2208988800UL);
 }
 
 /* ARGSUSED */
 static void
 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
 {
-       u_int result;
+       unsigned result;
 
        result = machtime();
        (void) write(s, (char *) &result, sizeof(result));
@@ -1709,7 +1777,7 @@ machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
 static void
 machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
 {
-       u_int result;
+       unsigned result;
        /* struct sockaddr_storage ss; */
        struct sockaddr sa;
        struct sockaddr_in *dg_sin;
@@ -1726,19 +1794,20 @@ machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
        result = machtime();
        (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
 }
-#endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME */
+#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
 
 
-#ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
 /* Return human-readable time of day */
 /* ARGSUSED */
 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
 {
-       char buffer[256];
+       char buffer[32];
        time_t t;
 
        t = time(NULL);
 
+// fdprintf instead?
        (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
        (void) write(s, buffer, strlen(buffer));
 }
@@ -1764,4 +1833,4 @@ daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
        (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
        (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
 }
-#endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
+#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */