Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/inetd.c

    r1772 r2725  
    44/*      $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $       */
    55/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru>     */
     6/* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */
    67/*
    78 * Copyright (c) 1983,1991 The Regents of the University of California.
     
    3940/* Inetd - Internet super-server
    4041 *
    41  * This program invokes all internet services as needed.
    42  * connection-oriented services are invoked each time a
     42 * This program invokes configured services when a connection
     43 * from a peer is established or a datagram arrives.
     44 * Connection-oriented services are invoked each time a
    4345 * connection is made, by creating a process.  This process
    4446 * is passed the connection as file descriptor 0 and is
    45  * expected to do a getpeername to find out the source host
     47 * expected to do a getpeername to find out peer's host
    4648 * and port.
    47  *
    4849 * Datagram oriented services are invoked when a datagram
    4950 * arrives; a process is created and passed a pending message
    50  * on file descriptor 0.  Datagram servers may either connect
    51  * to their peer, freeing up the original socket for inetd
    52  * to receive further messages on, or "take over the socket",
    53  * processing all arriving datagrams and, eventually, timing
    54  * out.  The first type of server is said to be "multi-threaded";
    55  * the second type of server "single-threaded".
     51 * on file descriptor 0. peer's address can be obtained
     52 * using recvfrom.
    5653 *
    5754 * Inetd uses a configuration file which is read at startup
     
    6158 * a space or tab.  All fields must be present in each entry.
    6259 *
    63  *      service name                    must be in /etc/services
    64  *      socket type                     stream/dgram/raw/rdm/seqpacket
     60 *      service_name                    must be in /etc/services
     61 *      socket_type                     stream/dgram/raw/rdm/seqpacket
    6562 *      protocol                        must be in /etc/protocols
     63 *                                      (usually "tcp" or "udp")
    6664 *      wait/nowait[.max]               single-threaded/multi-threaded, max #
    6765 *      user[.group] or user[:group]    user/group to run daemon as
    68  *      server program                  full path name
    69  *      server program arguments        maximum of MAXARGS (20)
     66 *      server_program                  full path name
     67 *      server_program_arguments        maximum of MAXARGS (20)
    7068 *
    7169 * For RPC services
    72  *      service name/version            must be in /etc/rpc
    73  *      socket type                     stream/dgram/raw/rdm/seqpacket
    74  *      protocol                        must be in /etc/protocols
     70 *      service_name/version            must be in /etc/rpc
     71 *      socket_type                     stream/dgram/raw/rdm/seqpacket
     72 *      rpc/protocol                    "rpc/tcp" etc
    7573 *      wait/nowait[.max]               single-threaded/multi-threaded
    7674 *      user[.group] or user[:group]    user to run daemon as
    77  *      server program                  full path name
    78  *      server program arguments        maximum of MAXARGS (20)
     75 *      server_program                  full path name
     76 *      server_program_arguments        maximum of MAXARGS (20)
    7977 *
    8078 * For non-RPC services, the "service name" can be of the form
    8179 * hostaddress:servicename, in which case the hostaddress is used
    8280 * as the host portion of the address to listen on.  If hostaddress
    83  * consists of a single `*' character, INADDR_ANY is used.
     81 * consists of a single '*' character, INADDR_ANY is used.
    8482 *
    8583 * A line can also consist of just
     
    102100 * specifiers are different.
    103101 *
    104  * Comment lines are indicated by a `#' in column 1.
     102 * Comment lines are indicated by a '#' in column 1.
    105103 */
    106104
     
    121119 * for new service requests to spawn new servers.  Datagram servers which
    122120 * process all incoming datagrams on a socket and eventually time out are
    123  * said to be "single-threaded".  The comsat(8), (biff(1)) and talkd(8)
     121 * said to be "single-threaded".  The comsat(8), biff(1) and talkd(8)
    124122 * utilities are both examples of the latter type of datagram server.  The
    125123 * tftpd(8) utility is an example of a multi-threaded datagram server.
     
    135133 */
    136134
    137 /* Here's the scoop concerning the user[.:]group feature:
    138  *
    139  * 1) set-group-option off.
    140  *
     135/* Despite of above doc saying that dgram services must use "wait",
     136 * "udp nowait" servers are implemented in busyboxed inetd.
     137 * IPv6 addresses are also implemented. However, they may look ugly -
     138 * ":::service..." means "address '::' (IPv6 wildcard addr)":"service"...
     139 * You have to put "tcp6"/"udp6" in protocol field to select IPv6.
     140 */
     141
     142/* Here's the scoop concerning the user[:group] feature:
     143 * 1) group is not specified:
    141144 *      a) user = root: NO setuid() or setgid() is done
    142  *
    143  *      b) other:       setgid(primary group as found in passwd)
    144  *                      initgroups(name, primary group)
     145 *      b) other:       initgroups(name, primary group)
     146 *                      setgid(primary group as found in passwd)
    145147 *                      setuid()
    146  *
    147  * 2) set-group-option on.
    148  *
     148 * 2) group is specified:
    149149 *      a) user = root: setgid(specified group)
    150150 *                      NO initgroups()
    151151 *                      NO setuid()
    152  *
    153  *      b) other:       setgid(specified group)
    154  *                      initgroups(name, specified group)
     152 *      b) other:       initgroups(name, specified group)
     153 *                      setgid(specified group)
    155154 *                      setuid()
    156155 */
    157156
    158 #include "libbb.h"
    159157#include <syslog.h>
    160158#include <sys/un.h>
    161159
    162 //#define ENABLE_FEATURE_INETD_RPC 1
    163 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1
    164 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1
    165 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1
    166 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1
    167 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1
    168 //#define ENABLE_FEATURE_IPV6 1
     160#include "libbb.h"
    169161
    170162#if ENABLE_FEATURE_INETD_RPC
     
    173165#endif
    174166
    175 extern char **environ;
    176 
     167#if !BB_MMU
     168/* stream version of chargen is forking but not execing,
     169 * can't do that (easily) on NOMMU */
     170#undef  ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     171#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
     172#endif
    177173
    178174#define _PATH_INETDPID  "/var/run/inetd.pid"
    179175
    180 #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
    181 #define RETRYTIME       (60*10)         /* retry after bind or server fail */
     176#define CNT_INTERVAL    60      /* servers in CNT_INTERVAL sec. */
     177#define RETRYTIME       60      /* retry after bind or server fail */
     178
     179// TODO: explain, or get rid of setrlimit games
    182180
    183181#ifndef RLIMIT_NOFILE
     
    191189/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
    192190#define FD_MARGIN       8
    193 static rlim_t rlim_ofile_cur = OPEN_MAX;
    194 static struct rlimit rlim_ofile;
    195 
    196 
    197 /* Check unsupporting builtin */
    198 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    199     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    200     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
    201     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
    202     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    203 # define INETD_FEATURE_ENABLED
    204 #endif
    205 
    206 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    207     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    208     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    209 # define INETD_SETPROCTITLE
    210 #endif
    211 
    212 typedef struct servtab {
    213     char *se_hostaddr;                    /* host address to listen on */
    214     char *se_service;                     /* name of service */
    215     int se_socktype;                      /* type of socket to use */
    216     int se_family;                        /* address family */
    217     char *se_proto;                       /* protocol used */
     191
     192#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD \
     193 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO    \
     194 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN \
     195 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME    \
     196 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     197# define INETD_BUILTINS_ENABLED
     198#endif
     199
     200typedef struct servtab_t {
     201    /* The most frequently referenced one: */
     202    int se_fd;                            /* open descriptor */
     203    /* NB: 'biggest fields last' saves on code size (~250 bytes) */
     204    /* [addr:]service socktype proto wait user[:group] prog [args] */
     205    char *se_local_hostname;              /* addr to listen on */
     206    char *se_service;                     /* "80" or "www" or "mount/2[-3]" */
     207    /* socktype is in se_socktype */      /* "stream" "dgram" "raw" "rdm" "seqpacket" */
     208    char *se_proto;                       /* "unix" or "[rpc/]tcp[6]" */
    218209#if ENABLE_FEATURE_INETD_RPC
    219210    int se_rpcprog;                       /* rpc program number */
    220     int se_rpcversl;                      /* rpc program lowest version */
    221     int se_rpcversh;                      /* rpc program highest version */
    222 #define isrpcservice(sep)       ((sep)->se_rpcversl != 0)
     211    int se_rpcver_lo;                     /* rpc program lowest version */
     212    int se_rpcver_hi;                     /* rpc program highest version */
     213#define is_rpc_service(sep)       ((sep)->se_rpcver_lo != 0)
    223214#else
    224 #define isrpcservice(sep)       0
    225 #endif
    226     pid_t se_wait;                        /* single threaded server */
    227     short se_checked;                     /* looked at during merge */
     215#define is_rpc_service(sep)       0
     216#endif
     217    pid_t se_wait;                        /* 0:"nowait", 1:"wait", >1:"wait" */
     218                                          /* and waiting for this pid */
     219    socktype_t se_socktype;               /* SOCK_STREAM/DGRAM/RDM/... */
     220    family_t se_family;                   /* AF_UNIX/INET[6] */
     221    /* se_proto_no is used by RPC code only... hmm */
     222    smallint se_proto_no;                 /* IPPROTO_TCP/UDP, n/a for AF_UNIX */
     223    smallint se_checked;                  /* looked at during merge */
     224    unsigned se_max;                      /* allowed instances per minute */
     225    unsigned se_count;                    /* number started since se_time */
     226    unsigned se_time;                     /* when we started counting */
    228227    char *se_user;                        /* user name to run as */
    229     char *se_group;                       /* group name to run as */
    230 #ifdef INETD_FEATURE_ENABLED
    231     const struct builtin *se_bi;          /* if built-in, description */
    232 #endif
    233     char *se_server;                      /* server program */
     228    char *se_group;                       /* group name to run as, can be NULL */
     229#ifdef INETD_BUILTINS_ENABLED
     230    const struct builtin *se_builtin;     /* if built-in, description */
     231#endif
     232    struct servtab_t *se_next;
     233    len_and_sockaddr *se_lsa;
     234    char *se_program;                     /* server program */
    234235#define MAXARGV 20
    235236    char *se_argv[MAXARGV + 1];           /* program arguments */
    236     int se_fd;                            /* open descriptor */
    237     union {
    238         struct sockaddr se_un_ctrladdr;
    239         struct sockaddr_in se_un_ctrladdr_in;
    240 #if ENABLE_FEATURE_IPV6
    241         struct sockaddr_in6 se_un_ctrladdr_in6;
    242 #endif
    243         struct sockaddr_un se_un_ctrladdr_un;
    244     } se_un;                              /* bound address */
    245 #define se_ctrladdr     se_un.se_un_ctrladdr
    246 #define se_ctrladdr_in  se_un.se_un_ctrladdr_in
    247 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
    248 #define se_ctrladdr_un  se_un.se_un_ctrladdr_un
    249     int se_ctrladdr_size;
    250     int se_max;                           /* max # of instances of this service */
    251     int se_count;                         /* number started since se_time */
    252     struct timeval se_time;               /* start of se_count */
    253     struct servtab *se_next;
    254237} servtab_t;
    255238
    256 static servtab_t *servtab;
    257 
    258 #ifdef INETD_FEATURE_ENABLED
     239#ifdef INETD_BUILTINS_ENABLED
     240/* Echo received data */
     241#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     242static void FAST_FUNC echo_stream(int, servtab_t *);
     243static void FAST_FUNC echo_dg(int, servtab_t *);
     244#endif
     245/* Internet /dev/null */
     246#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     247static void FAST_FUNC discard_stream(int, servtab_t *);
     248static void FAST_FUNC discard_dg(int, servtab_t *);
     249#endif
     250/* Return 32 bit time since 1900 */
     251#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     252static void FAST_FUNC machtime_stream(int, servtab_t *);
     253static void FAST_FUNC machtime_dg(int, servtab_t *);
     254#endif
     255/* Return human-readable time */
     256#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     257static void FAST_FUNC daytime_stream(int, servtab_t *);
     258static void FAST_FUNC daytime_dg(int, servtab_t *);
     259#endif
     260/* Familiar character generator */
     261#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     262static void FAST_FUNC chargen_stream(int, servtab_t *);
     263static void FAST_FUNC chargen_dg(int, servtab_t *);
     264#endif
     265
    259266struct builtin {
    260     const char *bi_service;               /* internally provided service name */
    261     int bi_socktype;                      /* type of socket supported */
    262     short bi_fork;                        /* 1 if should fork before call */
    263     short bi_wait;                        /* 1 if should wait for child */
    264     void (*bi_fn) (int, servtab_t *);
     267    /* NB: not necessarily NUL terminated */
     268    char bi_service7[7];      /* internally provided service name */
     269    uint8_t bi_fork;          /* 1 if stream fn should run in child */
     270    void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC;
     271    void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC;
    265272};
    266 
    267         /* Echo received data */
    268 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    269 static void echo_stream(int, servtab_t *);
    270 static void echo_dg(int, servtab_t *);
    271 #endif
    272         /* Internet /dev/null */
    273 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    274 static void discard_stream(int, servtab_t *);
    275 static void discard_dg(int, servtab_t *);
    276 #endif
    277         /* Return 32 bit time since 1900 */
    278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    279 static void machtime_stream(int, servtab_t *);
    280 static void machtime_dg(int, servtab_t *);
    281 #endif
    282         /* Return human-readable time */
    283 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    284 static void daytime_stream(int, servtab_t *);
    285 static void daytime_dg(int, servtab_t *);
    286 #endif
    287         /* Familiar character generator */
    288 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    289 static void chargen_stream(int, servtab_t *);
    290 static void chargen_dg(int, servtab_t *);
    291 #endif
    292273
    293274static const struct builtin builtins[] = {
    294275#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    295     /* Echo received data */
    296     {"echo", SOCK_STREAM, 1, 0, echo_stream,},
    297     {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
     276    { "echo", 1, echo_stream, echo_dg },
    298277#endif
    299278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    300     /* Internet /dev/null */
    301     {"discard", SOCK_STREAM, 1, 0, discard_stream,},
    302     {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
     279    { "discard", 1, discard_stream, discard_dg },
     280#endif
     281#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     282    { "chargen", 1, chargen_stream, chargen_dg },
    303283#endif
    304284#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    305     /* Return 32 bit time since 1900 */
    306     {"time", SOCK_STREAM, 0, 0, machtime_stream,},
    307     {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
     285    { "time", 0, machtime_stream, machtime_dg },
    308286#endif
    309287#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    310     /* Return human-readable time */
    311     {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
    312     {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
    313 #endif
     288    { "daytime", 0, daytime_stream, daytime_dg },
     289#endif
     290};
     291#endif /* INETD_BUILTINS_ENABLED */
     292
     293struct globals {
     294    rlim_t rlim_ofile_cur;
     295    struct rlimit rlim_ofile;
     296    servtab_t *serv_list;
     297    int global_queuelen;
     298    int maxsock;         /* max fd# in allsock, -1: unknown */
     299    /* whenever maxsock grows, prev_maxsock is set to new maxsock,
     300     * but if maxsock is set to -1, prev_maxsock is not changed */
     301    int prev_maxsock;
     302    unsigned max_concurrency;
     303    smallint alarm_armed;
     304    uid_t real_uid; /* user ID who ran us */
     305    const char *config_filename;
     306    parser_t *parser;
     307    char *default_local_hostname;
    314308#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    315     /* Familiar character generator */
    316     {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
    317     {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
    318 #endif
    319     {NULL, 0, 0, 0, NULL}
     309    char *end_ring;
     310    char *ring_pos;
     311    char ring[128];
     312#endif
     313    fd_set allsock;
     314    /* Used in next_line(), and as scratch read buffer */
     315    char line[256];          /* _at least_ 256, see LINE_SIZE */
     316} FIX_ALIASING;
     317#define G (*(struct globals*)&bb_common_bufsiz1)
     318enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) };
     319struct BUG_G_too_big {
     320    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
    320321};
    321 #endif /* INETD_FEATURE_ENABLED */
    322 
    323 static int global_queuelen = 128;
    324 static int nsock, maxsock;
    325 static fd_set allsock;
    326 static int toomany;
    327 static int timingout;
    328 static struct servent *sp;
    329 static uid_t uid;
    330 
    331 static const char *config_filename = "/etc/inetd.conf";
    332 
    333 static FILE *fconfig;
    334 static char *defhost;
    335 
    336 /* xstrdup(NULL) returns NULL, but this one
    337  * will return newly-allocated "" if called with NULL arg
    338  * TODO: audit whether this makes any real difference
    339  */
    340 static char *xxstrdup(char *cp)
    341 {
    342     return xstrdup(cp ? cp : "");
    343 }
    344 
    345 static int setconfig(void)
    346 {
    347     free(defhost);
    348     defhost = xstrdup("*");
    349     if (fconfig != NULL) {
    350         fseek(fconfig, 0L, SEEK_SET);
    351         return 1;
    352     }
    353     fconfig = fopen(config_filename, "r");
    354     return (fconfig != NULL);
    355 }
    356 
    357 static void endconfig(void)
    358 {
    359     if (fconfig) {
    360         (void) fclose(fconfig);
    361         fconfig = NULL;
    362     }
    363     free(defhost);
    364     defhost = 0;
     322#define rlim_ofile_cur  (G.rlim_ofile_cur )
     323#define rlim_ofile      (G.rlim_ofile     )
     324#define serv_list       (G.serv_list      )
     325#define global_queuelen (G.global_queuelen)
     326#define maxsock         (G.maxsock        )
     327#define prev_maxsock    (G.prev_maxsock   )
     328#define max_concurrency (G.max_concurrency)
     329#define alarm_armed     (G.alarm_armed    )
     330#define real_uid        (G.real_uid       )
     331#define config_filename (G.config_filename)
     332#define parser          (G.parser         )
     333#define default_local_hostname (G.default_local_hostname)
     334#define first_ps_byte   (G.first_ps_byte  )
     335#define last_ps_byte    (G.last_ps_byte   )
     336#define end_ring        (G.end_ring       )
     337#define ring_pos        (G.ring_pos       )
     338#define ring            (G.ring           )
     339#define allsock         (G.allsock        )
     340#define line            (G.line           )
     341#define INIT_G() do { \
     342    rlim_ofile_cur = OPEN_MAX; \
     343    global_queuelen = 128; \
     344    config_filename = "/etc/inetd.conf"; \
     345} while (0)
     346
     347static void maybe_close(int fd)
     348{
     349    if (fd >= 0)
     350        close(fd);
     351}
     352
     353// TODO: move to libbb?
     354static len_and_sockaddr *xzalloc_lsa(int family)
     355{
     356    len_and_sockaddr *lsa;
     357    int sz;
     358
     359    sz = sizeof(struct sockaddr_in);
     360    if (family == AF_UNIX)
     361        sz = sizeof(struct sockaddr_un);
     362#if ENABLE_FEATURE_IPV6
     363    if (family == AF_INET6)
     364        sz = sizeof(struct sockaddr_in6);
     365#endif
     366    lsa = xzalloc(LSA_LEN_SIZE + sz);
     367    lsa->len = sz;
     368    lsa->u.sa.sa_family = family;
     369    return lsa;
     370}
     371
     372static void rearm_alarm(void)
     373{
     374    if (!alarm_armed) {
     375        alarm_armed = 1;
     376        alarm(RETRYTIME);
     377    }
     378}
     379
     380static void block_CHLD_HUP_ALRM(sigset_t *m)
     381{
     382    sigemptyset(m);
     383    sigaddset(m, SIGCHLD);
     384    sigaddset(m, SIGHUP);
     385    sigaddset(m, SIGALRM);
     386    sigprocmask(SIG_BLOCK, m, m); /* old sigmask is stored in m */
     387}
     388
     389static void restore_sigmask(sigset_t *m)
     390{
     391    sigprocmask(SIG_SETMASK, m, NULL);
    365392}
    366393
     
    370397    int n;
    371398    struct sockaddr_in ir_sin;
    372     struct protoent *pp;
    373399    socklen_t size;
    374400
    375     if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) {
    376         bb_perror_msg("%s: getproto", sep->se_proto);
     401    size = sizeof(ir_sin);
     402    if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
     403        bb_perror_msg("getsockname");
    377404        return;
    378405    }
    379     size = sizeof ir_sin;
    380     if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
    381         bb_perror_msg("%s/%s: getsockname",
     406
     407    for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
     408        pmap_unset(sep->se_rpcprog, n);
     409        if (!pmap_set(sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port)))
     410            bb_perror_msg("%s %s: pmap_set(%u,%u,%u,%u)",
     411                sep->se_service, sep->se_proto,
     412                sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port));
     413    }
     414}
     415
     416static void unregister_rpc(servtab_t *sep)
     417{
     418    int n;
     419
     420    for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
     421        if (!pmap_unset(sep->se_rpcprog, n))
     422            bb_perror_msg("pmap_unset(%u,%u)", sep->se_rpcprog, n);
     423    }
     424}
     425#endif /* FEATURE_INETD_RPC */
     426
     427static void bump_nofile(void)
     428{
     429    enum { FD_CHUNK = 32 };
     430    struct rlimit rl;
     431
     432    /* Never fails under Linux (except if you pass it bad arguments) */
     433    getrlimit(RLIMIT_NOFILE, &rl);
     434    rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
     435    rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
     436    if (rl.rlim_cur <= rlim_ofile_cur) {
     437        bb_error_msg("can't extend file limit, max = %d",
     438                        (int) rl.rlim_cur);
     439        return;
     440    }
     441
     442    if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
     443        bb_perror_msg("setrlimit");
     444        return;
     445    }
     446
     447    rlim_ofile_cur = rl.rlim_cur;
     448}
     449
     450static void remove_fd_from_set(int fd)
     451{
     452    if (fd >= 0) {
     453        FD_CLR(fd, &allsock);
     454        maxsock = -1;
     455    }
     456}
     457
     458static void add_fd_to_set(int fd)
     459{
     460    if (fd >= 0) {
     461        FD_SET(fd, &allsock);
     462        if (maxsock >= 0 && fd > maxsock) {
     463            prev_maxsock = maxsock = fd;
     464            if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
     465                bump_nofile();
     466        }
     467    }
     468}
     469
     470static void recalculate_maxsock(void)
     471{
     472    int fd = 0;
     473
     474    /* We may have no services, in this case maxsock should still be >= 0
     475     * (code elsewhere is not happy with maxsock == -1) */
     476    maxsock = 0;
     477    while (fd <= prev_maxsock) {
     478        if (FD_ISSET(fd, &allsock))
     479            maxsock = fd;
     480        fd++;
     481    }
     482    prev_maxsock = maxsock;
     483    if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
     484        bump_nofile();
     485}
     486
     487static void prepare_socket_fd(servtab_t *sep)
     488{
     489    int r, fd;
     490
     491    fd = socket(sep->se_family, sep->se_socktype, 0);
     492    if (fd < 0) {
     493        bb_perror_msg("socket");
     494        return;
     495    }
     496    setsockopt_reuseaddr(fd);
     497
     498#if ENABLE_FEATURE_INETD_RPC
     499    if (is_rpc_service(sep)) {
     500        struct passwd *pwd;
     501
     502        /* zero out the port for all RPC services; let bind()
     503         * find one. */
     504        set_nport(sep->se_lsa, 0);
     505
     506        /* for RPC services, attempt to use a reserved port
     507         * if they are going to be running as root. */
     508        if (real_uid == 0 && sep->se_family == AF_INET
     509         && (pwd = getpwnam(sep->se_user)) != NULL
     510         && pwd->pw_uid == 0
     511        ) {
     512            r = bindresvport(fd, &sep->se_lsa->u.sin);
     513        } else {
     514            r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
     515        }
     516        if (r == 0) {
     517            int saveerrno = errno;
     518            /* update lsa with port# */
     519            getsockname(fd, &sep->se_lsa->u.sa, &sep->se_lsa->len);
     520            errno = saveerrno;
     521        }
     522    } else
     523#endif
     524    {
     525        if (sep->se_family == AF_UNIX) {
     526            struct sockaddr_un *sun;
     527            sun = (struct sockaddr_un*)&(sep->se_lsa->u.sa);
     528            unlink(sun->sun_path);
     529        }
     530        r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
     531    }
     532    if (r < 0) {
     533        bb_perror_msg("%s/%s: bind",
    382534                sep->se_service, sep->se_proto);
     535        close(fd);
     536        rearm_alarm();
    383537        return;
    384538    }
    385 
    386     for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
    387         (void) pmap_unset(sep->se_rpcprog, n);
    388         if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port)))
    389             bb_perror_msg("%s %s: pmap_set: %u %u %u %u",
    390                     sep->se_service, sep->se_proto,
    391                     sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port));
    392     }
    393 }
    394 
    395 static void unregister_rpc(servtab_t *sep)
    396 {
    397     int n;
    398 
    399     for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
    400         if (!pmap_unset(sep->se_rpcprog, n))
    401             bb_error_msg("pmap_unset(%u, %u)", sep->se_rpcprog, n);
    402     }
    403 }
    404 #endif /* FEATURE_INETD_RPC */
    405 
    406 static void freeconfig(servtab_t *cp)
     539    if (sep->se_socktype == SOCK_STREAM)
     540        listen(fd, global_queuelen);
     541
     542    add_fd_to_set(fd);
     543    sep->se_fd = fd;
     544}
     545
     546static int reopen_config_file(void)
     547{
     548    free(default_local_hostname);
     549    default_local_hostname = xstrdup("*");
     550    if (parser != NULL)
     551        config_close(parser);
     552    parser = config_open(config_filename);
     553    return (parser != NULL);
     554}
     555
     556static void close_config_file(void)
     557{
     558    if (parser) {
     559        config_close(parser);
     560        parser = NULL;
     561    }
     562}
     563
     564static void free_servtab_strings(servtab_t *cp)
    407565{
    408566    int i;
    409567
    410     free(cp->se_hostaddr);
     568    free(cp->se_local_hostname);
    411569    free(cp->se_service);
    412570    free(cp->se_proto);
    413571    free(cp->se_user);
    414572    free(cp->se_group);
    415     free(cp->se_server);
     573    free(cp->se_lsa); /* not a string in fact */
     574    free(cp->se_program);
    416575    for (i = 0; i < MAXARGV; i++)
    417576        free(cp->se_argv[i]);
    418577}
    419578
    420 static int bump_nofile(void)
    421 {
    422 #define FD_CHUNK        32
    423 
    424     struct rlimit rl;
    425 
    426     if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
    427         bb_perror_msg("getrlimit");
    428         return -1;
    429     }
    430     rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
    431     rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
    432     if (rl.rlim_cur <= rlim_ofile_cur) {
    433         bb_error_msg("bump_nofile: cannot extend file limit, max = %d",
    434                         (int) rl.rlim_cur);
    435         return -1;
    436     }
    437 
    438     if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
    439         bb_perror_msg("setrlimit");
    440         return -1;
    441     }
    442 
    443     rlim_ofile_cur = rl.rlim_cur;
    444     return 0;
    445 }
    446 
    447 static void setup(servtab_t *sep)
    448 {
    449     int r;
    450 
    451     sep->se_fd = socket(sep->se_family, sep->se_socktype, 0);
    452     if (sep->se_fd < 0) {
    453         bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto);
    454         return;
    455     }
    456     setsockopt_reuseaddr(sep->se_fd);
    457 
    458 #if ENABLE_FEATURE_INETD_RPC
    459     if (isrpcservice(sep)) {
    460         struct passwd *pwd;
    461 
    462         /*
    463          * for RPC services, attempt to use a reserved port
    464          * if they are going to be running as root.
    465          *
    466          * Also, zero out the port for all RPC services; let bind()
    467          * find one.
    468          */
    469         sep->se_ctrladdr_in.sin_port = 0;
    470         if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
    471                 pwd->pw_uid == 0 && uid == 0)
    472             r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
    473         else {
    474             r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
    475             if (r == 0) {
    476                 socklen_t len = sep->se_ctrladdr_size;
    477                 int saveerrno = errno;
    478 
    479                 /* update se_ctrladdr_in.sin_port */
    480                 r = getsockname(sep->se_fd, &sep->se_ctrladdr, &len);
    481                 if (r <= 0)
    482                     errno = saveerrno;
    483             }
    484         }
    485     } else
    486 #endif
    487         r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
    488     if (r < 0) {
    489         bb_perror_msg("%s/%s (%d): bind",
    490                 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
    491         close(sep->se_fd);
    492         sep->se_fd = -1;
    493         if (!timingout) {
    494             timingout = 1;
    495             alarm(RETRYTIME);
    496         }
    497         return;
    498     }
    499     if (sep->se_socktype == SOCK_STREAM)
    500         listen(sep->se_fd, global_queuelen);
    501 
    502     FD_SET(sep->se_fd, &allsock);
    503     nsock++;
    504     if (sep->se_fd > maxsock) {
    505         maxsock = sep->se_fd;
    506         if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
    507             bump_nofile();
    508     }
    509 }
    510 
    511 static char *nextline(void)
    512 {
    513 #define line bb_common_bufsiz1
    514 
    515     char *cp;
    516     FILE *fd = fconfig;
    517 
    518     if (fgets(line, sizeof(line), fd) == NULL)
    519         return NULL;
    520     cp = strchr(line, '\n');
    521     if (cp)
    522         *cp = '\0';
    523     return line;
    524 }
    525 
    526 static char *skip(char **cpp) /* int report; */
    527 {
    528     char *cp = *cpp;
    529     char *start;
    530 
    531 /* erp: */
    532     if (*cpp == NULL) {
    533         /* if (report) */
    534         /* bb_error_msg("syntax error in inetd config file"); */
    535         return NULL;
    536     }
    537 
    538  again:
    539     while (*cp == ' ' || *cp == '\t')
    540         cp++;
    541     if (*cp == '\0') {
    542         int c;
    543 
    544         c = getc(fconfig);
    545         ungetc(c, fconfig);
    546         if (c == ' ' || c == '\t') {
    547             cp = nextline();
    548             if (cp)
    549                 goto again;
    550         }
    551         *cpp = NULL;
    552         /* goto erp; */
    553         return NULL;
    554     }
    555     start = cp;
    556     while (*cp && *cp != ' ' && *cp != '\t')
    557         cp++;
    558     if (*cp != '\0')
    559         *cp++ = '\0';
    560     /* if ((*cpp = cp) == NULL) */
    561     /* goto erp; */
    562 
    563     *cpp = cp;
    564     return start;
    565 }
    566 
    567579static servtab_t *new_servtab(void)
    568580{
    569     return xmalloc(sizeof(servtab_t));
    570 }
    571 
    572 static servtab_t *dupconfig(servtab_t *sep)
     581    servtab_t *newtab = xzalloc(sizeof(servtab_t));
     582    newtab->se_fd = -1; /* paranoia */
     583    return newtab;
     584}
     585
     586static servtab_t *dup_servtab(servtab_t *sep)
    573587{
    574588    servtab_t *newtab;
     
    576590
    577591    newtab = new_servtab();
    578     memset(newtab, 0, sizeof(servtab_t));
    579     newtab->se_service = xstrdup(sep->se_service);
    580     newtab->se_socktype = sep->se_socktype;
    581     newtab->se_family = sep->se_family;
    582     newtab->se_proto = xstrdup(sep->se_proto);
    583 #if ENABLE_FEATURE_INETD_RPC
    584     newtab->se_rpcprog = sep->se_rpcprog;
    585     newtab->se_rpcversl = sep->se_rpcversl;
    586     newtab->se_rpcversh = sep->se_rpcversh;
    587 #endif
    588     newtab->se_wait = sep->se_wait;
    589     newtab->se_user = xstrdup(sep->se_user);
    590     newtab->se_group = xstrdup(sep->se_group);
    591 #ifdef INETD_FEATURE_ENABLED
    592     newtab->se_bi = sep->se_bi;
    593 #endif
    594     newtab->se_server = xstrdup(sep->se_server);
    595 
     592    *newtab = *sep; /* struct copy */
     593    /* deep-copying strings */
     594    newtab->se_service = xstrdup(newtab->se_service);
     595    newtab->se_proto = xstrdup(newtab->se_proto);
     596    newtab->se_user = xstrdup(newtab->se_user);
     597    newtab->se_group = xstrdup(newtab->se_group);
     598    newtab->se_program = xstrdup(newtab->se_program);
    596599    for (argc = 0; argc <= MAXARGV; argc++)
    597         newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]);
    598     newtab->se_max = sep->se_max;
     600        newtab->se_argv[argc] = xstrdup(newtab->se_argv[argc]);
     601    /* NB: se_fd, se_hostaddr and se_next are always
     602     * overwrittend by callers, so we don't bother resetting them
     603     * to NULL/0/-1 etc */
    599604
    600605    return newtab;
    601606}
    602607
    603 static servtab_t *getconfigent(void)
    604 {
     608/* gcc generates much more code if this is inlined */
     609static servtab_t *parse_one_line(void)
     610{
     611    int argc;
     612    char *token[6+MAXARGV];
     613    char *p, *arg;
     614    char *hostdelim;
    605615    servtab_t *sep;
    606     int argc;
    607     char *cp, *arg;
    608     char *hostdelim;
    609616    servtab_t *nsep;
    610     servtab_t *psep;
    611 
     617 new:
    612618    sep = new_servtab();
    613 
    614     /* memset(sep, 0, sizeof *sep); */
    615619 more:
    616     /* freeconfig(sep); */
    617 
    618     while ((cp = nextline()) && *cp == '#') /* skip comment line */;
    619     if (cp == NULL) {
    620         /* free(sep); */
     620    argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL);
     621    if (!argc) {
     622        free(sep);
    621623        return NULL;
    622624    }
    623625
    624     memset((char *) sep, 0, sizeof *sep);
    625     arg = skip(&cp);
    626     if (arg == NULL) {
    627         /* A blank line. */
    628         goto more;
    629     }
    630 
    631     /* Check for a host name. */
     626    /* [host:]service socktype proto wait user[:group] prog [args] */
     627    /* Check for "host:...." line */
     628    arg = token[0];
    632629    hostdelim = strrchr(arg, ':');
    633630    if (hostdelim) {
    634631        *hostdelim = '\0';
    635         sep->se_hostaddr = xstrdup(arg);
     632        sep->se_local_hostname = xstrdup(arg);
    636633        arg = hostdelim + 1;
    637         /*
    638          * If the line is of the form `host:', then just change the
    639          * default host for the following lines.
    640          */
    641         if (*arg == '\0') {
    642             arg = skip(&cp);
    643             if (cp == NULL) {
    644                 free(defhost);
    645                 defhost = sep->se_hostaddr;
    646                 goto more;
    647             }
     634        if (*arg == '\0' && argc == 1) {
     635            /* Line has just "host:", change the
     636             * default host for the following lines. */
     637            free(default_local_hostname);
     638            default_local_hostname = sep->se_local_hostname;
     639            goto more;
    648640        }
    649641    } else
    650         sep->se_hostaddr = xxstrdup(defhost);
    651 
    652     sep->se_service = xxstrdup(arg);
    653     arg = skip(&cp);
    654 
    655     if (strcmp(arg, "stream") == 0)
    656         sep->se_socktype = SOCK_STREAM;
    657     else if (strcmp(arg, "dgram") == 0)
    658         sep->se_socktype = SOCK_DGRAM;
    659     else if (strcmp(arg, "rdm") == 0)
    660         sep->se_socktype = SOCK_RDM;
    661     else if (strcmp(arg, "seqpacket") == 0)
    662         sep->se_socktype = SOCK_SEQPACKET;
    663     else if (strcmp(arg, "raw") == 0)
    664         sep->se_socktype = SOCK_RAW;
    665     else
    666         sep->se_socktype = -1;
    667 
    668     sep->se_proto = xxstrdup(skip(&cp));
    669 
    670     if (strcmp(sep->se_proto, "unix") == 0) {
     642        sep->se_local_hostname = xstrdup(default_local_hostname);
     643
     644    /* service socktype proto wait user[:group] prog [args] */
     645    sep->se_service = xstrdup(arg);
     646
     647    /* socktype proto wait user[:group] prog [args] */
     648    if (argc < 6) {
     649 parse_err:
     650        bb_error_msg("parse error on line %u, line is ignored",
     651                parser->lineno);
     652        free_servtab_strings(sep);
     653        /* Just "goto more" can make sep to carry over e.g.
     654         * "rpc"-ness (by having se_rpcver_lo != 0).
     655         * We will be more paranoid: */
     656        free(sep);
     657        goto new;
     658    }
     659
     660    {
     661        static const int8_t SOCK_xxx[] ALIGN1 = {
     662            -1,
     663            SOCK_STREAM, SOCK_DGRAM, SOCK_RDM,
     664            SOCK_SEQPACKET, SOCK_RAW
     665        };
     666        sep->se_socktype = SOCK_xxx[1 + index_in_strings(
     667            "stream""\0" "dgram""\0" "rdm""\0"
     668            "seqpacket""\0" "raw""\0"
     669            , token[1])];
     670    }
     671
     672    /* {unix,[rpc/]{tcp,udp}[6]} wait user[:group] prog [args] */
     673    sep->se_proto = arg = xstrdup(token[2]);
     674    if (strcmp(arg, "unix") == 0) {
    671675        sep->se_family = AF_UNIX;
    672676    } else {
     677        char *six;
    673678        sep->se_family = AF_INET;
    674         if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
     679        six = last_char_is(arg, '6');
     680        if (six) {
    675681#if ENABLE_FEATURE_IPV6
     682            *six = '\0';
    676683            sep->se_family = AF_INET6;
    677684#else
    678             bb_error_msg("%s: IPV6 not supported", sep->se_proto);
    679 #endif
    680         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
     685            bb_error_msg("%s: no support for IPv6", sep->se_proto);
     686            goto parse_err;
     687#endif
     688        }
     689        if (strncmp(arg, "rpc/", 4) == 0) {
    681690#if ENABLE_FEATURE_INETD_RPC
    682             char *p, *ccp;
    683             long l;
    684 
     691            unsigned n;
     692            arg += 4;
    685693            p = strchr(sep->se_service, '/');
    686             if (p == 0) {
    687                 bb_error_msg("%s: no rpc version", sep->se_service);
    688                 goto more;
     694            if (p == NULL) {
     695                bb_error_msg("no rpc version: '%s'", sep->se_service);
     696                goto parse_err;
    689697            }
    690698            *p++ = '\0';
    691             l = strtol(p, &ccp, 0);
    692             if (ccp == p || l < 0 || l > INT_MAX) {
    693  badafterall:
    694                 bb_error_msg("%s/%s: bad rpc version", sep->se_service, p);
    695                 goto more;
     699            n = bb_strtou(p, &p, 10);
     700            if (n > INT_MAX) {
     701 bad_ver_spec:
     702                bb_error_msg("bad rpc version");
     703                goto parse_err;
    696704            }
    697             sep->se_rpcversl = sep->se_rpcversh = l;
    698             if (*ccp == '-') {
    699                 p = ccp + 1;
    700                 l = strtol(p, &ccp, 0);
    701                 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
    702                     goto badafterall;
    703                 sep->se_rpcversh = l;
    704             } else if (*ccp != '\0')
    705                 goto badafterall;
     705            sep->se_rpcver_lo = sep->se_rpcver_hi = n;
     706            if (*p == '-') {
     707                p++;
     708                n = bb_strtou(p, &p, 10);
     709                if (n > INT_MAX || (int)n < sep->se_rpcver_lo)
     710                    goto bad_ver_spec;
     711                sep->se_rpcver_hi = n;
     712            }
     713            if (*p != '\0')
     714                goto bad_ver_spec;
    706715#else
    707             bb_error_msg("%s: rpc services not supported", sep->se_service);
     716            bb_error_msg("no support for rpc services");
     717            goto parse_err;
    708718#endif
    709719        }
    710     }
    711     arg = skip(&cp);
    712     if (arg == NULL)
    713         goto more;
    714 
    715     {
    716         char *s = strchr(arg, '.');
    717         if (s) {
    718             *s++ = '\0';
    719             sep->se_max = xatoi(s);
    720         } else
    721             sep->se_max = toomany;
    722     }
    723     sep->se_wait = strcmp(arg, "wait") == 0;
    724     /* if ((arg = skip(&cp, 1)) == NULL) */
    725     /* goto more; */
    726     sep->se_user = xxstrdup(skip(&cp));
     720        /* we don't really need getprotobyname()! */
     721        if (strcmp(arg, "tcp") == 0)
     722            sep->se_proto_no = IPPROTO_TCP; /* = 6 */
     723        if (strcmp(arg, "udp") == 0)
     724            sep->se_proto_no = IPPROTO_UDP; /* = 17 */
     725        if (six)
     726            *six = '6';
     727        if (!sep->se_proto_no) /* not tcp/udp?? */
     728            goto parse_err;
     729    }
     730
     731    /* [no]wait[.max] user[:group] prog [args] */
     732    arg = token[3];
     733    sep->se_max = max_concurrency;
     734    p = strchr(arg, '.');
     735    if (p) {
     736        *p++ = '\0';
     737        sep->se_max = bb_strtou(p, NULL, 10);
     738        if (errno)
     739            goto parse_err;
     740    }
     741    sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
     742    if (!sep->se_wait) /* "no" seen */
     743        arg += 2;
     744    if (strcmp(arg, "wait") != 0)
     745        goto parse_err;
     746
     747    /* user[:group] prog [args] */
     748    sep->se_user = xstrdup(token[4]);
    727749    arg = strchr(sep->se_user, '.');
    728750    if (arg == NULL)
     
    732754        sep->se_group = xstrdup(arg);
    733755    }
    734     /* if ((arg = skip(&cp, 1)) == NULL) */
    735     /* goto more; */
    736 
    737     arg = skip(&cp);
    738     sep->se_server = xxstrdup(arg);
    739     if (strcmp(sep->se_server, "internal") == 0) {
    740 #ifdef INETD_FEATURE_ENABLED
    741         const struct builtin *bi;
    742 
    743         for (bi = builtins; bi->bi_service; bi++)
    744             if (bi->bi_socktype == sep->se_socktype &&
    745                     strcmp(bi->bi_service, sep->se_service) == 0)
    746                 break;
    747         if (bi->bi_service == 0) {
    748             bb_error_msg("internal service %s unknown", sep->se_service);
    749             goto more;
    750         }
    751         sep->se_bi = bi;
    752         sep->se_wait = bi->bi_wait;
    753 #else
    754         bb_perror_msg("internal service %s unknown", sep->se_service);
    755         goto more;
    756 #endif
    757     }
    758 #ifdef INETD_FEATURE_ENABLED
    759         else
    760         sep->se_bi = NULL;
     756
     757    /* prog [args] */
     758    sep->se_program = xstrdup(token[5]);
     759#ifdef INETD_BUILTINS_ENABLED
     760    if (strcmp(sep->se_program, "internal") == 0
     761     && strlen(sep->se_service) <= 7
     762     && (sep->se_socktype == SOCK_STREAM
     763         || sep->se_socktype == SOCK_DGRAM)
     764    ) {
     765        unsigned i;
     766        for (i = 0; i < ARRAY_SIZE(builtins); i++)
     767            if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
     768                goto found_bi;
     769        bb_error_msg("unknown internal service %s", sep->se_service);
     770        goto parse_err;
     771 found_bi:
     772        sep->se_builtin = &builtins[i];
     773        /* stream builtins must be "nowait", dgram must be "wait" */
     774        if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
     775            goto parse_err;
     776    }
    761777#endif
    762778    argc = 0;
    763     for (; cp; arg = skip(&cp)) {
    764         if (argc < MAXARGV)
    765             sep->se_argv[argc++] = xxstrdup(arg);
    766     }
    767     while (argc <= MAXARGV)
    768         sep->se_argv[argc++] = NULL;
    769 
    770     /*
    771      * Now that we've processed the entire line, check if the hostname
    772      * specifier was a comma separated list of hostnames. If so
    773      * we'll make new entries for each address.
    774      */
    775     while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) {
    776         nsep = dupconfig(sep);
    777 
    778         /*
    779          * NULL terminate the hostname field of the existing entry,
    780          * and make a dup for the new entry.
    781          */
     779    while ((arg = token[6+argc]) != NULL && argc < MAXARGV)
     780        sep->se_argv[argc++] = xstrdup(arg);
     781    /* Some inetd.conf files have no argv's, not even argv[0].
     782     * Fix them up.
     783     * (Technically, programs can be execed with argv[0] = NULL,
     784     * but many programs do not like that at all) */
     785    if (argc == 0)
     786        sep->se_argv[0] = xstrdup(sep->se_program);
     787
     788    /* catch mixups. "<service> stream udp ..." == wtf */
     789    if (sep->se_socktype == SOCK_STREAM) {
     790        if (sep->se_proto_no == IPPROTO_UDP)
     791            goto parse_err;
     792    }
     793    if (sep->se_socktype == SOCK_DGRAM) {
     794        if (sep->se_proto_no == IPPROTO_TCP)
     795            goto parse_err;
     796    }
     797
     798//  bb_info_msg(
     799//      "ENTRY[%s][%s][%s][%d][%d][%d][%d][%d][%s][%s][%s]",
     800//      sep->se_local_hostname, sep->se_service, sep->se_proto, sep->se_wait, sep->se_proto_no,
     801//      sep->se_max, sep->se_count, sep->se_time, sep->se_user, sep->se_group, sep->se_program);
     802
     803    /* check if the hostname specifier is a comma separated list
     804     * of hostnames. we'll make new entries for each address. */
     805    while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
     806        nsep = dup_servtab(sep);
     807        /* NUL terminate the hostname field of the existing entry,
     808         * and make a dup for the new entry. */
    782809        *hostdelim++ = '\0';
    783         nsep->se_hostaddr = xstrdup(hostdelim);
    784 
     810        nsep->se_local_hostname = xstrdup(hostdelim);
    785811        nsep->se_next = sep->se_next;
    786812        sep->se_next = nsep;
    787813    }
    788814
    789     nsep = sep;
    790     while (nsep != NULL) {
    791         nsep->se_checked = 1;
    792         if (nsep->se_family == AF_INET) {
    793             if (LONE_CHAR(nsep->se_hostaddr, '*'))
    794                 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
    795             else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
    796                 struct hostent *hp;
    797 
    798                 hp = gethostbyname(nsep->se_hostaddr);
    799                 if (hp == 0) {
    800                     bb_error_msg("%s: unknown host", nsep->se_hostaddr);
    801                     nsep->se_checked = 0;
    802                     goto skip;
    803                 } else if (hp->h_addrtype != AF_INET) {
    804                     bb_error_msg("%s: address isn't an Internet "
    805                                   "address", nsep->se_hostaddr);
    806                     nsep->se_checked = 0;
    807                     goto skip;
    808                 } else {
    809                     int i = 1;
    810 
    811                     memmove(&nsep->se_ctrladdr_in.sin_addr,
    812                                    hp->h_addr_list[0], sizeof(struct in_addr));
    813                     while (hp->h_addr_list[i] != NULL) {
    814                         psep = dupconfig(nsep);
    815                         psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
    816                         psep->se_checked = 1;
    817                         memmove(&psep->se_ctrladdr_in.sin_addr,
    818                                      hp->h_addr_list[i], sizeof(struct in_addr));
    819                         psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
    820                         i++;
    821                         /* Prepend to list, don't want to look up */
    822                         /* its hostname again. */
    823                         psep->se_next = sep;
    824                         sep = psep;
    825                     }
    826                 }
    827             }
    828         }
    829 /* XXX BUG?: is this skip: label supposed to remain? */
    830  skip:
    831         nsep = nsep->se_next;
    832     }
    833 
    834     /*
    835      * Finally, free any entries which failed the gethostbyname
    836      * check.
    837      */
    838     psep = NULL;
    839     nsep = sep;
    840     while (nsep != NULL) {
    841         servtab_t *tsep;
    842 
    843         if (nsep->se_checked == 0) {
    844             tsep = nsep;
    845             if (psep == NULL) {
    846                 sep = nsep->se_next;
    847                 nsep = sep;
    848             } else {
    849                 nsep = nsep->se_next;
    850                 psep->se_next = nsep;
    851             }
    852             freeconfig(tsep);
    853         } else {
    854             nsep->se_checked = 0;
    855             psep = nsep;
    856             nsep = nsep->se_next;
    857         }
    858     }
     815    /* was doing it here: */
     816    /* DNS resolution, create copies for each IP address */
     817    /* IPv6-ization destroyed it :( */
    859818
    860819    return sep;
    861820}
    862821
    863 #define Block_Using_Signals(m) do { \
    864     sigemptyset(&m); \
    865     sigaddset(&m, SIGCHLD); \
    866     sigaddset(&m, SIGHUP); \
    867     sigaddset(&m, SIGALRM); \
    868     sigprocmask(SIG_BLOCK, &m, NULL); \
    869 } while (0)
    870 
    871 static servtab_t *enter(servtab_t *cp)
     822static servtab_t *insert_in_servlist(servtab_t *cp)
    872823{
    873824    servtab_t *sep;
     
    875826
    876827    sep = new_servtab();
    877     *sep = *cp;
     828    *sep = *cp; /* struct copy */
    878829    sep->se_fd = -1;
    879830#if ENABLE_FEATURE_INETD_RPC
    880831    sep->se_rpcprog = -1;
    881832#endif
    882     Block_Using_Signals(omask);
    883     sep->se_next = servtab;
    884     servtab = sep;
    885     sigprocmask(SIG_UNBLOCK, &omask, NULL);
     833    block_CHLD_HUP_ALRM(&omask);
     834    sep->se_next = serv_list;
     835    serv_list = sep;
     836    restore_sigmask(&omask);
    886837    return sep;
    887838}
    888839
    889 static int matchconf(servtab_t *old, servtab_t *new)
    890 {
     840static int same_serv_addr_proto(servtab_t *old, servtab_t *new)
     841{
     842    if (strcmp(old->se_local_hostname, new->se_local_hostname) != 0)
     843        return 0;
    891844    if (strcmp(old->se_service, new->se_service) != 0)
    892845        return 0;
    893 
    894     if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
    895         return 0;
    896 
    897846    if (strcmp(old->se_proto, new->se_proto) != 0)
    898847        return 0;
    899 
    900     /*
    901      * If the new servtab is bound to a specific address, check that the
    902      * old servtab is bound to the same entry. If the new service is not
    903      * bound to a specific address then the check of se_hostaddr above
    904      * is sufficient.
    905      */
    906 
    907     if (old->se_family == AF_INET && new->se_family == AF_INET &&
    908             memcmp(&old->se_ctrladdr_in.sin_addr,
    909                     &new->se_ctrladdr_in.sin_addr,
    910                     sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
    911         return 0;
    912 
    913 #if ENABLE_FEATURE_IPV6
    914     if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
    915             memcmp(&old->se_ctrladdr_in6.sin6_addr,
    916                     &new->se_ctrladdr_in6.sin6_addr,
    917                     sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
    918         return 0;
    919 #endif
    920848    return 1;
    921849}
    922850
    923 static void config(int sig ATTRIBUTE_UNUSED)
     851static void reread_config_file(int sig UNUSED_PARAM)
    924852{
    925853    servtab_t *sep, *cp, **sepp;
     854    len_and_sockaddr *lsa;
    926855    sigset_t omask;
    927     size_t n;
    928     char protoname[10];
    929 
    930     if (!setconfig()) {
    931         bb_perror_msg("%s", config_filename);
    932         return;
    933     }
    934     for (sep = servtab; sep; sep = sep->se_next)
     856    unsigned n;
     857    uint16_t port;
     858    int save_errno = errno;
     859
     860    if (!reopen_config_file())
     861        goto ret;
     862    for (sep = serv_list; sep; sep = sep->se_next)
    935863        sep->se_checked = 0;
    936     cp = getconfigent();
    937     while (cp != NULL) {
    938         for (sep = servtab; sep; sep = sep->se_next)
    939             if (matchconf(sep, cp))
     864
     865    goto first_line;
     866    while (1) {
     867        if (cp == NULL) {
     868 first_line:
     869            cp = parse_one_line();
     870            if (cp == NULL)
    940871                break;
    941 
    942         if (sep != 0) {
     872        }
     873        for (sep = serv_list; sep; sep = sep->se_next)
     874            if (same_serv_addr_proto(sep, cp))
     875                goto equal_servtab;
     876        /* not an "equal" servtab */
     877        sep = insert_in_servlist(cp);
     878        goto after_check;
     879 equal_servtab:
     880        {
    943881            int i;
    944882
    945 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
    946 
    947             Block_Using_Signals(omask);
    948             /*
    949              * sep->se_wait may be holding the pid of a daemon
    950              * that we're waiting for.  If so, don't overwrite
    951              * it unless the config file explicitly says don't
    952              * wait.
    953              */
    954             if (
    955 #ifdef INETD_FEATURE_ENABLED
    956                 cp->se_bi == 0 &&
    957 #endif
    958                 (sep->se_wait == 1 || cp->se_wait == 0))
    959                 sep->se_wait = cp->se_wait;
    960             SWAP(int, cp->se_max, sep->se_max);
    961             SWAP(char *, sep->se_user, cp->se_user);
    962             SWAP(char *, sep->se_group, cp->se_group);
    963             SWAP(char *, sep->se_server, cp->se_server);
     883            block_CHLD_HUP_ALRM(&omask);
     884#if ENABLE_FEATURE_INETD_RPC
     885            if (is_rpc_service(sep))
     886                unregister_rpc(sep);
     887            sep->se_rpcver_lo = cp->se_rpcver_lo;
     888            sep->se_rpcver_hi = cp->se_rpcver_hi;
     889#endif
     890            if (cp->se_wait == 0) {
     891                /* New config says "nowait". If old one
     892                 * was "wait", we currently may be waiting
     893                 * for a child (and not accepting connects).
     894                 * Stop waiting, start listening again.
     895                 * (if it's not true, this op is harmless) */
     896                add_fd_to_set(sep->se_fd);
     897            }
     898            sep->se_wait = cp->se_wait;
     899            sep->se_max = cp->se_max;
     900            /* string fields need more love - we don't want to leak them */
     901#define SWAP(type, a, b) do { type c = (type)a; a = (type)b; b = (type)c; } while (0)
     902            SWAP(char*, sep->se_user, cp->se_user);
     903            SWAP(char*, sep->se_group, cp->se_group);
     904            SWAP(char*, sep->se_program, cp->se_program);
    964905            for (i = 0; i < MAXARGV; i++)
    965                 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
     906                SWAP(char*, sep->se_argv[i], cp->se_argv[i]);
    966907#undef SWAP
    967 
     908            restore_sigmask(&omask);
     909            free_servtab_strings(cp);
     910        }
     911 after_check:
     912        /* cp->string_fields are consumed by insert_in_servlist()
     913         * or freed at this point, cp itself is not yet freed. */
     914        sep->se_checked = 1;
     915
     916        /* create new len_and_sockaddr */
     917        switch (sep->se_family) {
     918            struct sockaddr_un *sun;
     919        case AF_UNIX:
     920            lsa = xzalloc_lsa(AF_UNIX);
     921            sun = (struct sockaddr_un*)&lsa->u.sa;
     922            safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
     923            break;
     924
     925        default: /* case AF_INET, case AF_INET6 */
     926            n = bb_strtou(sep->se_service, NULL, 10);
    968927#if ENABLE_FEATURE_INETD_RPC
    969             if (isrpcservice(sep))
    970                 unregister_rpc(sep);
    971             sep->se_rpcversl = cp->se_rpcversl;
    972             sep->se_rpcversh = cp->se_rpcversh;
    973 #endif
    974             sigprocmask(SIG_UNBLOCK, &omask, NULL);
    975             freeconfig(cp);
    976         } else {
    977             sep = enter(cp);
    978         }
    979         sep->se_checked = 1;
    980 
    981         switch (sep->se_family) {
    982         case AF_UNIX:
    983             if (sep->se_fd != -1)
    984                 break;
    985             (void) unlink(sep->se_service);
    986             n = strlen(sep->se_service);
    987             if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
    988                 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
    989             safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
    990             sep->se_ctrladdr_un.sun_family = AF_UNIX;
    991             sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
    992             setup(sep);
    993             break;
    994         case AF_INET:
    995             sep->se_ctrladdr_in.sin_family = AF_INET;
    996             /* se_ctrladdr_in was set in getconfigent */
    997             sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
    998 
    999 #if ENABLE_FEATURE_INETD_RPC
    1000             if (isrpcservice(sep)) {
    1001                 struct rpcent *rp;
    1002                 // FIXME: atoi_or_else(str, 0) would be handy here
    1003                 sep->se_rpcprog = atoi(sep->se_service);
    1004                 if (sep->se_rpcprog == 0) {
    1005                     rp = getrpcbyname(sep->se_service);
    1006                     if (rp == 0) {
     928            if (is_rpc_service(sep)) {
     929                sep->se_rpcprog = n;
     930                if (errno) { /* se_service is not numeric */
     931                    struct rpcent *rp = getrpcbyname(sep->se_service);
     932                    if (rp == NULL) {
    1007933                        bb_error_msg("%s: unknown rpc service", sep->se_service);
    1008                         goto serv_unknown;
     934                        goto next_cp;
    1009935                    }
    1010936                    sep->se_rpcprog = rp->r_number;
    1011937                }
    1012938                if (sep->se_fd == -1)
    1013                     setup(sep);
     939                    prepare_socket_fd(sep);
    1014940                if (sep->se_fd != -1)
    1015941                    register_rpc(sep);
    1016             } else
    1017 #endif
    1018             {
    1019                 uint16_t port = htons(atoi(sep->se_service));
    1020                 // FIXME: atoi_or_else(str, 0) would be handy here
    1021                 if (!port) {
    1022                      /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
    1023                     if (isdigit(protoname[strlen(protoname) - 1]))
    1024                         protoname[strlen(protoname) - 1] = '\0';
    1025                     sp = getservbyname(sep->se_service, protoname);
    1026                     if (sp == 0) {
    1027                         bb_error_msg("%s/%s: unknown service",
    1028                                 sep->se_service, sep->se_proto);
    1029                         goto serv_unknown;
    1030                     }
    1031                     port = sp->s_port;
     942                goto next_cp;
     943            }
     944#endif
     945            /* what port to listen on? */
     946            port = htons(n);
     947            if (errno || n > 0xffff) { /* se_service is not numeric */
     948                char protoname[4];
     949                struct servent *sp;
     950                /* can result only in "tcp" or "udp": */
     951                safe_strncpy(protoname, sep->se_proto, 4);
     952                sp = getservbyname(sep->se_service, protoname);
     953                if (sp == NULL) {
     954                    bb_error_msg("%s/%s: unknown service",
     955                            sep->se_service, sep->se_proto);
     956                    goto next_cp;
    1032957                }
    1033                 if (port != sep->se_ctrladdr_in.sin_port) {
    1034                     sep->se_ctrladdr_in.sin_port = port;
    1035                     if (sep->se_fd != -1) {
    1036                         FD_CLR(sep->se_fd, &allsock);
    1037                         nsock--;
    1038                         (void) close(sep->se_fd);
    1039                     }
    1040                     sep->se_fd = -1;
     958                port = sp->s_port;
     959            }
     960            if (LONE_CHAR(sep->se_local_hostname, '*')) {
     961                lsa = xzalloc_lsa(sep->se_family);
     962                set_nport(lsa, port);
     963            } else {
     964                lsa = host_and_af2sockaddr(sep->se_local_hostname,
     965                        ntohs(port), sep->se_family);
     966                if (!lsa) {
     967                    bb_error_msg("%s/%s: unknown host '%s'",
     968                        sep->se_service, sep->se_proto,
     969                        sep->se_local_hostname);
     970                    goto next_cp;
    1041971                }
    1042                 if (sep->se_fd == -1)
    1043                     setup(sep);
    1044972            }
    1045973            break;
    1046 #if ENABLE_FEATURE_IPV6
    1047         case AF_INET6:
    1048             sep->se_ctrladdr_in6.sin6_family = AF_INET6;
    1049             /* se_ctrladdr_in was set in getconfigent */
    1050             sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
    1051 
    1052 #if ENABLE_FEATURE_INETD_RPC
    1053             if (isrpcservice(sep)) {
    1054                 struct rpcent *rp;
    1055 
    1056                 sep->se_rpcprog = atoi(sep->se_service);
    1057                 if (sep->se_rpcprog == 0) {
    1058                     rp = getrpcbyname(sep->se_service);
    1059                     if (rp == 0) {
    1060                         bb_error_msg("%s: unknown rpc service", sep->se_service);
    1061                         goto serv_unknown;
    1062                     }
    1063                     sep->se_rpcprog = rp->r_number;
    1064                 }
    1065                 if (sep->se_fd == -1)
    1066                     setup(sep);
    1067                 if (sep->se_fd != -1)
    1068                     register_rpc(sep);
    1069             } else
    1070 #endif
    1071             {
    1072                 uint16_t port = htons(atoi(sep->se_service));
    1073 
    1074                 if (!port) {
    1075                      /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
    1076                     if (isdigit(protoname[strlen(protoname) - 1]))
    1077                         protoname[strlen(protoname) - 1] = '\0';
    1078                     sp = getservbyname(sep->se_service, protoname);
    1079                     if (sp == 0) {
    1080                         bb_error_msg("%s/%s: unknown service",
    1081                                 sep->se_service, sep->se_proto);
    1082                         goto serv_unknown;
    1083                     }
    1084                     port = sp->s_port;
    1085                 }
    1086                 if (port != sep->se_ctrladdr_in6.sin6_port) {
    1087                     sep->se_ctrladdr_in6.sin6_port = port;
    1088                     if (sep->se_fd != -1) {
    1089                         FD_CLR(sep->se_fd, &allsock);
    1090                         nsock--;
    1091                         (void) close(sep->se_fd);
    1092                     }
    1093                     sep->se_fd = -1;
    1094                 }
    1095                 if (sep->se_fd == -1)
    1096                     setup(sep);
    1097             }
    1098             break;
    1099 #endif /* FEATURE_IPV6 */
     974        } /* end of "switch (sep->se_family)" */
     975
     976        /* did lsa change? Then close/open */
     977        if (sep->se_lsa == NULL
     978         || lsa->len != sep->se_lsa->len
     979         || memcmp(&lsa->u.sa, &sep->se_lsa->u.sa, lsa->len) != 0
     980        ) {
     981            remove_fd_from_set(sep->se_fd);
     982            maybe_close(sep->se_fd);
     983            free(sep->se_lsa);
     984            sep->se_lsa = lsa;
     985            sep->se_fd = -1;
     986        } else {
     987            free(lsa);
    1100988        }
    1101  serv_unknown:
    1102         if (cp->se_next != NULL) {
    1103             servtab_t *tmp = cp;
    1104 
    1105             cp = cp->se_next;
    1106             free(tmp);
    1107         } else {
    1108             free(cp);
    1109             cp = getconfigent();
    1110         }
    1111     }
    1112     endconfig();
    1113     /*
    1114      * Purge anything not looked at above.
    1115      */
    1116     Block_Using_Signals(omask);
    1117     sepp = &servtab;
     989        if (sep->se_fd == -1)
     990            prepare_socket_fd(sep);
     991 next_cp:
     992        sep = cp->se_next;
     993        free(cp);
     994        cp = sep;
     995    } /* end of "while (1) parse lines" */
     996    close_config_file();
     997
     998    /* Purge anything not looked at above - these are stale entries,
     999     * new config file doesnt have them. */
     1000    block_CHLD_HUP_ALRM(&omask);
     1001    sepp = &serv_list;
    11181002    while ((sep = *sepp)) {
    11191003        if (sep->se_checked) {
     
    11221006        }
    11231007        *sepp = sep->se_next;
    1124         if (sep->se_fd != -1) {
    1125             FD_CLR(sep->se_fd, &allsock);
    1126             nsock--;
    1127             (void) close(sep->se_fd);
    1128         }
     1008        remove_fd_from_set(sep->se_fd);
     1009        maybe_close(sep->se_fd);
    11291010#if ENABLE_FEATURE_INETD_RPC
    1130         if (isrpcservice(sep))
     1011        if (is_rpc_service(sep))
    11311012            unregister_rpc(sep);
    11321013#endif
    11331014        if (sep->se_family == AF_UNIX)
    1134             (void) unlink(sep->se_service);
    1135         freeconfig(sep);
     1015            unlink(sep->se_service);
     1016        free_servtab_strings(sep);
    11361017        free(sep);
    11371018    }
    1138     sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1139 }
    1140 
    1141 
    1142 static void reapchild(int sig ATTRIBUTE_UNUSED)
     1019    restore_sigmask(&omask);
     1020 ret:
     1021    errno = save_errno;
     1022}
     1023
     1024static void reap_child(int sig UNUSED_PARAM)
    11431025{
    11441026    pid_t pid;
    1145     int save_errno = errno, status;
     1027    int status;
    11461028    servtab_t *sep;
     1029    int save_errno = errno;
    11471030
    11481031    for (;;) {
    1149         pid = wait3(&status, WNOHANG, NULL);
     1032        pid = wait_any_nohang(&status);
    11501033        if (pid <= 0)
    11511034            break;
    1152         for (sep = servtab; sep; sep = sep->se_next)
    1153             if (sep->se_wait == pid) {
    1154                 if (WIFEXITED(status) && WEXITSTATUS(status))
    1155                     bb_error_msg("%s: exit status 0x%x",
    1156                             sep->se_server, WEXITSTATUS(status));
    1157                 else if (WIFSIGNALED(status))
    1158                     bb_error_msg("%s: exit signal 0x%x",
    1159                             sep->se_server, WTERMSIG(status));
    1160                 sep->se_wait = 1;
    1161                 FD_SET(sep->se_fd, &allsock);
    1162                 nsock++;
    1163             }
     1035        for (sep = serv_list; sep; sep = sep->se_next) {
     1036            if (sep->se_wait != pid)
     1037                continue;
     1038            /* One of our "wait" services */
     1039            if (WIFEXITED(status) && WEXITSTATUS(status))
     1040                bb_error_msg("%s: exit status %u",
     1041                        sep->se_program, WEXITSTATUS(status));
     1042            else if (WIFSIGNALED(status))
     1043                bb_error_msg("%s: exit signal %u",
     1044                        sep->se_program, WTERMSIG(status));
     1045            sep->se_wait = 1;
     1046            add_fd_to_set(sep->se_fd);
     1047            break;
     1048        }
    11641049    }
    11651050    errno = save_errno;
    11661051}
    11671052
    1168 static void retry(int sig ATTRIBUTE_UNUSED)
    1169 {
     1053static void retry_network_setup(int sig UNUSED_PARAM)
     1054{
     1055    int save_errno = errno;
    11701056    servtab_t *sep;
    11711057
    1172     timingout = 0;
    1173     for (sep = servtab; sep; sep = sep->se_next) {
     1058    alarm_armed = 0;
     1059    for (sep = serv_list; sep; sep = sep->se_next) {
    11741060        if (sep->se_fd == -1) {
    1175             switch (sep->se_family) {
    1176             case AF_UNIX:
    1177             case AF_INET:
    1178 #if ENABLE_FEATURE_IPV6
    1179             case AF_INET6:
    1180 #endif
    1181                 setup(sep);
     1061            prepare_socket_fd(sep);
    11821062#if ENABLE_FEATURE_INETD_RPC
    1183                 if (sep->se_fd != -1 && isrpcservice(sep))
    1184                     register_rpc(sep);
    1185 #endif
    1186                 break;
    1187             }
     1063            if (sep->se_fd != -1 && is_rpc_service(sep))
     1064                register_rpc(sep);
     1065#endif
    11881066        }
    11891067    }
    1190 }
    1191 
    1192 static void goaway(int sig ATTRIBUTE_UNUSED)
     1068    errno = save_errno;
     1069}
     1070
     1071static void clean_up_and_exit(int sig UNUSED_PARAM)
    11931072{
    11941073    servtab_t *sep;
    11951074
    11961075    /* XXX signal race walking sep list */
    1197     for (sep = servtab; sep; sep = sep->se_next) {
     1076    for (sep = serv_list; sep; sep = sep->se_next) {
    11981077        if (sep->se_fd == -1)
    11991078            continue;
     
    12011080        switch (sep->se_family) {
    12021081        case AF_UNIX:
    1203             (void) unlink(sep->se_service);
     1082            unlink(sep->se_service);
    12041083            break;
    1205         case AF_INET:
    1206 #if ENABLE_FEATURE_IPV6
    1207         case AF_INET6:
    1208 #endif
     1084        default: /* case AF_INET, AF_INET6 */
    12091085#if ENABLE_FEATURE_INETD_RPC
    1210             if (sep->se_wait == 1 && isrpcservice(sep))
     1086            if (sep->se_wait == 1 && is_rpc_service(sep))
    12111087                unregister_rpc(sep);   /* XXX signal race */
    12121088#endif
    12131089            break;
    12141090        }
    1215         (void) close(sep->se_fd);
     1091        if (ENABLE_FEATURE_CLEAN_UP)
     1092            close(sep->se_fd);
    12161093    }
    12171094    remove_pidfile(_PATH_INETDPID);
    1218     exit(0);
    1219 }
    1220 
    1221 
    1222 #ifdef INETD_SETPROCTITLE
    1223 static char **Argv;
    1224 static char *LastArg;
    1225 
    1226 static void
    1227 inetd_setproctitle(char *a, int s)
    1228 {
    1229     socklen_t size;
    1230     char *cp;
    1231     struct sockaddr_in prt_sin;
    1232     char buf[80];
    1233 
    1234     cp = Argv[0];
    1235     size = sizeof(prt_sin);
    1236     (void) snprintf(buf, sizeof buf, "-%s", a);
    1237     if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {
    1238         char *sa = inet_ntoa(prt_sin.sin_addr);
    1239 
    1240         buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0';
    1241         strcat(buf, " [");
    1242         strcat(buf, sa);
    1243         strcat(buf, "]");
    1244     }
    1245     strncpy(cp, buf, LastArg - cp);
    1246     cp += strlen(cp);
    1247     while (cp < LastArg)
    1248         *cp++ = ' ';
    1249 }
    1250 #endif
    1251 
    1252 
    1253 int inetd_main(int argc, char **argv);
    1254 int inetd_main(int argc, char **argv)
    1255 {
    1256     servtab_t *sep;
     1095    exit(EXIT_SUCCESS);
     1096}
     1097
     1098int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1099int inetd_main(int argc UNUSED_PARAM, char **argv)
     1100{
     1101    struct sigaction sa, saved_pipe_handler;
     1102    servtab_t *sep, *sep2;
    12571103    struct passwd *pwd;
    1258     struct group *grp = NULL;
    1259     int tmpint;
    1260     struct sigaction sa, sapipe;
     1104    struct group *grp = grp; /* for compiler */
    12611105    int opt;
    12621106    pid_t pid;
    1263     char buf[50];
    1264     char *stoomany;
    1265     sigset_t omask, wait_mask;
    1266 
    1267 #ifdef INETD_SETPROCTITLE
    1268     char **envp = environ;
    1269 
    1270     Argv = argv;
    1271     if (envp == 0 || *envp == 0)
    1272         envp = argv;
    1273     while (*envp)
    1274         envp++;
    1275     LastArg = envp[-1] + strlen(envp[-1]);
    1276 #endif
    1277 
    1278     uid = getuid();
    1279     if (uid != 0)
     1107    sigset_t omask;
     1108
     1109    INIT_G();
     1110
     1111    real_uid = getuid();
     1112    if (real_uid != 0) /* run by non-root user */
    12801113        config_filename = NULL;
    12811114
    1282     opt = getopt32(argv, "R:f", &stoomany);
    1283     if (opt & 1)
    1284         toomany = xatoi_u(stoomany);
     1115    opt_complementary = "R+:q+"; /* -q N, -R N */
     1116    opt = getopt32(argv, "R:feq:", &max_concurrency, &global_queuelen);
    12851117    argv += optind;
    1286     argc -= optind;
    1287     if (argc)
     1118    //argc -= optind;
     1119    if (argv[0])
    12881120        config_filename = argv[0];
    12891121    if (config_filename == NULL)
    1290         bb_error_msg_and_die("non-root must specify a config file");
    1291 
     1122        bb_error_msg_and_die("non-root must specify config file");
    12921123    if (!(opt & 2))
    12931124        bb_daemonize_or_rexec(0, argv - optind);
    12941125    else
    12951126        bb_sanitize_stdio();
    1296     openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
    1297     logmode = LOGMODE_SYSLOG;
    1298 
    1299     if (uid == 0) {
    1300         /* If run by hand, ensure groups vector gets trashed */
     1127    if (!(opt & 4)) {
     1128        /* LOG_NDELAY: connect to syslog daemon NOW.
     1129         * Otherwise, we may open syslog socket
     1130         * in vforked child, making opened fds and syslog()
     1131         * internal state inconsistent.
     1132         * This was observed to leak file descriptors. */
     1133        openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON);
     1134        logmode = LOGMODE_SYSLOG;
     1135    }
     1136
     1137    if (real_uid == 0) {
     1138        /* run by root, ensure groups vector gets trashed */
    13011139        gid_t gid = getgid();
    13021140        setgroups(1, &gid);
     
    13051143    write_pidfile(_PATH_INETDPID);
    13061144
    1307     if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
    1308         bb_perror_msg("getrlimit");
    1309     } else {
    1310         rlim_ofile_cur = rlim_ofile.rlim_cur;
    1311         if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
    1312             rlim_ofile_cur = OPEN_MAX;
    1313     }
    1314 
    1315     memset((char *) &sa, 0, sizeof(sa));
    1316     sigemptyset(&sa.sa_mask);
     1145    /* never fails under Linux (except if you pass it bad arguments) */
     1146    getrlimit(RLIMIT_NOFILE, &rlim_ofile);
     1147    rlim_ofile_cur = rlim_ofile.rlim_cur;
     1148    if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
     1149        rlim_ofile_cur = OPEN_MAX;
     1150
     1151    memset(&sa, 0, sizeof(sa));
     1152    /*sigemptyset(&sa.sa_mask); - memset did it */
    13171153    sigaddset(&sa.sa_mask, SIGALRM);
    13181154    sigaddset(&sa.sa_mask, SIGCHLD);
    13191155    sigaddset(&sa.sa_mask, SIGHUP);
    1320     sa.sa_handler = retry;
    1321     sigaction(SIGALRM, &sa, NULL);
    1322     config(SIGHUP);
    1323     sa.sa_handler = config;
    1324     sigaction(SIGHUP, &sa, NULL);
    1325     sa.sa_handler = reapchild;
    1326     sigaction(SIGCHLD, &sa, NULL);
    1327     sa.sa_handler = goaway;
    1328     sigaction(SIGTERM, &sa, NULL);
    1329     sa.sa_handler = goaway;
    1330     sigaction(SIGINT, &sa, NULL);
     1156    sa.sa_handler = retry_network_setup;
     1157    sigaction_set(SIGALRM, &sa);
     1158    sa.sa_handler = reread_config_file;
     1159    sigaction_set(SIGHUP, &sa);
     1160    sa.sa_handler = reap_child;
     1161    sigaction_set(SIGCHLD, &sa);
     1162    sa.sa_handler = clean_up_and_exit;
     1163    sigaction_set(SIGTERM, &sa);
     1164    sa.sa_handler = clean_up_and_exit;
     1165    sigaction_set(SIGINT, &sa);
    13311166    sa.sa_handler = SIG_IGN;
    1332     sigaction(SIGPIPE, &sa, &sapipe);
    1333     memset(&wait_mask, 0, sizeof(wait_mask));
    1334     {
    1335         /* space for daemons to overwrite environment for ps */
    1336 #define DUMMYSIZE       100
    1337         char dummy[DUMMYSIZE];
    1338 
    1339         (void) memset(dummy, 'x', DUMMYSIZE - 1);
    1340         dummy[DUMMYSIZE - 1] = '\0';
    1341 
    1342         (void) setenv("inetd_dummy", dummy, 1);
    1343     }
     1167    sigaction(SIGPIPE, &sa, &saved_pipe_handler);
     1168
     1169    reread_config_file(SIGHUP); /* load config from file */
    13441170
    13451171    for (;;) {
    1346         int n, ctrl = -1;
     1172        int ready_fd_cnt;
     1173        int ctrl, accepted_fd, new_udp_fd;
    13471174        fd_set readable;
    13481175
    1349         if (nsock == 0) {
    1350             Block_Using_Signals(omask);
    1351             while (nsock == 0)
    1352                 sigsuspend(&wait_mask);
    1353             sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1354         }
    1355 
    1356         readable = allsock;
    1357         n = select(maxsock + 1, &readable, NULL, NULL, NULL);
    1358         if (n <= 0) {
    1359             if (n < 0 && errno != EINTR) {
     1176        if (maxsock < 0)
     1177            recalculate_maxsock();
     1178
     1179        readable = allsock; /* struct copy */
     1180        /* if there are no fds to wait on, we will block
     1181         * until signal wakes us up (maxsock == 0, but readable
     1182         * never contains fds 0 and 1...) */
     1183        ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL);
     1184        if (ready_fd_cnt < 0) {
     1185            if (errno != EINTR) {
    13601186                bb_perror_msg("select");
    13611187                sleep(1);
     
    13641190        }
    13651191
    1366         for (sep = servtab; n && sep; sep = sep->se_next) {
     1192        for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
    13671193            if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
    13681194                continue;
    13691195
    1370             n--;
    1371             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
    1372                 ctrl = accept(sep->se_fd, NULL, NULL);
    1373                 if (ctrl < 0) {
    1374                     if (errno == EINTR)
    1375                         continue;
    1376                     bb_perror_msg("accept (for %s)", sep->se_service);
    1377                     continue;
    1378                 }
    1379                 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
    1380                     struct sockaddr_in peer;
    1381                     socklen_t plen = sizeof(peer);
    1382 
    1383                     if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) {
    1384                         bb_error_msg("cannot getpeername");
    1385                         close(ctrl);
    1386                         continue;
    1387                     }
    1388                     if (ntohs(peer.sin_port) == 20) {
    1389                         /* XXX ftp bounce */
    1390                         close(ctrl);
     1196            ready_fd_cnt--;
     1197            ctrl = sep->se_fd;
     1198            accepted_fd = -1;
     1199            new_udp_fd = -1;
     1200            if (!sep->se_wait) {
     1201                if (sep->se_socktype == SOCK_STREAM) {
     1202                    ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
     1203                    if (ctrl < 0) {
     1204                        if (errno != EINTR)
     1205                            bb_perror_msg("accept (for %s)", sep->se_service);
    13911206                        continue;
    13921207                    }
    13931208                }
    1394             } else
    1395                 ctrl = sep->se_fd;
    1396 
    1397             Block_Using_Signals(omask);
    1398             pid = 0;
    1399 #ifdef INETD_FEATURE_ENABLED
    1400             if (sep->se_bi == 0 || sep->se_bi->bi_fork)
    1401 #endif
    1402             {
    1403                 if (sep->se_count++ == 0)
    1404                     (void) gettimeofday(&sep->se_time, NULL);
    1405                 else if (toomany > 0 && sep->se_count >= sep->se_max) {
    1406                     struct timeval now;
    1407 
    1408                     (void) gettimeofday(&now, NULL);
    1409                     if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
    1410                         sep->se_time = now;
    1411                         sep->se_count = 1;
    1412                     } else {
    1413                         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1414                             close(ctrl);
    1415                         if (sep->se_family == AF_INET &&
    1416                               ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
    1417                             /*
    1418                              * Cannot close it -- there are
    1419                              * thieves on the system.
    1420                              * Simply ignore the connection.
    1421                              */
    1422                             --sep->se_count;
    1423                             continue;
    1424                         }
    1425                         bb_error_msg("%s/%s server failing (looping), service terminated",
    1426                                   sep->se_service, sep->se_proto);
    1427                         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1428                             close(ctrl);
    1429                         FD_CLR(sep->se_fd, &allsock);
    1430                         (void) close(sep->se_fd);
    1431                         sep->se_fd = -1;
    1432                         sep->se_count = 0;
    1433                         nsock--;
    1434                         sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1435                         if (!timingout) {
    1436                             timingout = 1;
    1437                             alarm(RETRYTIME);
    1438                         }
     1209                /* "nowait" udp */
     1210                if (sep->se_socktype == SOCK_DGRAM
     1211                 && sep->se_family != AF_UNIX
     1212                ) {
     1213/* How udp "nowait" works:
     1214 * child peeks at (received and buffered by kernel) UDP packet,
     1215 * performs connect() on the socket so that it is linked only
     1216 * to this peer. But this also affects parent, because descriptors
     1217 * are shared after fork() a-la dup(). When parent performs
     1218 * select(), it will see this descriptor connected to the peer (!)
     1219 * and still readable, will act on it and mess things up
     1220 * (can create many copies of same child, etc).
     1221 * Parent must create and use new socket instead. */
     1222                    new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
     1223                    if (new_udp_fd < 0) { /* error: eat packet, forget about it */
     1224 udp_err:
     1225                        recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
    14391226                        continue;
    14401227                    }
    1441                 }
    1442                 pid = fork();
    1443             }
    1444             if (pid < 0) {
    1445                 bb_perror_msg("fork");
    1446                 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1447                     close(ctrl);
    1448                 sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1449                 sleep(1);
    1450                 continue;
    1451             }
    1452             if (pid && sep->se_wait) {
    1453                 sep->se_wait = pid;
    1454                 FD_CLR(sep->se_fd, &allsock);
    1455                 nsock--;
    1456             }
    1457             sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1458             if (pid == 0) {
    1459 #ifdef INETD_FEATURE_ENABLED
    1460                 if (sep->se_bi) {
    1461                     (*sep->se_bi->bi_fn)(ctrl, sep);
    1462                 } else
    1463 #endif
    1464                 {
    1465                     pwd = getpwnam(sep->se_user);
    1466                     if (pwd == NULL) {
    1467                         bb_error_msg("getpwnam: %s: no such user", sep->se_user);
    1468                         goto do_exit1;
     1228                    setsockopt_reuseaddr(new_udp_fd);
     1229                    /* TODO: better do bind after vfork in parent,
     1230                     * so that we don't have two wildcard bound sockets
     1231                     * even for a brief moment? */
     1232                    if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
     1233                        close(new_udp_fd);
     1234                        goto udp_err;
    14691235                    }
    1470                     if (setsid() < 0)
    1471                         bb_perror_msg("%s: setsid", sep->se_service);
    1472                     if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
    1473                         bb_error_msg("getgrnam: %s: no such group", sep->se_group);
    1474                         goto do_exit1;
    1475                     }
    1476                     if (uid != 0) {
    1477                         /* a user running private inetd */
    1478                         if (uid != pwd->pw_uid)
    1479                             _exit(1);
    1480                     } else if (pwd->pw_uid) {
    1481                         if (sep->se_group)
    1482                             pwd->pw_gid = grp->gr_gid;
    1483                         xsetgid((gid_t) pwd->pw_gid);
    1484                         initgroups(pwd->pw_name, pwd->pw_gid);
    1485                         xsetuid((uid_t) pwd->pw_uid);
    1486                     } else if (sep->se_group) {
    1487                         xsetgid(grp->gr_gid);
    1488                         setgroups(1, &grp->gr_gid);
    1489                     }
    1490                     dup2(ctrl, 0);
    1491                     if (ctrl) close(ctrl);
    1492                     dup2(0, 1);
    1493                     dup2(0, 2);
    1494                     if (rlim_ofile.rlim_cur != rlim_ofile_cur)
    1495                         if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
    1496                             bb_perror_msg("setrlimit");
    1497                     closelog();
    1498                     for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
    1499                         (void) close(tmpint);
    1500                     sigaction(SIGPIPE, &sapipe, NULL);
    1501                     execv(sep->se_server, sep->se_argv);
    1502                     bb_perror_msg("execv %s", sep->se_server);
    1503  do_exit1:
    1504                     if (sep->se_socktype != SOCK_STREAM)
    1505                         recv(0, buf, sizeof(buf), 0);
    1506                     _exit(1);
    15071236                }
    15081237            }
    1509             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1510                 close(ctrl);
     1238
     1239            block_CHLD_HUP_ALRM(&omask);
     1240            pid = 0;
     1241#ifdef INETD_BUILTINS_ENABLED
     1242            /* do we need to fork? */
     1243            if (sep->se_builtin == NULL
     1244             || (sep->se_socktype == SOCK_STREAM
     1245                 && sep->se_builtin->bi_fork))
     1246#endif
     1247            {
     1248                if (sep->se_max != 0) {
     1249                    if (++sep->se_count == 1)
     1250                        sep->se_time = monotonic_sec();
     1251                    else if (sep->se_count >= sep->se_max) {
     1252                        unsigned now = monotonic_sec();
     1253                        /* did we accumulate se_max connects too quickly? */
     1254                        if (now - sep->se_time <= CNT_INTERVAL) {
     1255                            bb_error_msg("%s/%s: too many connections, pausing",
     1256                                    sep->se_service, sep->se_proto);
     1257                            remove_fd_from_set(sep->se_fd);
     1258                            close(sep->se_fd);
     1259                            sep->se_fd = -1;
     1260                            sep->se_count = 0;
     1261                            rearm_alarm(); /* will revive it in RETRYTIME sec */
     1262                            restore_sigmask(&omask);
     1263                            maybe_close(accepted_fd);
     1264                            continue; /* -> check next fd in fd set */
     1265                        }
     1266                        sep->se_count = 0;
     1267                    }
     1268                }
     1269                /* on NOMMU, streamed chargen
     1270                 * builtin wouldn't work, but it is
     1271                 * not allowed on NOMMU (ifdefed out) */
     1272#ifdef INETD_BUILTINS_ENABLED
     1273                if (BB_MMU && sep->se_builtin)
     1274                    pid = fork();
     1275                else
     1276#endif
     1277                    pid = vfork();
     1278
     1279                if (pid < 0) { /* fork error */
     1280                    bb_perror_msg("vfork"+1);
     1281                    sleep(1);
     1282                    restore_sigmask(&omask);
     1283                    maybe_close(accepted_fd);
     1284                    continue; /* -> check next fd in fd set */
     1285                }
     1286                if (pid == 0)
     1287                    pid--; /* -1: "we did fork and we are child" */
     1288            }
     1289            /* if pid == 0 here, we never forked */
     1290
     1291            if (pid > 0) { /* parent */
     1292                if (sep->se_wait) {
     1293                    /* tcp wait: we passed listening socket to child,
     1294                     * will wait for child to terminate */
     1295                    sep->se_wait = pid;
     1296                    remove_fd_from_set(sep->se_fd);
     1297                }
     1298                if (new_udp_fd >= 0) {
     1299                    /* udp nowait: child connected the socket,
     1300                     * we created and will use new, unconnected one */
     1301                    xmove_fd(new_udp_fd, sep->se_fd);
     1302                }
     1303                restore_sigmask(&omask);
     1304                maybe_close(accepted_fd);
     1305                continue; /* -> check next fd in fd set */
     1306            }
     1307
     1308            /* we are either child or didn't vfork at all */
     1309#ifdef INETD_BUILTINS_ENABLED
     1310            if (sep->se_builtin) {
     1311                if (pid) { /* "pid" is -1: we did vfork */
     1312                    close(sep->se_fd); /* listening socket */
     1313                    logmode = LOGMODE_NONE; /* make xwrite etc silent */
     1314                }
     1315                restore_sigmask(&omask);
     1316                if (sep->se_socktype == SOCK_STREAM)
     1317                    sep->se_builtin->bi_stream_fn(ctrl, sep);
     1318                else
     1319                    sep->se_builtin->bi_dgram_fn(ctrl, sep);
     1320                if (pid) /* we did vfork */
     1321                    _exit(EXIT_FAILURE);
     1322                maybe_close(accepted_fd);
     1323                continue; /* -> check next fd in fd set */
     1324            }
     1325#endif
     1326            /* child */
     1327            setsid();
     1328            /* "nowait" udp */
     1329            if (new_udp_fd >= 0) {
     1330                len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
     1331                /* peek at the packet and remember peer addr */
     1332                int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
     1333                    &lsa->u.sa, &lsa->len);
     1334                if (r < 0)
     1335                    goto do_exit1;
     1336                /* make this socket "connected" to peer addr:
     1337                 * only packets from this peer will be recv'ed,
     1338                 * and bare write()/send() will work on it */
     1339                connect(ctrl, &lsa->u.sa, lsa->len);
     1340                free(lsa);
     1341            }
     1342            /* prepare env and exec program */
     1343            pwd = getpwnam(sep->se_user);
     1344            if (pwd == NULL) {
     1345                bb_error_msg("%s: no such %s", sep->se_user, "user");
     1346                goto do_exit1;
     1347            }
     1348            if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
     1349                bb_error_msg("%s: no such %s", sep->se_group, "group");
     1350                goto do_exit1;
     1351            }
     1352            if (real_uid != 0 && real_uid != pwd->pw_uid) {
     1353                /* a user running private inetd */
     1354                bb_error_msg("non-root must run services as himself");
     1355                goto do_exit1;
     1356            }
     1357            if (pwd->pw_uid) {
     1358                if (sep->se_group)
     1359                    pwd->pw_gid = grp->gr_gid;
     1360                /* initgroups, setgid, setuid: */
     1361                change_identity(pwd);
     1362            } else if (sep->se_group) {
     1363                xsetgid(grp->gr_gid);
     1364                setgroups(1, &grp->gr_gid);
     1365            }
     1366            if (rlim_ofile.rlim_cur != rlim_ofile_cur)
     1367                if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
     1368                    bb_perror_msg("setrlimit");
     1369
     1370            /* closelog(); - WRONG. we are after vfork,
     1371             * this may confuse syslog() internal state.
     1372             * Let's hope libc sets syslog fd to CLOEXEC...
     1373             */
     1374            xmove_fd(ctrl, STDIN_FILENO);
     1375            xdup2(STDIN_FILENO, STDOUT_FILENO);
     1376            /* manpages of inetd I managed to find either say
     1377             * that stderr is also redirected to the network,
     1378             * or do not talk about redirection at all (!) */
     1379            if (!sep->se_wait) /* only for usual "tcp nowait" */
     1380                xdup2(STDIN_FILENO, STDERR_FILENO);
     1381            /* NB: among others, this loop closes listening sockets
     1382             * for nowait stream children */
     1383            for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
     1384                if (sep2->se_fd != ctrl)
     1385                    maybe_close(sep2->se_fd);
     1386            sigaction_set(SIGPIPE, &saved_pipe_handler);
     1387            restore_sigmask(&omask);
     1388            BB_EXECVP(sep->se_program, sep->se_argv);
     1389            bb_perror_msg("can't execute '%s'", sep->se_program);
     1390 do_exit1:
     1391            /* eat packet in udp case */
     1392            if (sep->se_socktype != SOCK_STREAM)
     1393                recv(0, line, LINE_SIZE, MSG_DONTWAIT);
     1394            _exit(EXIT_FAILURE);
    15111395        } /* for (sep = servtab...) */
    15121396    } /* for (;;) */
    15131397}
     1398
     1399#if !BB_MMU
     1400static const char *const cat_args[] = { "cat", NULL };
     1401#endif
    15141402
    15151403/*
    15161404 * Internet services provided internally by inetd:
    15171405 */
    1518 #define BUFSIZE 4096
    1519 
    1520 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    1521     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
    1522     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    1523 static int dg_badinput(struct sockaddr_in *dg_sin)
    1524 {
    1525     if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
    1526         return 1;
    1527     if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))
    1528         return 1;
    1529     /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
    1530     return 0;
    1531 }
    1532 #endif
    1533 
    15341406#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    1535 /* Echo service -- echo data back */
     1407/* Echo service -- echo data back. */
    15361408/* ARGSUSED */
    1537 static void
    1538 echo_stream(int s, servtab_t *sep)
    1539 {
    1540     char buffer[BUFSIZE];
    1541     int i;
    1542 
    1543     inetd_setproctitle(sep->se_service, s);
     1409static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM)
     1410{
     1411#if BB_MMU
    15441412    while (1) {
    1545         i = read(s, buffer, sizeof(buffer));
    1546         if (i <= 0) break;
    1547         /* FIXME: this isnt correct - safe_write()? */
    1548         if (write(s, buffer, i) <= 0) break;
    1549     }
    1550     exit(0);
    1551 }
    1552 
    1553 /* Echo service -- echo data back */
     1413        ssize_t sz = safe_read(s, line, LINE_SIZE);
     1414        if (sz <= 0)
     1415            break;
     1416        xwrite(s, line, sz);
     1417    }
     1418#else
     1419    /* We are after vfork here! */
     1420    /* move network socket to stdin/stdout */
     1421    xmove_fd(s, STDIN_FILENO);
     1422    xdup2(STDIN_FILENO, STDOUT_FILENO);
     1423    /* no error messages please... */
     1424    close(STDERR_FILENO);
     1425    xopen(bb_dev_null, O_WRONLY);
     1426    BB_EXECVP("cat", (char**)cat_args);
     1427    /* on failure we return to main, which does exit(EXIT_FAILURE) */
     1428#endif
     1429}
     1430static void FAST_FUNC echo_dg(int s, servtab_t *sep)
     1431{
     1432    enum { BUFSIZE = 12*1024 }; /* for jumbo sized packets! :) */
     1433    char *buf = xmalloc(BUFSIZE); /* too big for stack */
     1434    int sz;
     1435    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1436
     1437    lsa->len = sep->se_lsa->len;
     1438    /* dgram builtins are non-forking - DONT BLOCK! */
     1439    sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len);
     1440    if (sz > 0)
     1441        sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len);
     1442    free(buf);
     1443}
     1444#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
     1445
     1446
     1447#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     1448/* Discard service -- ignore data. */
    15541449/* ARGSUSED */
    1555 static void
    1556 echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1557 {
    1558     char buffer[BUFSIZE];
    1559     int i;
    1560     socklen_t size;
    1561     /* struct sockaddr_storage ss; */
    1562     struct sockaddr sa;
    1563 
    1564     size = sizeof(sa);
    1565     i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size);
    1566     if (i < 0)
    1567         return;
    1568     if (dg_badinput((struct sockaddr_in *) &sa))
    1569         return;
    1570     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
    1571 }
    1572 #endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
    1573 
    1574 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    1575 /* Discard service -- ignore data */
     1450static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM)
     1451{
     1452#if BB_MMU
     1453    while (safe_read(s, line, LINE_SIZE) > 0)
     1454        continue;
     1455#else
     1456    /* We are after vfork here! */
     1457    /* move network socket to stdin */
     1458    xmove_fd(s, STDIN_FILENO);
     1459    /* discard output */
     1460    close(STDOUT_FILENO);
     1461    xopen(bb_dev_null, O_WRONLY);
     1462    /* no error messages please... */
     1463    xdup2(STDOUT_FILENO, STDERR_FILENO);
     1464    BB_EXECVP("cat", (char**)cat_args);
     1465    /* on failure we return to main, which does exit(EXIT_FAILURE) */
     1466#endif
     1467}
    15761468/* ARGSUSED */
    1577 static void
    1578 discard_stream(int s, servtab_t *sep)
    1579 {
    1580     char buffer[BUFSIZE];
    1581 
    1582     inetd_setproctitle(sep->se_service, s);
    1583     while (1) {
    1584         errno = 0;
    1585         if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR)
    1586             exit(0);
    1587     }
    1588 }
    1589 
    1590 /* Discard service -- ignore data */
    1591 /* ARGSUSED */
    1592 static void
    1593 discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1594 {
    1595     char buffer[BUFSIZE];
    1596 
    1597     (void) read(s, buffer, sizeof(buffer));
     1469static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM)
     1470{
     1471    /* dgram builtins are non-forking - DONT BLOCK! */
     1472    recv(s, line, LINE_SIZE, MSG_DONTWAIT);
    15981473}
    15991474#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
     
    16021477#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    16031478#define LINESIZ 72
    1604 static char ring[128];
    1605 static char *endring;
    1606 
    1607 static void
    1608 initring(void)
     1479static void init_ring(void)
    16091480{
    16101481    int i;
    16111482
    1612     endring = ring;
    1613 
    1614     for (i = 0; i <= 128; ++i)
    1615         if (isprint(i))
    1616             *endring++ = i;
    1617 }
    1618 
    1619 /* Character generator */
     1483    end_ring = ring;
     1484    for (i = ' '; i < 127; i++)
     1485        *end_ring++ = i;
     1486}
     1487/* Character generator. MMU arches only. */
    16201488/* ARGSUSED */
    1621 static void
    1622 chargen_stream(int s, servtab_t *sep)
     1489static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM)
    16231490{
    16241491    char *rs;
     
    16261493    char text[LINESIZ + 2];
    16271494
    1628     inetd_setproctitle(sep->se_service, s);
    1629 
    1630     if (!endring) {
    1631         initring();
     1495    if (!end_ring) {
     1496        init_ring();
    16321497        rs = ring;
    16331498    }
     
    16371502    rs = ring;
    16381503    for (;;) {
    1639         len = endring - rs;
     1504        len = end_ring - rs;
    16401505        if (len >= LINESIZ)
    16411506            memmove(text, rs, LINESIZ);
     
    16441509            memmove(text + len, ring, LINESIZ - len);
    16451510        }
    1646         if (++rs == endring)
     1511        if (++rs == end_ring)
    16471512            rs = ring;
    1648         if (write(s, text, sizeof(text)) != sizeof(text))
    1649             break;
    1650     }
    1651     exit(0);
    1652 }
    1653 
    1654 /* Character generator */
     1513        xwrite(s, text, sizeof(text));
     1514    }
     1515}
    16551516/* ARGSUSED */
    1656 static void
    1657 chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1658 {
    1659     /* struct sockaddr_storage ss; */
    1660     struct sockaddr sa;
    1661     static char *rs;
     1517static void FAST_FUNC chargen_dg(int s, servtab_t *sep)
     1518{
    16621519    int len;
    16631520    char text[LINESIZ + 2];
    1664     socklen_t size;
    1665 
    1666     if (endring == 0) {
    1667         initring();
    1668         rs = ring;
    1669     }
    1670 
    1671     size = sizeof(sa);
    1672     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
     1521    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1522
     1523    /* Eat UDP packet which started it all */
     1524    /* dgram builtins are non-forking - DONT BLOCK! */
     1525    lsa->len = sep->se_lsa->len;
     1526    if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
    16731527        return;
    1674     if (dg_badinput((struct sockaddr_in *) &sa))
    1675         return;
    1676 
    1677     if ((len = endring - rs) >= LINESIZ)
    1678         memmove(text, rs, LINESIZ);
     1528
     1529    if (!end_ring) {
     1530        init_ring();
     1531        ring_pos = ring;
     1532    }
     1533
     1534    len = end_ring - ring_pos;
     1535    if (len >= LINESIZ)
     1536        memmove(text, ring_pos, LINESIZ);
    16791537    else {
    1680         memmove(text, rs, len);
     1538        memmove(text, ring_pos, len);
    16811539        memmove(text + len, ring, LINESIZ - len);
    16821540    }
    1683     if (++rs == endring)
    1684         rs = ring;
     1541    if (++ring_pos == end_ring)
     1542        ring_pos = ring;
    16851543    text[LINESIZ] = '\r';
    16861544    text[LINESIZ + 1] = '\n';
    1687     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
     1545    sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
    16881546}
    16891547#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
     
    16981556 * some seventy years Bell Labs was asleep.
    16991557 */
    1700 
    1701 static unsigned machtime(void)
     1558static uint32_t machtime(void)
    17021559{
    17031560    struct timeval tv;
    17041561
    1705     if (gettimeofday(&tv, NULL) < 0) {
    1706         fprintf(stderr, "Unable to get time of day\n");
    1707         return 0L;
    1708     }
    1709     return htonl((unsigned) tv.tv_sec + 2208988800UL);
    1710 }
    1711 
     1562    gettimeofday(&tv, NULL);
     1563    return htonl((uint32_t)(tv.tv_sec + 2208988800));
     1564}
    17121565/* ARGSUSED */
    1713 static void
    1714 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1715 {
    1716     unsigned result;
     1566static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
     1567{
     1568    uint32_t result;
    17171569
    17181570    result = machtime();
    1719     (void) write(s, (char *) &result, sizeof(result));
    1720 }
    1721 
    1722 /* ARGSUSED */
    1723 static void
    1724 machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1725 {
    1726     unsigned result;
    1727     /* struct sockaddr_storage ss; */
    1728     struct sockaddr sa;
    1729     struct sockaddr_in *dg_sin;
    1730     socklen_t size;
    1731 
    1732     size = sizeof(sa);
    1733     if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)
     1571    full_write(s, &result, sizeof(result));
     1572}
     1573static void FAST_FUNC machtime_dg(int s, servtab_t *sep)
     1574{
     1575    uint32_t result;
     1576    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1577
     1578    lsa->len = sep->se_lsa->len;
     1579    if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
    17341580        return;
    1735     /* if (dg_badinput((struct sockaddr *)&ss)) */
    1736     dg_sin = (struct sockaddr_in *) &sa;
    1737     if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
    1738             ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)
    1739         return;
     1581
    17401582    result = machtime();
    1741     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
     1583    sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len);
    17421584}
    17431585#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
     
    17471589/* Return human-readable time of day */
    17481590/* ARGSUSED */
    1749 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1750 {
    1751     char buffer[32];
     1591static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM)
     1592{
    17521593    time_t t;
    17531594
    17541595    t = time(NULL);
    1755 
    1756 // fdprintf instead?
    1757     (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
    1758     (void) write(s, buffer, strlen(buffer));
    1759 }
    1760 
    1761 /* Return human-readable time of day */
    1762 /* ARGSUSED */
    1763 void
    1764 daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1765 {
    1766     char buffer[256];
     1596    fdprintf(s, "%.24s\r\n", ctime(&t));
     1597}
     1598static void FAST_FUNC daytime_dg(int s, servtab_t *sep)
     1599{
    17671600    time_t t;
    1768     /* struct sockaddr_storage ss; */
    1769     struct sockaddr sa;
    1770     socklen_t size;
     1601    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1602
     1603    lsa->len = sep->se_lsa->len;
     1604    if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
     1605        return;
    17711606
    17721607    t = time(NULL);
    1773 
    1774     size = sizeof(sa);
    1775     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
    1776         return;
    1777     if (dg_badinput((struct sockaddr_in *) &sa))
    1778         return;
    1779     (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
    1780     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
     1608    sprintf(line, "%.24s\r\n", ctime(&t));
     1609    sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len);
    17811610}
    17821611#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
Note: See TracChangeset for help on using the changeset viewer.