Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (13 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

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

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*      $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $    */
    23/*      $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $      */
     
    2324 *    without specific prior written permission.
    2425 *
    25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
    2627 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    2728 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     
    3637 */
    3738
    38 /*
    39  * Inetd - Internet super-server
     39/* Inetd - Internet super-server
    4040 *
    4141 * This program invokes all internet services as needed.
     
    5050 * on file descriptor 0.  Datagram servers may either connect
    5151 * to their peer, freeing up the original socket for inetd
    52  * to receive further messages on, or ``take over the socket'',
     52 * to receive further messages on, or "take over the socket",
    5353 * 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''.
     54 * out.  The first type of server is said to be "multi-threaded";
     55 * the second type of server "single-threaded".
    5656 *
    5757 * Inetd uses a configuration file which is read at startup
    5858 * and, possibly, at some later time in response to a hangup signal.
    59  * The configuration file is ``free format'' with fields given in the
     59 * The configuration file is "free format" with fields given in the
    6060 * order shown below.  Continuation lines for an entry must begin with
    6161 * a space or tab.  All fields must be present in each entry.
     
    105105 */
    106106
    107 /*
    108  * Here's the scoop concerning the user[.:]group feature:
     107/* inetd rules for passing file descriptors to children
     108 * (http://www.freebsd.org/cgi/man.cgi?query=inetd):
     109 *
     110 * The wait/nowait entry specifies whether the server that is invoked by
     111 * inetd will take over the socket associated with the service access point,
     112 * and thus whether inetd should wait for the server to exit before listen-
     113 * ing for new service requests.  Datagram servers must use "wait", as
     114 * they are always invoked with the original datagram socket bound to the
     115 * specified service address.  These servers must read at least one datagram
     116 * from the socket before exiting.  If a datagram server connects to its
     117 * peer, freeing the socket so inetd can receive further messages on the
     118 * socket, it is said to be a "multi-threaded" server; it should read one
     119 * datagram from the socket and create a new socket connected to the peer.
     120 * It should fork, and the parent should then exit to allow inetd to check
     121 * for new service requests to spawn new servers.  Datagram servers which
     122 * 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)
     124 * utilities are both examples of the latter type of datagram server.  The
     125 * tftpd(8) utility is an example of a multi-threaded datagram server.
     126 *
     127 * Servers using stream sockets generally are multi-threaded and use the
     128 * "nowait" entry. Connection requests for these services are accepted by
     129 * inetd, and the server is given only the newly-accepted socket connected
     130 * to a client of the service.  Most stream-based services operate in this
     131 * manner.  Stream-based servers that use "wait" are started with the lis-
     132 * tening service socket, and must accept at least one connection request
     133 * before exiting.  Such a server would normally accept and process incoming
     134 * connection requests until a timeout.
     135 */
     136
     137/* Here's the scoop concerning the user[.:]group feature:
    109138 *
    110139 * 1) set-group-option off.
     
    125154 *                      initgroups(name, specified group)
    126155 *                      setuid()
    127  *
    128156 */
    129157
    130 #include <sys/param.h>
    131 #include <sys/stat.h>
    132 #include <sys/ioctl.h>
    133 #include <sys/socket.h>
     158#include "libbb.h"
     159#include <syslog.h>
    134160#include <sys/un.h>
    135 #include <sys/file.h>
    136 #include <sys/wait.h>
    137 #include <sys/resource.h>
    138 
    139 
    140 #include <netinet/in.h>
    141 #include <arpa/inet.h>
    142 
    143 #include <errno.h>
    144 #include <signal.h>
    145 #include <netdb.h>
    146 #include <syslog.h>
    147 #include <stdio.h>
    148 #include <stdlib.h>
    149 #include <unistd.h>
    150 #include <string.h>
    151 #include <ctype.h>
    152 #include <time.h>
    153 
    154 #include "busybox.h"
    155 
    156 //#define CONFIG_FEATURE_INETD_RPC
    157 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    158 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    159 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    160 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    161 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    162 //#define CONFIG_FEATURE_IPV6
    163 
    164 #ifdef CONFIG_FEATURE_INETD_RPC
     161
     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
     169
     170#if ENABLE_FEATURE_INETD_RPC
    165171#include <rpc/rpc.h>
    166172#include <rpc/pmap_clnt.h>
    167173#endif
    168174
    169 #define _PATH_INETDCONF "/etc/inetd.conf"
     175extern char **environ;
     176
     177
    170178#define _PATH_INETDPID  "/var/run/inetd.pid"
    171 
    172 
    173 #define TOOMANY         0               /* don't start more than TOOMANY */
    174179
    175180#define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
     
    185190
    186191/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
    187 #define FD_MARGIN       (8)
     192#define FD_MARGIN       8
    188193static rlim_t rlim_ofile_cur = OPEN_MAX;
    189194static struct rlimit rlim_ofile;
     
    191196
    192197/* Check unsupporting builtin */
    193 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    194     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    195     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
    196     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
    197     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     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
    198203# define INETD_FEATURE_ENABLED
    199204#endif
    200205
    201 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    202     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    203     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     206#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     207    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
     208    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    204209# define INETD_SETPROCTITLE
    205210#endif
    206211
    207 typedef struct servtab
    208 {
    209   char *se_hostaddr;                    /* host address to listen on */
    210   char *se_service;                     /* name of service */
    211   int se_socktype;                      /* type of socket to use */
    212   int se_family;                        /* address family */
    213   char *se_proto;                       /* protocol used */
    214 #ifdef CONFIG_FEATURE_INETD_RPC
    215   int se_rpcprog;                       /* rpc program number */
    216   int se_rpcversl;                      /* rpc program lowest version */
    217   int se_rpcversh;                      /* rpc program highest version */
     212typedef 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 */
     218#if ENABLE_FEATURE_INETD_RPC
     219    int se_rpcprog;                       /* rpc program number */
     220    int se_rpcversl;                      /* rpc program lowest version */
     221    int se_rpcversh;                      /* rpc program highest version */
    218222#define isrpcservice(sep)       ((sep)->se_rpcversl != 0)
    219223#else
    220224#define isrpcservice(sep)       0
    221225#endif
    222   pid_t se_wait;                        /* single threaded server */
    223   short se_checked;                     /* looked at during merge */
    224   char *se_user;                        /* user name to run as */
    225   char *se_group;                       /* group name to run as */
     226    pid_t se_wait;                        /* single threaded server */
     227    short se_checked;                     /* looked at during merge */
     228    char *se_user;                        /* user name to run as */
     229    char *se_group;                       /* group name to run as */
    226230#ifdef INETD_FEATURE_ENABLED
    227   const struct builtin *se_bi;                 /* if built-in, description */
    228 #endif
    229   char *se_server;                      /* server program */
     231    const struct builtin *se_bi;          /* if built-in, description */
     232#endif
     233    char *se_server;                      /* server program */
    230234#define MAXARGV 20
    231   char *se_argv[MAXARGV + 1];           /* program arguments */
    232   int se_fd;                            /* open descriptor */
    233   union
    234   {
    235     struct sockaddr se_un_ctrladdr;
    236     struct sockaddr_in se_un_ctrladdr_in;
    237 #ifdef CONFIG_FEATURE_IPV6
    238     struct sockaddr_in6 se_un_ctrladdr_in6;
    239 #endif
    240     struct sockaddr_un se_un_ctrladdr_un;
    241   } se_un;                              /* bound address */
     235    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 */
    242245#define se_ctrladdr     se_un.se_un_ctrladdr
    243246#define se_ctrladdr_in  se_un.se_un_ctrladdr_in
    244247#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
    245248#define se_ctrladdr_un  se_un.se_un_ctrladdr_un
    246   int se_ctrladdr_size;
    247   int se_max;                           /* max # of instances of this service */
    248   int se_count;                         /* number started since se_time */
    249   struct timeval se_time;               /* start of se_count */
    250   struct servtab *se_next;
     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;
    251254} servtab_t;
    252255
     
    254257
    255258#ifdef INETD_FEATURE_ENABLED
    256 struct builtin
    257 {
    258   const char *bi_service;               /* internally provided service name */
    259   int bi_socktype;                      /* type of socket supported */
    260   short bi_fork;                        /* 1 if should fork before call */
    261   short bi_wait;                        /* 1 if should wait for child */
    262   void (*bi_fn) (int, servtab_t *);
     259struct 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 *);
    263265};
    264266
     267        /* Echo received data */
     268#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     269static void echo_stream(int, servtab_t *);
     270static void echo_dg(int, servtab_t *);
     271#endif
     272        /* Internet /dev/null */
     273#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     274static void discard_stream(int, servtab_t *);
     275static void discard_dg(int, servtab_t *);
     276#endif
     277        /* Return 32 bit time since 1900 */
     278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     279static void machtime_stream(int, servtab_t *);
     280static void machtime_dg(int, servtab_t *);
     281#endif
     282        /* Return human-readable time */
     283#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     284static void daytime_stream(int, servtab_t *);
     285static void daytime_dg(int, servtab_t *);
     286#endif
     287        /* Familiar character generator */
     288#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     289static void chargen_stream(int, servtab_t *);
     290static void chargen_dg(int, servtab_t *);
     291#endif
     292
     293static const struct builtin builtins[] = {
     294#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    265295    /* Echo received data */
    266 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    267 static void echo_stream (int, servtab_t *);
    268 static void echo_dg (int, servtab_t *);
    269 #endif
     296    {"echo", SOCK_STREAM, 1, 0, echo_stream,},
     297    {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
     298#endif
     299#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    270300    /* Internet /dev/null */
    271 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    272 static void discard_stream (int, servtab_t *);
    273 static void discard_dg (int, servtab_t *);
    274 #endif
     301    {"discard", SOCK_STREAM, 1, 0, discard_stream,},
     302    {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
     303#endif
     304#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    275305    /* Return 32 bit time since 1900 */
    276 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    277 static void machtime_stream (int, servtab_t *);
    278 static void machtime_dg (int, servtab_t *);
    279 #endif
     306    {"time", SOCK_STREAM, 0, 0, machtime_stream,},
     307    {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
     308#endif
     309#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    280310    /* Return human-readable time */
    281 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    282 static void daytime_stream (int, servtab_t *);
    283 static void daytime_dg (int, servtab_t *);
    284 #endif
     311    {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
     312    {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
     313#endif
     314#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    285315    /* Familiar character generator */
    286 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    287 static void chargen_stream (int, servtab_t *);
    288 static void chargen_dg (int, servtab_t *);
    289 #endif
    290 
    291 static const struct builtin builtins[] = {
    292 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    293   /* Echo received data */
    294   {"echo", SOCK_STREAM, 1, 0, echo_stream,},
    295   {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
    296 #endif
    297 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    298   /* Internet /dev/null */
    299   {"discard", SOCK_STREAM, 1, 0, discard_stream,},
    300   {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
    301 #endif
    302 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    303   /* Return 32 bit time since 1900 */
    304   {"time", SOCK_STREAM, 0, 0, machtime_stream,},
    305   {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
    306 #endif
    307 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    308   /* Return human-readable time */
    309   {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
    310   {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
    311 #endif
    312 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    313   /* Familiar character generator */
    314   {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
    315   {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
    316 #endif
    317   {NULL, 0, 0, 0, NULL}
     316    {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
     317    {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
     318#endif
     319    {NULL, 0, 0, 0, NULL}
    318320};
    319321#endif /* INETD_FEATURE_ENABLED */
     
    322324static int nsock, maxsock;
    323325static fd_set allsock;
    324 static int toomany = TOOMANY;
     326static int toomany;
    325327static int timingout;
    326328static struct servent *sp;
    327329static uid_t uid;
    328330
    329 static char *CONFIG = _PATH_INETDCONF;
     331static const char *config_filename = "/etc/inetd.conf";
    330332
    331333static FILE *fconfig;
    332 static char line[1024];
    333334static char *defhost;
    334335
    335 static char *newstr (char *cp)
    336 {
    337   if ((cp = strdup (cp ? cp : "")))
    338     return (cp);
    339   syslog (LOG_ERR, "strdup: %m");
    340   exit (1);
    341 }
    342 
    343 static int setconfig (void)
    344 {
    345   free (defhost);
    346   defhost = newstr ("*");
    347   if (fconfig != NULL) {
    348     fseek (fconfig, 0L, SEEK_SET);
    349     return (1);
    350   }
    351   fconfig = fopen (CONFIG, "r");
    352   return (fconfig != NULL);
    353 }
    354 
    355 static void endconfig (void)
    356 {
    357   if (fconfig) {
    358     (void) fclose (fconfig);
    359     fconfig = NULL;
    360   }
    361   free (defhost);
    362   defhost = 0;
    363 }
    364 
    365 #ifdef CONFIG_FEATURE_INETD_RPC
    366 static void register_rpc (servtab_t *sep)
    367 {
    368   int n;
    369   struct sockaddr_in ir_sin;
    370   struct protoent *pp;
    371   socklen_t size;
    372 
    373   if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) {
    374     syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto);
    375     return;
    376   }
    377   size = sizeof ir_sin;
    378   if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
    379     syslog (LOG_ERR, "%s/%s: getsockname: %m",
    380             sep->se_service, sep->se_proto);
    381     return;
    382   }
    383 
    384   for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
    385     (void) pmap_unset (sep->se_rpcprog, n);
    386     if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)))
    387       syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
    388               sep->se_service, sep->se_proto,
    389               sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port));
    390   }
    391 }
    392 
    393 static void unregister_rpc (servtab_t *sep)
    394 {
    395   int n;
    396 
    397   for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
    398     if (!pmap_unset (sep->se_rpcprog, n))
    399       syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n);
    400   }
    401 }
    402 #endif /* CONFIG_FEATURE_INETD_RPC */
    403 
    404 static void freeconfig (servtab_t *cp)
    405 {
    406   int i;
    407 
    408   free (cp->se_hostaddr);
    409   free (cp->se_service);
    410   free (cp->se_proto);
    411   free (cp->se_user);
    412   free (cp->se_group);
    413   free (cp->se_server);
    414   for (i = 0; i < MAXARGV; i++)
    415     free (cp->se_argv[i]);
    416 }
    417 
    418 static int bump_nofile (void)
     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 */
     340static char *xxstrdup(char *cp)
     341{
     342    return xstrdup(cp ? cp : "");
     343}
     344
     345static 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
     357static void endconfig(void)
     358{
     359    if (fconfig) {
     360        (void) fclose(fconfig);
     361        fconfig = NULL;
     362    }
     363    free(defhost);
     364    defhost = 0;
     365}
     366
     367#if ENABLE_FEATURE_INETD_RPC
     368static void register_rpc(servtab_t *sep)
     369{
     370    int n;
     371    struct sockaddr_in ir_sin;
     372    struct protoent *pp;
     373    socklen_t size;
     374
     375    if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) {
     376        bb_perror_msg("%s: getproto", sep->se_proto);
     377        return;
     378    }
     379    size = sizeof ir_sin;
     380    if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
     381        bb_perror_msg("%s/%s: getsockname",
     382                sep->se_service, sep->se_proto);
     383        return;
     384    }
     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
     395static 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
     406static void freeconfig(servtab_t *cp)
     407{
     408    int i;
     409
     410    free(cp->se_hostaddr);
     411    free(cp->se_service);
     412    free(cp->se_proto);
     413    free(cp->se_user);
     414    free(cp->se_group);
     415    free(cp->se_server);
     416    for (i = 0; i < MAXARGV; i++)
     417        free(cp->se_argv[i]);
     418}
     419
     420static int bump_nofile(void)
    419421{
    420422#define FD_CHUNK        32
    421423
    422   struct rlimit rl;
    423 
    424   if (getrlimit (RLIMIT_NOFILE, &rl) < 0) {
    425     syslog (LOG_ERR, "getrlimit: %m");
    426     return -1;
    427   }
    428   rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK);
    429   rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
    430   if (rl.rlim_cur <= rlim_ofile_cur) {
    431     syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d",
    432             (int) rl.rlim_cur);
    433     return -1;
    434   }
    435 
    436   if (setrlimit (RLIMIT_NOFILE, &rl) < 0) {
    437     syslog (LOG_ERR, "setrlimit: %m");
    438     return -1;
    439   }
    440 
    441   rlim_ofile_cur = rl.rlim_cur;
    442   return 0;
    443 }
    444 
    445 static void setup (servtab_t *sep)
    446 {
    447   int on = 1;
    448   int r;
    449 
    450   if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) {
    451     syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto);
    452     return;
    453   }
    454 #define turnon(fd, opt) \
    455 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
    456   if (turnon (sep->se_fd, SO_REUSEADDR) < 0)
    457     syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
    458 #undef turnon
    459 
    460 #ifdef CONFIG_FEATURE_INETD_RPC
    461   if (isrpcservice (sep)) {
    462     struct passwd *pwd;
     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
     447static 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
     511static 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
     526static 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
     567static servtab_t *new_servtab(void)
     568{
     569    return xmalloc(sizeof(servtab_t));
     570}
     571
     572static servtab_t *dupconfig(servtab_t *sep)
     573{
     574    servtab_t *newtab;
     575    int argc;
     576
     577    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
     596    for (argc = 0; argc <= MAXARGV; argc++)
     597        newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]);
     598    newtab->se_max = sep->se_max;
     599
     600    return newtab;
     601}
     602
     603static servtab_t *getconfigent(void)
     604{
     605    servtab_t *sep;
     606    int argc;
     607    char *cp, *arg;
     608    char *hostdelim;
     609    servtab_t *nsep;
     610    servtab_t *psep;
     611
     612    sep = new_servtab();
     613
     614    /* memset(sep, 0, sizeof *sep); */
     615 more:
     616    /* freeconfig(sep); */
     617
     618    while ((cp = nextline()) && *cp == '#') /* skip comment line */;
     619    if (cp == NULL) {
     620        /* free(sep); */
     621        return NULL;
     622    }
     623
     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. */
     632    hostdelim = strrchr(arg, ':');
     633    if (hostdelim) {
     634        *hostdelim = '\0';
     635        sep->se_hostaddr = xstrdup(arg);
     636        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            }
     648        }
     649    } 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) {
     671        sep->se_family = AF_UNIX;
     672    } else {
     673        sep->se_family = AF_INET;
     674        if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
     675#if ENABLE_FEATURE_IPV6
     676            sep->se_family = AF_INET6;
     677#else
     678            bb_error_msg("%s: IPV6 not supported", sep->se_proto);
     679#endif
     680        if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
     681#if ENABLE_FEATURE_INETD_RPC
     682            char *p, *ccp;
     683            long l;
     684
     685            p = strchr(sep->se_service, '/');
     686            if (p == 0) {
     687                bb_error_msg("%s: no rpc version", sep->se_service);
     688                goto more;
     689            }
     690            *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;
     696            }
     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;
     706#else
     707            bb_error_msg("%s: rpc services not supported", sep->se_service);
     708#endif
     709        }
     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));
     727    arg = strchr(sep->se_user, '.');
     728    if (arg == NULL)
     729        arg = strchr(sep->se_user, ':');
     730    if (arg) {
     731        *arg++ = '\0';
     732        sep->se_group = xstrdup(arg);
     733    }
     734    /* if ((arg = skip(&cp, 1)) == NULL) */
     735    /* goto more; */
     736
     737    sep->se_server = xxstrdup(skip(&cp));
     738    if (strcmp(sep->se_server, "internal") == 0) {
     739#ifdef INETD_FEATURE_ENABLED
     740        const struct builtin *bi;
     741
     742        for (bi = builtins; bi->bi_service; bi++)
     743            if (bi->bi_socktype == sep->se_socktype &&
     744                    strcmp(bi->bi_service, sep->se_service) == 0)
     745                break;
     746        if (bi->bi_service == 0) {
     747            bb_error_msg("internal service %s unknown", sep->se_service);
     748            goto more;
     749        }
     750        sep->se_bi = bi;
     751        sep->se_wait = bi->bi_wait;
     752#else
     753        bb_perror_msg("internal service %s unknown", sep->se_service);
     754        goto more;
     755#endif
     756    }
     757#ifdef INETD_FEATURE_ENABLED
     758        else
     759        sep->se_bi = NULL;
     760#endif
     761    argc = 0;
     762    for (arg = skip(&cp); cp; arg = skip(&cp)) {
     763        if (argc < MAXARGV)
     764            sep->se_argv[argc++] = xxstrdup(arg);
     765    }
     766    while (argc <= MAXARGV)
     767        sep->se_argv[argc++] = NULL;
    463768
    464769    /*
    465      * for RPC services, attempt to use a reserved port
    466      * if they are going to be running as root.
    467      *
    468      * Also, zero out the port for all RPC services; let bind()
    469      * find one.
     770     * Now that we've processed the entire line, check if the hostname
     771     * specifier was a comma separated list of hostnames. If so
     772     * we'll make new entries for each address.
    470773     */
    471     sep->se_ctrladdr_in.sin_port = 0;
    472     if (sep->se_user && (pwd = getpwnam (sep->se_user)) &&
    473         pwd->pw_uid == 0 && uid == 0)
    474       r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in);
    475     else {
    476       r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
    477       if (r == 0) {
    478         socklen_t len = sep->se_ctrladdr_size;
    479         int saveerrno = errno;
    480 
    481         /* update se_ctrladdr_in.sin_port */
    482         r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len);
    483         if (r <= 0)
    484           errno = saveerrno;
    485       }
    486     }
    487   } else
    488 #endif
    489     r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
    490   if (r < 0) {
    491     syslog (LOG_ERR, "%s/%s (%d): bind: %m",
    492             sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
    493     close (sep->se_fd);
     774    while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) {
     775        nsep = dupconfig(sep);
     776
     777        /*
     778         * NULL terminate the hostname field of the existing entry,
     779         * and make a dup for the new entry.
     780         */
     781        *hostdelim++ = '\0';
     782        nsep->se_hostaddr = xstrdup(hostdelim);
     783
     784        nsep->se_next = sep->se_next;
     785        sep->se_next = nsep;
     786    }
     787
     788    nsep = sep;
     789    while (nsep != NULL) {
     790        nsep->se_checked = 1;
     791        if (nsep->se_family == AF_INET) {
     792            if (LONE_CHAR(nsep->se_hostaddr, '*'))
     793                nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
     794            else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
     795                struct hostent *hp;
     796
     797                hp = gethostbyname(nsep->se_hostaddr);
     798                if (hp == 0) {
     799                    bb_error_msg("%s: unknown host", nsep->se_hostaddr);
     800                    nsep->se_checked = 0;
     801                    goto skip;
     802                } else if (hp->h_addrtype != AF_INET) {
     803                    bb_error_msg("%s: address isn't an Internet "
     804                                  "address", nsep->se_hostaddr);
     805                    nsep->se_checked = 0;
     806                    goto skip;
     807                } else {
     808                    int i = 1;
     809
     810                    memmove(&nsep->se_ctrladdr_in.sin_addr,
     811                                   hp->h_addr_list[0], sizeof(struct in_addr));
     812                    while (hp->h_addr_list[i] != NULL) {
     813                        psep = dupconfig(nsep);
     814                        psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
     815                        psep->se_checked = 1;
     816                        memmove(&psep->se_ctrladdr_in.sin_addr,
     817                                     hp->h_addr_list[i], sizeof(struct in_addr));
     818                        psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
     819                        i++;
     820                        /* Prepend to list, don't want to look up */
     821                        /* its hostname again. */
     822                        psep->se_next = sep;
     823                        sep = psep;
     824                    }
     825                }
     826            }
     827        }
     828/* XXX BUG?: is this skip: label supposed to remain? */
     829 skip:
     830        nsep = nsep->se_next;
     831    }
     832
     833    /*
     834     * Finally, free any entries which failed the gethostbyname
     835     * check.
     836     */
     837    psep = NULL;
     838    nsep = sep;
     839    while (nsep != NULL) {
     840        servtab_t *tsep;
     841
     842        if (nsep->se_checked == 0) {
     843            tsep = nsep;
     844            if (psep == NULL) {
     845                sep = nsep->se_next;
     846                nsep = sep;
     847            } else {
     848                nsep = nsep->se_next;
     849                psep->se_next = nsep;
     850            }
     851            freeconfig(tsep);
     852        } else {
     853            nsep->se_checked = 0;
     854            psep = nsep;
     855            nsep = nsep->se_next;
     856        }
     857    }
     858
     859    return sep;
     860}
     861
     862#define Block_Using_Signals(m) do { \
     863    sigemptyset(&m); \
     864    sigaddset(&m, SIGCHLD); \
     865    sigaddset(&m, SIGHUP); \
     866    sigaddset(&m, SIGALRM); \
     867    sigprocmask(SIG_BLOCK, &m, NULL); \
     868} while (0)
     869
     870static servtab_t *enter(servtab_t *cp)
     871{
     872    servtab_t *sep;
     873    sigset_t omask;
     874
     875    sep = new_servtab();
     876    *sep = *cp;
    494877    sep->se_fd = -1;
    495     if (!timingout) {
    496       timingout = 1;
    497       alarm (RETRYTIME);
    498     }
    499     return;
    500   }
    501   if (sep->se_socktype == SOCK_STREAM)
    502     listen (sep->se_fd, global_queuelen);
    503 
    504   FD_SET (sep->se_fd, &allsock);
    505   nsock++;
    506   if (sep->se_fd > maxsock) {
    507     maxsock = sep->se_fd;
    508     if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
    509       bump_nofile ();
    510   }
    511 }
    512 
    513 static char *nextline (void)
    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     /* syslog(LOG_ERR, "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     (void) ungetc (c, fconfig);
    546     if (c == ' ' || c == '\t')
    547       if ((cp = nextline ()))
    548         goto again;
    549     *cpp = NULL;
    550     /* goto erp; */
    551     return (NULL);
    552   }
    553   start = cp;
    554   while (*cp && *cp != ' ' && *cp != '\t')
    555     cp++;
    556   if (*cp != '\0')
    557     *cp++ = '\0';
    558   /* if ((*cpp = cp) == NULL) */
    559   /* goto erp; */
    560 
    561   *cpp = cp;
    562   return (start);
    563 }
    564 
    565 static servtab_t *new_servtab(void)
    566 {
    567   servtab_t *sep;
    568 
    569   sep = (servtab_t *) malloc (sizeof (servtab_t));
    570   if (sep == NULL) {
    571     syslog (LOG_ERR, bb_msg_memory_exhausted);
    572     exit (1);
    573   }
    574   return sep;
    575 }
    576 
    577 static servtab_t *dupconfig (servtab_t *sep)
    578 {
    579   servtab_t *newtab;
    580   int argc;
    581 
    582   newtab = new_servtab();
    583   memset (newtab, 0, sizeof (servtab_t));
    584   newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL;
    585   newtab->se_socktype = sep->se_socktype;
    586   newtab->se_family = sep->se_family;
    587   newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL;
    588 #ifdef CONFIG_FEATURE_INETD_RPC
    589   newtab->se_rpcprog = sep->se_rpcprog;
    590   newtab->se_rpcversl = sep->se_rpcversl;
    591   newtab->se_rpcversh = sep->se_rpcversh;
    592 #endif
    593   newtab->se_wait = sep->se_wait;
    594   newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL;
    595   newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL;
     878#if ENABLE_FEATURE_INETD_RPC
     879    sep->se_rpcprog = -1;
     880#endif
     881    Block_Using_Signals(omask);
     882    sep->se_next = servtab;
     883    servtab = sep;
     884    sigprocmask(SIG_UNBLOCK, &omask, NULL);
     885    return sep;
     886}
     887
     888static int matchconf(servtab_t *old, servtab_t *new)
     889{
     890    if (strcmp(old->se_service, new->se_service) != 0)
     891        return 0;
     892
     893    if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
     894        return 0;
     895
     896    if (strcmp(old->se_proto, new->se_proto) != 0)
     897        return 0;
     898
     899    /*
     900     * If the new servtab is bound to a specific address, check that the
     901     * old servtab is bound to the same entry. If the new service is not
     902     * bound to a specific address then the check of se_hostaddr above
     903     * is sufficient.
     904     */
     905
     906    if (old->se_family == AF_INET && new->se_family == AF_INET &&
     907            memcmp(&old->se_ctrladdr_in.sin_addr,
     908                    &new->se_ctrladdr_in.sin_addr,
     909                    sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
     910        return 0;
     911
     912#if ENABLE_FEATURE_IPV6
     913    if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
     914            memcmp(&old->se_ctrladdr_in6.sin6_addr,
     915                    &new->se_ctrladdr_in6.sin6_addr,
     916                    sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
     917        return 0;
     918#endif
     919    return 1;
     920}
     921
     922static void config(int sig ATTRIBUTE_UNUSED)
     923{
     924    servtab_t *sep, *cp, **sepp;
     925    sigset_t omask;
     926    size_t n;
     927    char protoname[10];
     928
     929    if (!setconfig()) {
     930        bb_perror_msg("%s", config_filename);
     931        return;
     932    }
     933    for (sep = servtab; sep; sep = sep->se_next)
     934        sep->se_checked = 0;
     935    cp = getconfigent();
     936    while (cp != NULL) {
     937        for (sep = servtab; sep; sep = sep->se_next)
     938            if (matchconf(sep, cp))
     939                break;
     940
     941        if (sep != 0) {
     942            int i;
     943
     944#define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
     945
     946            Block_Using_Signals(omask);
     947            /*
     948             * sep->se_wait may be holding the pid of a daemon
     949             * that we're waiting for.  If so, don't overwrite
     950             * it unless the config file explicitly says don't
     951             * wait.
     952             */
     953            if (
    596954#ifdef INETD_FEATURE_ENABLED
    597   newtab->se_bi = sep->se_bi;
    598 #endif
    599   newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0;
    600 
    601   for (argc = 0; argc <= MAXARGV; argc++)
    602     newtab->se_argv[argc] = sep->se_argv[argc] ?
    603       newstr (sep->se_argv[argc]) : NULL;
    604   newtab->se_max = sep->se_max;
    605 
    606   return (newtab);
    607 }
    608 
    609 static servtab_t *getconfigent (void)
    610 {
    611   servtab_t *sep;
    612   int argc;
    613   char *cp, *arg;
    614   char *hostdelim;
    615   servtab_t *nsep;
    616   servtab_t *psep;
    617 
    618   sep = new_servtab();
    619 
    620   /* memset(sep, 0, sizeof *sep); */
    621 more:
    622   /* freeconfig(sep); */
    623 
    624   while ((cp = nextline ()) && *cp == '#');
    625   if (cp == NULL) {
    626     /* free(sep); */
    627     return (NULL);
    628   }
    629 
    630   memset ((char *) sep, 0, sizeof *sep);
    631   arg = skip (&cp);
    632   if (arg == NULL) {
    633     /* A blank line. */
    634     goto more;
    635   }
    636 
    637   /* Check for a host name. */
    638   hostdelim = strrchr (arg, ':');
    639   if (hostdelim) {
    640     *hostdelim = '\0';
    641     sep->se_hostaddr = newstr (arg);
    642     arg = hostdelim + 1;
     955                cp->se_bi == 0 &&
     956#endif
     957                (sep->se_wait == 1 || cp->se_wait == 0))
     958                sep->se_wait = cp->se_wait;
     959            SWAP(int, cp->se_max, sep->se_max);
     960            SWAP(char *, sep->se_user, cp->se_user);
     961            SWAP(char *, sep->se_group, cp->se_group);
     962            SWAP(char *, sep->se_server, cp->se_server);
     963            for (i = 0; i < MAXARGV; i++)
     964                SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
     965#undef SWAP
     966
     967#if ENABLE_FEATURE_INETD_RPC
     968            if (isrpcservice(sep))
     969                unregister_rpc(sep);
     970            sep->se_rpcversl = cp->se_rpcversl;
     971            sep->se_rpcversh = cp->se_rpcversh;
     972#endif
     973            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     974            freeconfig(cp);
     975        } else {
     976            sep = enter(cp);
     977        }
     978        sep->se_checked = 1;
     979
     980        switch (sep->se_family) {
     981        case AF_UNIX:
     982            if (sep->se_fd != -1)
     983                break;
     984            (void) unlink(sep->se_service);
     985            n = strlen(sep->se_service);
     986            if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
     987                n = sizeof sep->se_ctrladdr_un.sun_path - 1;
     988            safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
     989            sep->se_ctrladdr_un.sun_family = AF_UNIX;
     990            sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
     991            setup(sep);
     992            break;
     993        case AF_INET:
     994            sep->se_ctrladdr_in.sin_family = AF_INET;
     995            /* se_ctrladdr_in was set in getconfigent */
     996            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
     997
     998#if ENABLE_FEATURE_INETD_RPC
     999            if (isrpcservice(sep)) {
     1000                struct rpcent *rp;
     1001                // FIXME: atoi_or_else(str, 0) would be handy here
     1002                sep->se_rpcprog = atoi(sep->se_service);
     1003                if (sep->se_rpcprog == 0) {
     1004                    rp = getrpcbyname(sep->se_service);
     1005                    if (rp == 0) {
     1006                        bb_error_msg("%s: unknown rpc service", sep->se_service);
     1007                        goto serv_unknown;
     1008                    }
     1009                    sep->se_rpcprog = rp->r_number;
     1010                }
     1011                if (sep->se_fd == -1)
     1012                    setup(sep);
     1013                if (sep->se_fd != -1)
     1014                    register_rpc(sep);
     1015            } else
     1016#endif
     1017            {
     1018                uint16_t port = htons(atoi(sep->se_service));
     1019                // FIXME: atoi_or_else(str, 0) would be handy here
     1020                if (!port) {
     1021                     /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
     1022                    if (isdigit(protoname[strlen(protoname) - 1]))
     1023                        protoname[strlen(protoname) - 1] = '\0';
     1024                    sp = getservbyname(sep->se_service, protoname);
     1025                    if (sp == 0) {
     1026                        bb_error_msg("%s/%s: unknown service",
     1027                                sep->se_service, sep->se_proto);
     1028                        goto serv_unknown;
     1029                    }
     1030                    port = sp->s_port;
     1031                }
     1032                if (port != sep->se_ctrladdr_in.sin_port) {
     1033                    sep->se_ctrladdr_in.sin_port = port;
     1034                    if (sep->se_fd != -1) {
     1035                        FD_CLR(sep->se_fd, &allsock);
     1036                        nsock--;
     1037                        (void) close(sep->se_fd);
     1038                    }
     1039                    sep->se_fd = -1;
     1040                }
     1041                if (sep->se_fd == -1)
     1042                    setup(sep);
     1043            }
     1044            break;
     1045#if ENABLE_FEATURE_IPV6
     1046        case AF_INET6:
     1047            sep->se_ctrladdr_in6.sin6_family = AF_INET6;
     1048            /* se_ctrladdr_in was set in getconfigent */
     1049            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
     1050
     1051#if ENABLE_FEATURE_INETD_RPC
     1052            if (isrpcservice(sep)) {
     1053                struct rpcent *rp;
     1054
     1055                sep->se_rpcprog = atoi(sep->se_service);
     1056                if (sep->se_rpcprog == 0) {
     1057                    rp = getrpcbyname(sep->se_service);
     1058                    if (rp == 0) {
     1059                        bb_error_msg("%s: unknown rpc service", sep->se_service);
     1060                        goto serv_unknown;
     1061                    }
     1062                    sep->se_rpcprog = rp->r_number;
     1063                }
     1064                if (sep->se_fd == -1)
     1065                    setup(sep);
     1066                if (sep->se_fd != -1)
     1067                    register_rpc(sep);
     1068            } else
     1069#endif
     1070            {
     1071                uint16_t port = htons(atoi(sep->se_service));
     1072
     1073                if (!port) {
     1074                     /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
     1075                    if (isdigit(protoname[strlen(protoname) - 1]))
     1076                        protoname[strlen(protoname) - 1] = '\0';
     1077                    sp = getservbyname(sep->se_service, protoname);
     1078                    if (sp == 0) {
     1079                        bb_error_msg("%s/%s: unknown service",
     1080                                sep->se_service, sep->se_proto);
     1081                        goto serv_unknown;
     1082                    }
     1083                    port = sp->s_port;
     1084                }
     1085                if (port != sep->se_ctrladdr_in6.sin6_port) {
     1086                    sep->se_ctrladdr_in6.sin6_port = port;
     1087                    if (sep->se_fd != -1) {
     1088                        FD_CLR(sep->se_fd, &allsock);
     1089                        nsock--;
     1090                        (void) close(sep->se_fd);
     1091                    }
     1092                    sep->se_fd = -1;
     1093                }
     1094                if (sep->se_fd == -1)
     1095                    setup(sep);
     1096            }
     1097            break;
     1098#endif /* FEATURE_IPV6 */
     1099        }
     1100 serv_unknown:
     1101        if (cp->se_next != NULL) {
     1102            servtab_t *tmp = cp;
     1103
     1104            cp = cp->se_next;
     1105            free(tmp);
     1106        } else {
     1107            free(cp);
     1108            cp = getconfigent();
     1109        }
     1110    }
     1111    endconfig();
    6431112    /*
    644      * If the line is of the form `host:', then just change the
    645      * default host for the following lines.
     1113     * Purge anything not looked at above.
    6461114     */
    647     if (*arg == '\0') {
    648       arg = skip (&cp);
    649       if (cp == NULL) {
    650         free (defhost);
    651         defhost = sep->se_hostaddr;
    652         goto more;
    653       }
    654     }
    655   } else
    656     sep->se_hostaddr = newstr (defhost);
    657 
    658   sep->se_service = newstr (arg);
    659   arg = skip (&cp);
    660 
    661   if (strcmp (arg, "stream") == 0)
    662     sep->se_socktype = SOCK_STREAM;
    663   else if (strcmp (arg, "dgram") == 0)
    664     sep->se_socktype = SOCK_DGRAM;
    665   else if (strcmp (arg, "rdm") == 0)
    666     sep->se_socktype = SOCK_RDM;
    667   else if (strcmp (arg, "seqpacket") == 0)
    668     sep->se_socktype = SOCK_SEQPACKET;
    669   else if (strcmp (arg, "raw") == 0)
    670     sep->se_socktype = SOCK_RAW;
    671   else
    672     sep->se_socktype = -1;
    673 
    674   sep->se_proto = newstr (skip (&cp));
    675 
    676   if (strcmp (sep->se_proto, "unix") == 0) {
    677     sep->se_family = AF_UNIX;
    678   } else {
    679     sep->se_family = AF_INET;
    680     if (sep->se_proto[strlen (sep->se_proto) - 1] == '6')
    681 #ifdef CONFIG_FEATURE_IPV6
    682       sep->se_family = AF_INET6;
    683 #else
    684       syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto);
    685 #endif
    686     if (strncmp (sep->se_proto, "rpc/", 4) == 0) {
    687 #ifdef CONFIG_FEATURE_INETD_RPC
    688       char *p, *ccp;
    689       long l;
    690 
    691       p = strchr (sep->se_service, '/');
    692       if (p == 0) {
    693         syslog (LOG_ERR, "%s: no rpc version", sep->se_service);
    694         goto more;
    695       }
    696       *p++ = '\0';
    697       l = strtol (p, &ccp, 0);
    698       if (ccp == p || l < 0 || l > INT_MAX) {
    699       badafterall:
    700         syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p);
    701         goto more;
    702       }
    703       sep->se_rpcversl = sep->se_rpcversh = l;
    704       if (*ccp == '-') {
    705         p = ccp + 1;
    706         l = strtol (p, &ccp, 0);
    707         if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
    708           goto badafterall;
    709         sep->se_rpcversh = l;
    710       } else if (*ccp != '\0')
    711         goto badafterall;
    712 #else
    713     syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service);
    714 #endif
    715     }
    716   }
    717   arg = skip (&cp);
    718   if (arg == NULL)
    719     goto more;
    720 
    721   {
    722     char *s = strchr (arg, '.');
    723     if (s) {
    724       *s++ = '\0';
    725       sep->se_max = atoi (s);
    726     } else
    727       sep->se_max = toomany;
    728   }
    729   sep->se_wait = strcmp (arg, "wait") == 0;
    730   /* if ((arg = skip(&cp, 1)) == NULL) */
    731   /* goto more; */
    732   sep->se_user = newstr (skip (&cp));
    733   arg = strchr (sep->se_user, '.');
    734   if (arg == NULL)
    735     arg = strchr (sep->se_user, ':');
    736   if (arg) {
    737     *arg++ = '\0';
    738     sep->se_group = newstr (arg);
    739   }
    740   /* if ((arg = skip(&cp, 1)) == NULL) */
    741   /* goto more; */
    742 
    743   sep->se_server = newstr (skip (&cp));
    744   if (strcmp (sep->se_server, "internal") == 0) {
    745 #ifdef INETD_FEATURE_ENABLED
    746     const struct builtin *bi;
    747 
    748     for (bi = builtins; bi->bi_service; bi++)
    749       if (bi->bi_socktype == sep->se_socktype &&
    750           strcmp (bi->bi_service, sep->se_service) == 0)
    751         break;
    752     if (bi->bi_service == 0) {
    753       syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
    754       goto more;
    755     }
    756     sep->se_bi = bi;
    757     sep->se_wait = bi->bi_wait;
    758 #else
    759     syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
    760     goto more;
    761 #endif
    762   }
    763 #ifdef INETD_FEATURE_ENABLED
    764     else
    765     sep->se_bi = NULL;
    766 #endif
    767   argc = 0;
    768   for (arg = skip (&cp); cp; arg = skip (&cp)) {
    769     if (argc < MAXARGV)
    770       sep->se_argv[argc++] = newstr (arg);
    771   }
    772   while (argc <= MAXARGV)
    773     sep->se_argv[argc++] = NULL;
    774 
    775   /*
    776    * Now that we've processed the entire line, check if the hostname
    777    * specifier was a comma separated list of hostnames. If so
    778    * we'll make new entries for each address.
    779    */
    780   while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) {
    781     nsep = dupconfig (sep);
    782 
    783     /*
    784      * NULL terminate the hostname field of the existing entry,
    785      * and make a dup for the new entry.
    786      */
    787     *hostdelim++ = '\0';
    788     nsep->se_hostaddr = newstr (hostdelim);
    789 
    790     nsep->se_next = sep->se_next;
    791     sep->se_next = nsep;
    792   }
    793 
    794   nsep = sep;
    795   while (nsep != NULL) {
    796     nsep->se_checked = 1;
    797     if (nsep->se_family == AF_INET) {
    798       if (!strcmp (nsep->se_hostaddr, "*"))
    799         nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
    800       else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
    801         struct hostent *hp;
    802 
    803         hp = gethostbyname (nsep->se_hostaddr);
    804         if (hp == 0) {
    805           syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr);
    806           nsep->se_checked = 0;
    807           goto skip;
    808         } else if (hp->h_addrtype != AF_INET) {
    809           syslog (LOG_ERR,
    810                   "%s: address isn't an Internet "
    811                   "address", nsep->se_hostaddr);
    812           nsep->se_checked = 0;
    813           goto skip;
    814         } else {
    815           int i = 1;
    816 
    817           memmove (&nsep->se_ctrladdr_in.sin_addr,
    818                    hp->h_addr_list[0], sizeof (struct in_addr));
    819           while (hp->h_addr_list[i] != NULL) {
    820             psep = dupconfig (nsep);
    821             psep->se_hostaddr = newstr (nsep->se_hostaddr);
    822             psep->se_checked = 1;
    823             memmove (&psep->se_ctrladdr_in.sin_addr,
    824                      hp->h_addr_list[i], sizeof (struct in_addr));
    825             psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in);
    826             i++;
    827             /* Prepend to list, don't want to look up its */
    828             /* hostname again. */
    829             psep->se_next = sep;
    830             sep = psep;
    831           }
     1115    Block_Using_Signals(omask);
     1116    sepp = &servtab;
     1117    while ((sep = *sepp)) {
     1118        if (sep->se_checked) {
     1119            sepp = &sep->se_next;
     1120            continue;
    8321121        }
    833       }
    834     }
    835 /* XXX BUG?: is this skip: label supposed to remain? */
    836   skip:
    837     nsep = nsep->se_next;
    838   }
    839 
    840   /*
    841    * Finally, free any entries which failed the gethostbyname
    842    * check.
    843    */
    844   psep = NULL;
    845   nsep = sep;
    846   while (nsep != NULL) {
    847     servtab_t *tsep;
    848 
    849     if (nsep->se_checked == 0) {
    850       tsep = nsep;
    851       if (psep == NULL) {
    852         sep = nsep->se_next;
    853         nsep = sep;
    854       } else {
    855         nsep = nsep->se_next;
    856         psep->se_next = nsep;
    857       }
    858       freeconfig (tsep);
    859     } else {
    860       nsep->se_checked = 0;
    861       psep = nsep;
    862       nsep = nsep->se_next;
    863     }
    864   }
    865 
    866   return (sep);
    867 }
    868 
    869 #define Block_Using_Signals(m) do {     sigemptyset(&m); \
    870                     sigaddset(&m, SIGCHLD); \
    871                     sigaddset(&m, SIGHUP); \
    872                     sigaddset(&m, SIGALRM); \
    873                     sigprocmask(SIG_BLOCK, &m, NULL); \
    874                 } while(0)
    875 
    876 
    877 static servtab_t *enter (servtab_t *cp)
    878 {
    879   servtab_t *sep;
    880   sigset_t omask;
    881 
    882   sep = new_servtab();
    883   *sep = *cp;
    884   sep->se_fd = -1;
    885 #ifdef CONFIG_FEATURE_INETD_RPC
    886   sep->se_rpcprog = -1;
    887 #endif
    888   Block_Using_Signals(omask);
    889   sep->se_next = servtab;
    890   servtab = sep;
    891   sigprocmask(SIG_UNBLOCK, &omask, NULL);
    892   return (sep);
    893 }
    894 
    895 static int matchconf (servtab_t *old, servtab_t *new)
    896 {
    897   if (strcmp (old->se_service, new->se_service) != 0)
    898     return (0);
    899 
    900   if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0)
    901     return (0);
    902 
    903   if (strcmp (old->se_proto, new->se_proto) != 0)
    904     return (0);
    905 
    906   /*
    907    * If the new servtab is bound to a specific address, check that the
    908    * old servtab is bound to the same entry. If the new service is not
    909    * bound to a specific address then the check of se_hostaddr above
    910    * is sufficient.
    911    */
    912 
    913   if (old->se_family == AF_INET && new->se_family == AF_INET &&
    914       memcmp (&old->se_ctrladdr_in.sin_addr,
    915               &new->se_ctrladdr_in.sin_addr,
    916               sizeof (new->se_ctrladdr_in.sin_addr)) != 0)
    917     return (0);
    918 
    919 #ifdef CONFIG_FEATURE_IPV6
    920   if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
    921       memcmp (&old->se_ctrladdr_in6.sin6_addr,
    922               &new->se_ctrladdr_in6.sin6_addr,
    923               sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0)
    924     return (0);
    925 #endif
    926   return (1);
    927 }
    928 
    929 static void config (int sig ATTRIBUTE_UNUSED)
    930 {
    931   servtab_t *sep, *cp, **sepp;
    932   sigset_t omask;
    933   int add;
    934   size_t n;
    935   char protoname[10];
    936 
    937   if (!setconfig ()) {
    938     syslog (LOG_ERR, "%s: %m", CONFIG);
    939     return;
    940   }
    941   for (sep = servtab; sep; sep = sep->se_next)
    942     sep->se_checked = 0;
    943   cp = getconfigent ();
    944   while (cp != NULL) {
    945     for (sep = servtab; sep; sep = sep->se_next)
    946       if (matchconf (sep, cp))
    947         break;
    948     add = 0;
    949     if (sep != 0) {
    950       int i;
    951 
    952 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
    953 
    954       Block_Using_Signals(omask);
    955       /*
    956        * sep->se_wait may be holding the pid of a daemon
    957        * that we're waiting for.  If so, don't overwrite
    958        * it unless the config file explicitly says don't
    959        * wait.
    960        */
    961       if (
    962 #ifdef INETD_FEATURE_ENABLED
    963            cp->se_bi == 0 &&
    964 #endif
    965         (sep->se_wait == 1 || cp->se_wait == 0))
    966         sep->se_wait = cp->se_wait;
    967       SWAP (int, cp->se_max, sep->se_max);
    968       SWAP (char *, sep->se_user, cp->se_user);
    969       SWAP (char *, sep->se_group, cp->se_group);
    970       SWAP (char *, sep->se_server, cp->se_server);
    971       for (i = 0; i < MAXARGV; i++)
    972         SWAP (char *, sep->se_argv[i], cp->se_argv[i]);
    973 #undef SWAP
    974 
    975 #ifdef CONFIG_FEATURE_INETD_RPC
    976       if (isrpcservice (sep))
    977         unregister_rpc (sep);
    978       sep->se_rpcversl = cp->se_rpcversl;
    979       sep->se_rpcversh = cp->se_rpcversh;
    980 #endif
    981       sigprocmask(SIG_UNBLOCK, &omask, NULL);
    982       freeconfig (cp);
    983       add = 1;
    984     } else {
    985       sep = enter (cp);
    986     }
    987     sep->se_checked = 1;
    988 
    989     switch (sep->se_family) {
    990     case AF_UNIX:
    991       if (sep->se_fd != -1)
    992         break;
    993       (void) unlink (sep->se_service);
    994       n = strlen (sep->se_service);
    995       if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
    996         n = sizeof sep->se_ctrladdr_un.sun_path - 1;
    997       safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
    998       sep->se_ctrladdr_un.sun_family = AF_UNIX;
    999       sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
    1000       setup (sep);
    1001       break;
    1002     case AF_INET:
    1003       sep->se_ctrladdr_in.sin_family = AF_INET;
    1004       /* se_ctrladdr_in was set in getconfigent */
    1005       sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
    1006 
    1007 #ifdef CONFIG_FEATURE_INETD_RPC
    1008       if (isrpcservice (sep)) {
    1009         struct rpcent *rp;
    1010 
    1011         sep->se_rpcprog = atoi (sep->se_service);
    1012         if (sep->se_rpcprog == 0) {
    1013           rp = getrpcbyname (sep->se_service);
    1014           if (rp == 0) {
    1015             syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
    1016             goto serv_unknown;
    1017           }
    1018           sep->se_rpcprog = rp->r_number;
     1122        *sepp = sep->se_next;
     1123        if (sep->se_fd != -1) {
     1124            FD_CLR(sep->se_fd, &allsock);
     1125            nsock--;
     1126            (void) close(sep->se_fd);
    10191127        }
     1128#if ENABLE_FEATURE_INETD_RPC
     1129        if (isrpcservice(sep))
     1130            unregister_rpc(sep);
     1131#endif
     1132        if (sep->se_family == AF_UNIX)
     1133            (void) unlink(sep->se_service);
     1134        freeconfig(sep);
     1135        free(sep);
     1136    }
     1137    sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1138}
     1139
     1140
     1141static void reapchild(int sig ATTRIBUTE_UNUSED)
     1142{
     1143    pid_t pid;
     1144    int save_errno = errno, status;
     1145    servtab_t *sep;
     1146
     1147    for (;;) {
     1148        pid = wait3(&status, WNOHANG, NULL);
     1149        if (pid <= 0)
     1150            break;
     1151        for (sep = servtab; sep; sep = sep->se_next)
     1152            if (sep->se_wait == pid) {
     1153                if (WIFEXITED(status) && WEXITSTATUS(status))
     1154                    bb_error_msg("%s: exit status 0x%x",
     1155                            sep->se_server, WEXITSTATUS(status));
     1156                else if (WIFSIGNALED(status))
     1157                    bb_error_msg("%s: exit signal 0x%x",
     1158                            sep->se_server, WTERMSIG(status));
     1159                sep->se_wait = 1;
     1160                FD_SET(sep->se_fd, &allsock);
     1161                nsock++;
     1162            }
     1163    }
     1164    errno = save_errno;
     1165}
     1166
     1167static void retry(int sig ATTRIBUTE_UNUSED)
     1168{
     1169    servtab_t *sep;
     1170
     1171    timingout = 0;
     1172    for (sep = servtab; sep; sep = sep->se_next) {
     1173        if (sep->se_fd == -1) {
     1174            switch (sep->se_family) {
     1175            case AF_UNIX:
     1176            case AF_INET:
     1177#if ENABLE_FEATURE_IPV6
     1178            case AF_INET6:
     1179#endif
     1180                setup(sep);
     1181#if ENABLE_FEATURE_INETD_RPC
     1182                if (sep->se_fd != -1 && isrpcservice(sep))
     1183                    register_rpc(sep);
     1184#endif
     1185                break;
     1186            }
     1187        }
     1188    }
     1189}
     1190
     1191static void goaway(int sig ATTRIBUTE_UNUSED)
     1192{
     1193    servtab_t *sep;
     1194
     1195    /* XXX signal race walking sep list */
     1196    for (sep = servtab; sep; sep = sep->se_next) {
    10201197        if (sep->se_fd == -1)
    1021           setup (sep);
    1022         if (sep->se_fd != -1)
    1023           register_rpc (sep);
    1024       } else
    1025 #endif
    1026          {
    1027         u_short port = htons (atoi (sep->se_service));
    1028 
    1029         if (!port) {
    1030            /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
    1031           if (isdigit (protoname[strlen (protoname) - 1]))
    1032             protoname[strlen (protoname) - 1] = '\0';
    1033           sp = getservbyname (sep->se_service, protoname);
    1034           if (sp == 0) {
    1035             syslog (LOG_ERR,
    1036                     "%s/%s: unknown service", sep->se_service, sep->se_proto);
    1037             goto serv_unknown;
    1038           }
    1039           port = sp->s_port;
     1198            continue;
     1199
     1200        switch (sep->se_family) {
     1201        case AF_UNIX:
     1202            (void) unlink(sep->se_service);
     1203            break;
     1204        case AF_INET:
     1205#if ENABLE_FEATURE_IPV6
     1206        case AF_INET6:
     1207#endif
     1208#if ENABLE_FEATURE_INETD_RPC
     1209            if (sep->se_wait == 1 && isrpcservice(sep))
     1210                unregister_rpc(sep);   /* XXX signal race */
     1211#endif
     1212            break;
    10401213        }
    1041         if (port != sep->se_ctrladdr_in.sin_port) {
    1042           sep->se_ctrladdr_in.sin_port = port;
    1043           if (sep->se_fd != -1) {
    1044             FD_CLR (sep->se_fd, &allsock);
    1045             nsock--;
    1046             (void) close (sep->se_fd);
    1047           }
    1048           sep->se_fd = -1;
    1049         }
    1050         if (sep->se_fd == -1)
    1051           setup (sep);
    1052       }
    1053       break;
    1054 #ifdef CONFIG_FEATURE_IPV6
    1055     case AF_INET6:
    1056       sep->se_ctrladdr_in6.sin6_family = AF_INET6;
    1057       /* se_ctrladdr_in was set in getconfigent */
    1058       sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
    1059 
    1060 #ifdef CONFIG_FEATURE_INETD_RPC
    1061       if (isrpcservice (sep)) {
    1062         struct rpcent *rp;
    1063 
    1064         sep->se_rpcprog = atoi (sep->se_service);
    1065         if (sep->se_rpcprog == 0) {
    1066           rp = getrpcbyname (sep->se_service);
    1067           if (rp == 0) {
    1068             syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
    1069             goto serv_unknown;
    1070           }
    1071           sep->se_rpcprog = rp->r_number;
    1072         }
    1073         if (sep->se_fd == -1)
    1074           setup (sep);
    1075         if (sep->se_fd != -1)
    1076           register_rpc (sep);
    1077       } else
    1078 #endif
    1079         {
    1080         u_short port = htons (atoi (sep->se_service));
    1081 
    1082         if (!port) {
    1083            /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
    1084           if (isdigit (protoname[strlen (protoname) - 1]))
    1085             protoname[strlen (protoname) - 1] = '\0';
    1086           sp = getservbyname (sep->se_service, protoname);
    1087           if (sp == 0) {
    1088             syslog (LOG_ERR,
    1089                     "%s/%s: unknown service", sep->se_service, sep->se_proto);
    1090             goto serv_unknown;
    1091           }
    1092           port = sp->s_port;
    1093         }
    1094         if (port != sep->se_ctrladdr_in6.sin6_port) {
    1095           sep->se_ctrladdr_in6.sin6_port = port;
    1096           if (sep->se_fd != -1) {
    1097             FD_CLR (sep->se_fd, &allsock);
    1098             nsock--;
    1099             (void) close (sep->se_fd);
    1100           }
    1101           sep->se_fd = -1;
    1102         }
    1103         if (sep->se_fd == -1)
    1104           setup (sep);
    1105       }
    1106       break;
    1107 #endif /* CONFIG_FEATURE_IPV6 */
    1108     }
    1109   serv_unknown:
    1110     if (cp->se_next != NULL) {
    1111       servtab_t *tmp = cp;
    1112 
    1113       cp = cp->se_next;
    1114       free (tmp);
    1115     } else {
    1116       free (cp);
    1117       cp = getconfigent ();
    1118     }
    1119   }
    1120   endconfig ();
    1121   /*
    1122    * Purge anything not looked at above.
    1123    */
    1124   Block_Using_Signals(omask);
    1125   sepp = &servtab;
    1126   while ((sep = *sepp)) {
    1127     if (sep->se_checked) {
    1128       sepp = &sep->se_next;
    1129       continue;
    1130     }
    1131     *sepp = sep->se_next;
    1132     if (sep->se_fd != -1) {
    1133       FD_CLR (sep->se_fd, &allsock);
    1134       nsock--;
    1135       (void) close (sep->se_fd);
    1136     }
    1137 #ifdef CONFIG_FEATURE_INETD_RPC
    1138     if (isrpcservice (sep))
    1139       unregister_rpc (sep);
    1140 #endif
    1141     if (sep->se_family == AF_UNIX)
    1142       (void) unlink (sep->se_service);
    1143     freeconfig (sep);
    1144     free (sep);
    1145   }
    1146   sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1147 }
    1148 
    1149 
    1150 static void reapchild (int sig ATTRIBUTE_UNUSED)
    1151 {
    1152   pid_t pid;
    1153   int save_errno = errno, status;
    1154   servtab_t *sep;
    1155 
    1156   for (;;) {
    1157     pid = wait3 (&status, WNOHANG, NULL);
    1158     if (pid <= 0)
    1159       break;
    1160     for (sep = servtab; sep; sep = sep->se_next)
    1161       if (sep->se_wait == pid) {
    1162         if (WIFEXITED (status) && WEXITSTATUS (status))
    1163           syslog (LOG_WARNING,
    1164                   "%s: exit status 0x%x",
    1165                   sep->se_server, WEXITSTATUS (status));
    1166         else if (WIFSIGNALED (status))
    1167           syslog (LOG_WARNING,
    1168                   "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status));
    1169         sep->se_wait = 1;
    1170         FD_SET (sep->se_fd, &allsock);
    1171         nsock++;
    1172       }
    1173   }
    1174   errno = save_errno;
    1175 }
    1176 
    1177 static void retry (int sig ATTRIBUTE_UNUSED)
    1178 {
    1179   servtab_t *sep;
    1180 
    1181   timingout = 0;
    1182   for (sep = servtab; sep; sep = sep->se_next) {
    1183     if (sep->se_fd == -1) {
    1184       switch (sep->se_family) {
    1185       case AF_UNIX:
    1186       case AF_INET:
    1187 #ifdef CONFIG_FEATURE_IPV6
    1188       case AF_INET6:
    1189 #endif
    1190         setup (sep);
    1191 #ifdef CONFIG_FEATURE_INETD_RPC
    1192         if (sep->se_fd != -1 && isrpcservice (sep))
    1193           register_rpc (sep);
    1194 #endif
    1195         break;
    1196       }
    1197     }
    1198   }
    1199 }
    1200 
    1201 static void goaway (int sig ATTRIBUTE_UNUSED)
    1202 {
    1203   servtab_t *sep;
    1204 
    1205   /* XXX signal race walking sep list */
    1206   for (sep = servtab; sep; sep = sep->se_next) {
    1207     if (sep->se_fd == -1)
    1208       continue;
    1209 
    1210     switch (sep->se_family) {
    1211     case AF_UNIX:
    1212       (void) unlink (sep->se_service);
    1213       break;
    1214     case AF_INET:
    1215 #ifdef CONFIG_FEATURE_IPV6
    1216     case AF_INET6:
    1217 #endif
    1218 #ifdef CONFIG_FEATURE_INETD_RPC
    1219       if (sep->se_wait == 1 && isrpcservice (sep))
    1220         unregister_rpc (sep);   /* XXX signal race */
    1221 #endif
    1222       break;
    1223     }
    1224     (void) close (sep->se_fd);
    1225   }
    1226   (void) unlink (_PATH_INETDPID);
    1227   exit (0);
     1214        (void) close(sep->se_fd);
     1215    }
     1216    remove_pidfile(_PATH_INETDPID);
     1217    exit(0);
    12281218}
    12291219
     
    12341224
    12351225static void
    1236 inetd_setproctitle (char *a, int s)
    1237 {
    1238   socklen_t size;
    1239   char *cp;
    1240   struct sockaddr_in prt_sin;
    1241   char buf[80];
    1242 
    1243   cp = Argv[0];
    1244   size = sizeof (prt_sin);
    1245   (void) snprintf (buf, sizeof buf, "-%s", a);
    1246   if (getpeername (s, (struct sockaddr *) &prt_sin, &size) == 0) {
    1247     char *sa = inet_ntoa (prt_sin.sin_addr);
    1248 
    1249     buf[sizeof (buf) - 1 - strlen (sa) - 3] = '\0';
    1250     strcat (buf, " [");
    1251     strcat (buf, sa);
    1252     strcat (buf, "]");
    1253   }
    1254   strncpy (cp, buf, LastArg - cp);
    1255   cp += strlen (cp);
    1256   while (cp < LastArg)
    1257     *cp++ = ' ';
    1258 }
    1259 #endif
    1260 
    1261 
    1262 int
    1263 inetd_main (int argc, char *argv[])
    1264 {
    1265   servtab_t *sep;
    1266   struct passwd *pwd;
    1267   struct group *grp = NULL;
    1268   int tmpint;
    1269   struct sigaction sa, sapipe;
    1270   int opt;
    1271   pid_t pid;
    1272   char buf[50];
    1273   char *stoomany;
    1274   sigset_t omask, wait_mask;
     1226inetd_setproctitle(char *a, int s)
     1227{
     1228    socklen_t size;
     1229    char *cp;
     1230    struct sockaddr_in prt_sin;
     1231    char buf[80];
     1232
     1233    cp = Argv[0];
     1234    size = sizeof(prt_sin);
     1235    (void) snprintf(buf, sizeof buf, "-%s", a);
     1236    if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {
     1237        char *sa = inet_ntoa(prt_sin.sin_addr);
     1238
     1239        buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0';
     1240        strcat(buf, " [");
     1241        strcat(buf, sa);
     1242        strcat(buf, "]");
     1243    }
     1244    strncpy(cp, buf, LastArg - cp);
     1245    cp += strlen(cp);
     1246    while (cp < LastArg)
     1247        *cp++ = ' ';
     1248}
     1249#endif
     1250
     1251
     1252int inetd_main(int argc, char **argv);
     1253int inetd_main(int argc, char **argv)
     1254{
     1255    servtab_t *sep;
     1256    struct passwd *pwd;
     1257    struct group *grp = NULL;
     1258    int tmpint;
     1259    struct sigaction sa, sapipe;
     1260    int opt;
     1261    pid_t pid;
     1262    char buf[50];
     1263    char *stoomany;
     1264    sigset_t omask, wait_mask;
    12751265
    12761266#ifdef INETD_SETPROCTITLE
    1277   extern char **environ;
    1278   char **envp = environ;
    1279 
    1280   Argv = argv;
    1281   if (envp == 0 || *envp == 0)
    1282     envp = argv;
    1283   while (*envp)
    1284     envp++;
    1285   LastArg = envp[-1] + strlen (envp[-1]);
    1286 #endif
    1287 
    1288   openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
    1289 
    1290   opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany);
    1291   if(opt & 1) {
    1292     char *e;
    1293 
    1294     toomany = strtoul (stoomany, &e, 0);
    1295     if (!(toomany >= 0 && *e == '\0')) {
    1296         toomany = TOOMANY;
    1297         syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany);
    1298     }
    1299   }
    1300   argc -= optind;
    1301   argv += optind;
    1302 
    1303   uid = getuid ();
    1304   if (uid != 0)
    1305     CONFIG = NULL;
    1306   if (argc > 0)
    1307     CONFIG = argv[0];
    1308   if (CONFIG == NULL)
    1309     bb_error_msg_and_die ("non-root must specify a config file");
    1310 
    1311   if (!(opt & 2)) {
    1312 #ifdef BB_NOMMU
    1313     /* reexec for vfork() do continue parent */
    1314     vfork_daemon_rexec (0, 0, argc, argv, "-f");
    1315 #else
    1316     bb_xdaemon (0, 0);
    1317 #endif
    1318   } else {
    1319     setsid ();
    1320   }
    1321 
    1322   if (uid == 0) {
    1323     gid_t gid = getgid ();
    1324 
    1325     /* If run by hand, ensure groups vector gets trashed */
    1326     setgroups (1, &gid);
    1327   }
    1328 
    1329   {
    1330     FILE *fp;
    1331 
    1332     if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) {
    1333         fprintf (fp, "%u\n", getpid ());
    1334         (void) fclose (fp);
    1335     }
    1336   }
    1337 
    1338   if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) {
    1339     syslog (LOG_ERR, "getrlimit: %m");
    1340   } else {
    1341     rlim_ofile_cur = rlim_ofile.rlim_cur;
    1342     if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
    1343       rlim_ofile_cur = OPEN_MAX;
    1344   }
    1345 
    1346   memset ((char *) &sa, 0, sizeof (sa));
    1347   sigemptyset (&sa.sa_mask);
    1348   sigaddset (&sa.sa_mask, SIGALRM);
    1349   sigaddset (&sa.sa_mask, SIGCHLD);
    1350   sigaddset (&sa.sa_mask, SIGHUP);
    1351   sa.sa_handler = retry;
    1352   sigaction (SIGALRM, &sa, NULL);
    1353   /* doconfig(); */
    1354   config (SIGHUP);
    1355   sa.sa_handler = config;
    1356   sigaction (SIGHUP, &sa, NULL);
    1357   sa.sa_handler = reapchild;
    1358   sigaction (SIGCHLD, &sa, NULL);
    1359   sa.sa_handler = goaway;
    1360   sigaction (SIGTERM, &sa, NULL);
    1361   sa.sa_handler = goaway;
    1362   sigaction (SIGINT, &sa, NULL);
    1363   sa.sa_handler = SIG_IGN;
    1364   sigaction (SIGPIPE, &sa, &sapipe);
    1365   memset(&wait_mask, 0, sizeof(wait_mask));
    1366   {
    1367     /* space for daemons to overwrite environment for ps */
     1267    char **envp = environ;
     1268
     1269    Argv = argv;
     1270    if (envp == 0 || *envp == 0)
     1271        envp = argv;
     1272    while (*envp)
     1273        envp++;
     1274    LastArg = envp[-1] + strlen(envp[-1]);
     1275#endif
     1276
     1277    uid = getuid();
     1278    if (uid != 0)
     1279        config_filename = NULL;
     1280
     1281    opt = getopt32(argv, "R:f", &stoomany);
     1282    if (opt & 1)
     1283        toomany = xatoi_u(stoomany);
     1284    argv += optind;
     1285    argc -= optind;
     1286    if (argc)
     1287        config_filename = argv[0];
     1288    if (config_filename == NULL)
     1289        bb_error_msg_and_die("non-root must specify a config file");
     1290
     1291    if (!(opt & 2))
     1292        bb_daemonize_or_rexec(0, argv - optind);
     1293    else
     1294        bb_sanitize_stdio();
     1295    openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
     1296    logmode = LOGMODE_SYSLOG;
     1297
     1298    if (uid == 0) {
     1299        /* If run by hand, ensure groups vector gets trashed */
     1300        gid_t gid = getgid();
     1301        setgroups(1, &gid);
     1302    }
     1303
     1304    write_pidfile(_PATH_INETDPID);
     1305
     1306    if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
     1307        bb_perror_msg("getrlimit");
     1308    } else {
     1309        rlim_ofile_cur = rlim_ofile.rlim_cur;
     1310        if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
     1311            rlim_ofile_cur = OPEN_MAX;
     1312    }
     1313
     1314    memset((char *) &sa, 0, sizeof(sa));
     1315    sigemptyset(&sa.sa_mask);
     1316    sigaddset(&sa.sa_mask, SIGALRM);
     1317    sigaddset(&sa.sa_mask, SIGCHLD);
     1318    sigaddset(&sa.sa_mask, SIGHUP);
     1319    sa.sa_handler = retry;
     1320    sigaction(SIGALRM, &sa, NULL);
     1321    config(SIGHUP);
     1322    sa.sa_handler = config;
     1323    sigaction(SIGHUP, &sa, NULL);
     1324    sa.sa_handler = reapchild;
     1325    sigaction(SIGCHLD, &sa, NULL);
     1326    sa.sa_handler = goaway;
     1327    sigaction(SIGTERM, &sa, NULL);
     1328    sa.sa_handler = goaway;
     1329    sigaction(SIGINT, &sa, NULL);
     1330    sa.sa_handler = SIG_IGN;
     1331    sigaction(SIGPIPE, &sa, &sapipe);
     1332    memset(&wait_mask, 0, sizeof(wait_mask));
     1333    {
     1334        /* space for daemons to overwrite environment for ps */
    13681335#define DUMMYSIZE       100
    1369     char dummy[DUMMYSIZE];
    1370 
    1371     (void) memset (dummy, 'x', DUMMYSIZE - 1);
    1372     dummy[DUMMYSIZE - 1] = '\0';
    1373 
    1374     (void) setenv ("inetd_dummy", dummy, 1);
    1375   }
    1376 
    1377   for (;;) {
    1378     int n, ctrl = -1;
    1379     fd_set readable;
    1380 
    1381     if (nsock == 0) {
    1382       Block_Using_Signals(omask);
    1383       while (nsock == 0)
    1384         sigsuspend (&wait_mask);
    1385       sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1386     }
    1387 
    1388     readable = allsock;
    1389     if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) {
    1390       if (n < 0 && errno != EINTR) {
    1391         syslog (LOG_WARNING, "select: %m");
    1392         sleep (1);
    1393       }
    1394       continue;
    1395     }
    1396     for (sep = servtab; n && sep; sep = sep->se_next)
    1397       if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) {
    1398         n--;
    1399         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
    1400           ctrl = accept (sep->se_fd, NULL, NULL);
    1401           if (ctrl < 0) {
    1402             if (errno == EINTR)
    1403               continue;
    1404             syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service);
     1336        char dummy[DUMMYSIZE];
     1337
     1338        (void) memset(dummy, 'x', DUMMYSIZE - 1);
     1339        dummy[DUMMYSIZE - 1] = '\0';
     1340
     1341        (void) setenv("inetd_dummy", dummy, 1);
     1342    }
     1343
     1344    for (;;) {
     1345        int n, ctrl = -1;
     1346        fd_set readable;
     1347
     1348        if (nsock == 0) {
     1349            Block_Using_Signals(omask);
     1350            while (nsock == 0)
     1351                sigsuspend(&wait_mask);
     1352            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1353        }
     1354
     1355        readable = allsock;
     1356        n = select(maxsock + 1, &readable, NULL, NULL, NULL);
     1357        if (n <= 0) {
     1358            if (n < 0 && errno != EINTR) {
     1359                bb_perror_msg("select");
     1360                sleep(1);
     1361            }
    14051362            continue;
    1406           }
    1407           if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
    1408             struct sockaddr_in peer;
    1409             socklen_t plen = sizeof (peer);
    1410 
    1411             if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) {
    1412               syslog (LOG_WARNING, "could not getpeername");
    1413               close (ctrl);
    1414               continue;
     1363        }
     1364
     1365        for (sep = servtab; n && sep; sep = sep->se_next) {
     1366            if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
     1367                continue;
     1368
     1369            n--;
     1370            if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
     1371                ctrl = accept(sep->se_fd, NULL, NULL);
     1372                if (ctrl < 0) {
     1373                    if (errno == EINTR)
     1374                        continue;
     1375                    bb_perror_msg("accept (for %s)", sep->se_service);
     1376                    continue;
     1377                }
     1378                if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
     1379                    struct sockaddr_in peer;
     1380                    socklen_t plen = sizeof(peer);
     1381
     1382                    if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) {
     1383                        bb_error_msg("cannot getpeername");
     1384                        close(ctrl);
     1385                        continue;
     1386                    }
     1387                    if (ntohs(peer.sin_port) == 20) {
     1388                        /* XXX ftp bounce */
     1389                        close(ctrl);
     1390                        continue;
     1391                    }
     1392                }
     1393            } else
     1394                ctrl = sep->se_fd;
     1395
     1396            Block_Using_Signals(omask);
     1397            pid = 0;
     1398#ifdef INETD_FEATURE_ENABLED
     1399            if (sep->se_bi == 0 || sep->se_bi->bi_fork)
     1400#endif
     1401            {
     1402                if (sep->se_count++ == 0)
     1403                    (void) gettimeofday(&sep->se_time, NULL);
     1404                else if (toomany > 0 && sep->se_count >= sep->se_max) {
     1405                    struct timeval now;
     1406
     1407                    (void) gettimeofday(&now, NULL);
     1408                    if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
     1409                        sep->se_time = now;
     1410                        sep->se_count = 1;
     1411                    } else {
     1412                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1413                            close(ctrl);
     1414                        if (sep->se_family == AF_INET &&
     1415                              ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
     1416                            /*
     1417                             * Cannot close it -- there are
     1418                             * thieves on the system.
     1419                             * Simply ignore the connection.
     1420                             */
     1421                            --sep->se_count;
     1422                            continue;
     1423                        }
     1424                        bb_error_msg("%s/%s server failing (looping), service terminated",
     1425                                  sep->se_service, sep->se_proto);
     1426                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1427                            close(ctrl);
     1428                        FD_CLR(sep->se_fd, &allsock);
     1429                        (void) close(sep->se_fd);
     1430                        sep->se_fd = -1;
     1431                        sep->se_count = 0;
     1432                        nsock--;
     1433                        sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1434                        if (!timingout) {
     1435                            timingout = 1;
     1436                            alarm(RETRYTIME);
     1437                        }
     1438                        continue;
     1439                    }
     1440                }
     1441                pid = fork();
    14151442            }
    1416             if (ntohs (peer.sin_port) == 20) {
    1417               /* XXX ftp bounce */
    1418               close (ctrl);
    1419               continue;
     1443            if (pid < 0) {
     1444                bb_perror_msg("fork");
     1445                if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1446                    close(ctrl);
     1447                sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1448                sleep(1);
     1449                continue;
    14201450            }
    1421           }
    1422         } else
    1423           ctrl = sep->se_fd;
    1424         Block_Using_Signals(omask);
    1425         pid = 0;
     1451            if (pid && sep->se_wait) {
     1452                sep->se_wait = pid;
     1453                FD_CLR(sep->se_fd, &allsock);
     1454                nsock--;
     1455            }
     1456            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1457            if (pid == 0) {
    14261458#ifdef INETD_FEATURE_ENABLED
    1427         if (sep->se_bi == 0 || sep->se_bi->bi_fork)
    1428 #endif
    1429         {
    1430           if (sep->se_count++ == 0)
    1431             (void) gettimeofday (&sep->se_time, NULL);
    1432           else if (toomany > 0 && sep->se_count >= sep->se_max) {
    1433             struct timeval now;
    1434 
    1435             (void) gettimeofday (&now, NULL);
    1436             if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
    1437               sep->se_time = now;
    1438               sep->se_count = 1;
    1439             } else {
    1440               if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1441                 close (ctrl);
    1442               if (sep->se_family == AF_INET &&
    1443                   ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
    1444                 /*
    1445                  * Cannot close it -- there are
    1446                  * thieves on the system.
    1447                  * Simply ignore the connection.
    1448                  */
    1449                 --sep->se_count;
    1450                 continue;
    1451               }
    1452               syslog (LOG_ERR,
    1453                       "%s/%s server failing (looping), service terminated",
    1454                       sep->se_service, sep->se_proto);
    1455               if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1456                 close (ctrl);
    1457               FD_CLR (sep->se_fd, &allsock);
    1458               (void) close (sep->se_fd);
    1459               sep->se_fd = -1;
    1460               sep->se_count = 0;
    1461               nsock--;
    1462               sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1463               if (!timingout) {
    1464                 timingout = 1;
    1465                 alarm (RETRYTIME);
    1466               }
    1467               continue;
     1459                if (sep->se_bi) {
     1460                    (*sep->se_bi->bi_fn)(ctrl, sep);
     1461                } else
     1462#endif
     1463                {
     1464                    pwd = getpwnam(sep->se_user);
     1465                    if (pwd == NULL) {
     1466                        bb_error_msg("getpwnam: %s: no such user", sep->se_user);
     1467                        goto do_exit1;
     1468                    }
     1469                    if (setsid() < 0)
     1470                        bb_perror_msg("%s: setsid", sep->se_service);
     1471                    if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
     1472                        bb_error_msg("getgrnam: %s: no such group", sep->se_group);
     1473                        goto do_exit1;
     1474                    }
     1475                    if (uid != 0) {
     1476                        /* a user running private inetd */
     1477                        if (uid != pwd->pw_uid)
     1478                            _exit(1);
     1479                    } else if (pwd->pw_uid) {
     1480                        if (sep->se_group)
     1481                            pwd->pw_gid = grp->gr_gid;
     1482                        xsetgid((gid_t) pwd->pw_gid);
     1483                        initgroups(pwd->pw_name, pwd->pw_gid);
     1484                        xsetuid((uid_t) pwd->pw_uid);
     1485                    } else if (sep->se_group) {
     1486                        xsetgid(grp->gr_gid);
     1487                        setgroups(1, &grp->gr_gid);
     1488                    }
     1489                    dup2(ctrl, 0);
     1490                    if (ctrl) close(ctrl);
     1491                    dup2(0, 1);
     1492                    dup2(0, 2);
     1493                    if (rlim_ofile.rlim_cur != rlim_ofile_cur)
     1494                        if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
     1495                            bb_perror_msg("setrlimit");
     1496                    closelog();
     1497                    for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
     1498                        (void) close(tmpint);
     1499                    sigaction(SIGPIPE, &sapipe, NULL);
     1500                    execv(sep->se_server, sep->se_argv);
     1501                    bb_perror_msg("execv %s", sep->se_server);
     1502 do_exit1:
     1503                    if (sep->se_socktype != SOCK_STREAM)
     1504                        recv(0, buf, sizeof(buf), 0);
     1505                    _exit(1);
     1506                }
    14681507            }
    1469           }
    1470           pid = fork ();
    1471         }
    1472         if (pid < 0) {
    1473           syslog (LOG_ERR, "fork: %m");
    1474           if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1475             close (ctrl);
    1476           sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1477           sleep (1);
    1478           continue;
    1479         }
    1480         if (pid && sep->se_wait) {
    1481           sep->se_wait = pid;
    1482           FD_CLR (sep->se_fd, &allsock);
    1483           nsock--;
    1484         }
    1485         sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1486         if (pid == 0) {
    1487 #ifdef INETD_FEATURE_ENABLED
    1488           if (sep->se_bi) {
    1489             (*sep->se_bi->bi_fn) (ctrl, sep);
    1490           } else
    1491 #endif
    1492             {
    1493             if ((pwd = getpwnam (sep->se_user)) == NULL) {
    1494               syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user);
    1495               if (sep->se_socktype != SOCK_STREAM)
    1496                 recv (0, buf, sizeof (buf), 0);
    1497               _exit (1);
    1498             }
    1499             if (setsid () < 0)
    1500               syslog (LOG_ERR, "%s: setsid: %m", sep->se_service);
    1501             if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) {
    1502               syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group);
    1503               if (sep->se_socktype != SOCK_STREAM)
    1504                 recv (0, buf, sizeof (buf), 0);
    1505               _exit (1);
    1506             }
    1507             if (uid != 0) {
    1508               /* a user running private inetd */
    1509               if (uid != pwd->pw_uid)
    1510                 _exit (1);
    1511             } else if (pwd->pw_uid) {
    1512               if (sep->se_group) {
    1513                 pwd->pw_gid = grp->gr_gid;
    1514               }
    1515               xsetgid ((gid_t) pwd->pw_gid);
    1516               initgroups (pwd->pw_name, pwd->pw_gid);
    1517               xsetuid((uid_t) pwd->pw_uid);
    1518             } else if (sep->se_group) {
    1519               xsetgid(grp->gr_gid);
    1520               setgroups (1, &grp->gr_gid);
    1521             }
    1522             dup2 (ctrl, 0);
    1523             close (ctrl);
    1524             dup2 (0, 1);
    1525             dup2 (0, 2);
    1526             if (rlim_ofile.rlim_cur != rlim_ofile_cur)
    1527               if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0)
    1528                 syslog (LOG_ERR, "setrlimit: %m");
    1529             closelog ();
    1530             for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
    1531               (void) close (tmpint);
    1532             sigaction (SIGPIPE, &sapipe, NULL);
    1533             execv (sep->se_server, sep->se_argv);
    1534             if (sep->se_socktype != SOCK_STREAM)
    1535               recv (0, buf, sizeof (buf), 0);
    1536             syslog (LOG_ERR, "execv %s: %m", sep->se_server);
    1537             _exit (1);
    1538           }
    1539         }
    1540         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1541           close (ctrl);
    1542       }
    1543   }
     1508            if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1509                close(ctrl);
     1510        } /* for (sep = servtab...) */
     1511    } /* for (;;) */
    15441512}
    15451513
     
    15491517#define BUFSIZE 4096
    15501518
    1551 #if defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO) || \
    1552     defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN) || \
    1553     defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME)
    1554 static int dg_badinput (struct sockaddr_in *dg_sin)
    1555 {
    1556   if (ntohs (dg_sin->sin_port) < IPPORT_RESERVED)
    1557     return (1);
    1558   if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST))
    1559     return (1);
    1560   /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
    1561   return (0);
    1562 }
    1563 #endif
    1564 
    1565 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     1519#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     1520    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
     1521    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     1522static int dg_badinput(struct sockaddr_in *dg_sin)
     1523{
     1524    if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
     1525        return 1;
     1526    if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))
     1527        return 1;
     1528    /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
     1529    return 0;
     1530}
     1531#endif
     1532
     1533#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    15661534/* Echo service -- echo data back */
    15671535/* ARGSUSED */
    15681536static void
    1569 echo_stream (int s, servtab_t *sep)
    1570 {
    1571   char buffer[BUFSIZE];
    1572   int i;
    1573 
    1574   inetd_setproctitle (sep->se_service, s);
    1575   while ((i = read (s, buffer, sizeof (buffer))) > 0 &&
    1576          write (s, buffer, i) > 0);
    1577   exit (0);
     1537echo_stream(int s, servtab_t *sep)
     1538{
     1539    char buffer[BUFSIZE];
     1540    int i;
     1541
     1542    inetd_setproctitle(sep->se_service, s);
     1543    while (1) {
     1544        i = read(s, buffer, sizeof(buffer));
     1545        if (i <= 0) break;
     1546        /* FIXME: this isnt correct - safe_write()? */
     1547        if (write(s, buffer, i) <= 0) break;
     1548    }
     1549    exit(0);
    15781550}
    15791551
     
    15811553/* ARGSUSED */
    15821554static void
    1583 echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1584 {
    1585   char buffer[BUFSIZE];
    1586   int i;
    1587   socklen_t size;
    1588   /* struct sockaddr_storage ss; */
    1589   struct sockaddr sa;
    1590 
    1591   size = sizeof (sa);
    1592   if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0)
    1593     return;
    1594   if (dg_badinput ((struct sockaddr_in *) &sa))
    1595     return;
    1596   (void) sendto (s, buffer, i, 0, &sa, sizeof (sa));
    1597 }
    1598 #endif  /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
    1599 
    1600 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     1555echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1556{
     1557    char buffer[BUFSIZE];
     1558    int i;
     1559    socklen_t size;
     1560    /* struct sockaddr_storage ss; */
     1561    struct sockaddr sa;
     1562
     1563    size = sizeof(sa);
     1564    i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size);
     1565    if (i < 0)
     1566        return;
     1567    if (dg_badinput((struct sockaddr_in *) &sa))
     1568        return;
     1569    (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
     1570}
     1571#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
     1572
     1573#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    16011574/* Discard service -- ignore data */
    16021575/* ARGSUSED */
    16031576static void
    1604 discard_stream (int s, servtab_t *sep)
    1605 {
    1606   char buffer[BUFSIZE];
    1607 
    1608   inetd_setproctitle (sep->se_service, s);
    1609   while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) ||
    1610          errno == EINTR);
    1611   exit (0);
     1577discard_stream(int s, servtab_t *sep)
     1578{
     1579    char buffer[BUFSIZE];
     1580
     1581    inetd_setproctitle(sep->se_service, s);
     1582    while (1) {
     1583        errno = 0;
     1584        if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR)
     1585            exit(0);
     1586    }
    16121587}
    16131588
     
    16151590/* ARGSUSED */
    16161591static void
    1617 discard_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1618 {
    1619   char buffer[BUFSIZE];
    1620 
    1621   (void) read (s, buffer, sizeof (buffer));
    1622 }
    1623 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
    1624 
    1625 
    1626 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     1592discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1593{
     1594    char buffer[BUFSIZE];
     1595
     1596    (void) read(s, buffer, sizeof(buffer));
     1597}
     1598#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
     1599
     1600
     1601#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    16271602#define LINESIZ 72
    16281603static char ring[128];
     
    16301605
    16311606static void
    1632 initring (void)
    1633 {
    1634   int i;
    1635 
    1636   endring = ring;
    1637 
    1638   for (i = 0; i <= 128; ++i)
    1639     if (isprint (i))
    1640       *endring++ = i;
     1607initring(void)
     1608{
     1609    int i;
     1610
     1611    endring = ring;
     1612
     1613    for (i = 0; i <= 128; ++i)
     1614        if (isprint(i))
     1615            *endring++ = i;
    16411616}
    16421617
     
    16441619/* ARGSUSED */
    16451620static void
    1646 chargen_stream (int s, servtab_t *sep)
    1647 {
    1648   char *rs;
    1649   int len;
    1650   char text[LINESIZ + 2];
    1651 
    1652   inetd_setproctitle (sep->se_service, s);
    1653 
    1654   if (!endring) {
    1655     initring ();
     1621chargen_stream(int s, servtab_t *sep)
     1622{
     1623    char *rs;
     1624    int len;
     1625    char text[LINESIZ + 2];
     1626
     1627    inetd_setproctitle(sep->se_service, s);
     1628
     1629    if (!endring) {
     1630        initring();
     1631        rs = ring;
     1632    }
     1633
     1634    text[LINESIZ] = '\r';
     1635    text[LINESIZ + 1] = '\n';
    16561636    rs = ring;
    1657   }
    1658 
    1659   text[LINESIZ] = '\r';
    1660   text[LINESIZ + 1] = '\n';
    1661   for (rs = ring;;) {
    1662     if ((len = endring - rs) >= LINESIZ)
    1663       memmove (text, rs, LINESIZ);
    1664     else {
    1665       memmove (text, rs, len);
    1666       memmove (text + len, ring, LINESIZ - len);
    1667     }
    1668     if (++rs == endring)
    1669       rs = ring;
    1670     if (write (s, text, sizeof (text)) != sizeof (text))
    1671       break;
    1672   }
    1673   exit (0);
     1637    for (;;) {
     1638        len = endring - rs;
     1639        if (len >= LINESIZ)
     1640            memmove(text, rs, LINESIZ);
     1641        else {
     1642            memmove(text, rs, len);
     1643            memmove(text + len, ring, LINESIZ - len);
     1644        }
     1645        if (++rs == endring)
     1646            rs = ring;
     1647        if (write(s, text, sizeof(text)) != sizeof(text))
     1648            break;
     1649    }
     1650    exit(0);
    16741651}
    16751652
     
    16771654/* ARGSUSED */
    16781655static void
    1679 chargen_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1680 {
    1681   /* struct sockaddr_storage ss; */
    1682   struct sockaddr sa;
    1683   static char *rs;
    1684   int len;
    1685   char text[LINESIZ + 2];
    1686   socklen_t size;
    1687 
    1688   if (endring == 0) {
    1689     initring ();
    1690     rs = ring;
    1691   }
    1692 
    1693   size = sizeof (sa);
    1694   if (recvfrom (s, text, sizeof (text), 0, &sa, &size) < 0)
    1695     return;
    1696   if (dg_badinput ((struct sockaddr_in *) &sa))
    1697     return;
    1698 
    1699   if ((len = endring - rs) >= LINESIZ)
    1700     memmove (text, rs, LINESIZ);
    1701   else {
    1702     memmove (text, rs, len);
    1703     memmove (text + len, ring, LINESIZ - len);
    1704   }
    1705   if (++rs == endring)
    1706     rs = ring;
    1707   text[LINESIZ] = '\r';
    1708   text[LINESIZ + 1] = '\n';
    1709   (void) sendto (s, text, sizeof (text), 0, &sa, sizeof (sa));
    1710 }
    1711 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
    1712 
    1713 
    1714 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     1656chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1657{
     1658    /* struct sockaddr_storage ss; */
     1659    struct sockaddr sa;
     1660    static char *rs;
     1661    int len;
     1662    char text[LINESIZ + 2];
     1663    socklen_t size;
     1664
     1665    if (endring == 0) {
     1666        initring();
     1667        rs = ring;
     1668    }
     1669
     1670    size = sizeof(sa);
     1671    if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
     1672        return;
     1673    if (dg_badinput((struct sockaddr_in *) &sa))
     1674        return;
     1675
     1676    if ((len = endring - rs) >= LINESIZ)
     1677        memmove(text, rs, LINESIZ);
     1678    else {
     1679        memmove(text, rs, len);
     1680        memmove(text + len, ring, LINESIZ - len);
     1681    }
     1682    if (++rs == endring)
     1683        rs = ring;
     1684    text[LINESIZ] = '\r';
     1685    text[LINESIZ + 1] = '\n';
     1686    (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
     1687}
     1688#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
     1689
     1690
     1691#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    17151692/*
    17161693 * Return a machine readable date and time, in the form of the
     
    17211698 */
    17221699
    1723 static u_int machtime (void)
    1724 {
    1725   struct timeval tv;
    1726 
    1727   if (gettimeofday (&tv, NULL) < 0) {
    1728     fprintf (stderr, "Unable to get time of day\n");
    1729     return (0L);
    1730   }
    1731   return (htonl ((u_int) tv.tv_sec + 2208988800UL));
     1700static unsigned machtime(void)
     1701{
     1702    struct timeval tv;
     1703
     1704    if (gettimeofday(&tv, NULL) < 0) {
     1705        fprintf(stderr, "Unable to get time of day\n");
     1706        return 0L;
     1707    }
     1708    return htonl((unsigned) tv.tv_sec + 2208988800UL);
    17321709}
    17331710
    17341711/* ARGSUSED */
    17351712static void
    1736 machtime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1737 {
    1738   u_int result;
    1739 
    1740   result = machtime ();
    1741   (void) write (s, (char *) &result, sizeof (result));
     1713machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1714{
     1715    unsigned result;
     1716
     1717    result = machtime();
     1718    (void) write(s, (char *) &result, sizeof(result));
    17421719}
    17431720
    17441721/* ARGSUSED */
    17451722static void
    1746 machtime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1747 {
    1748   u_int result;
    1749   /* struct sockaddr_storage ss; */
    1750   struct sockaddr sa;
    1751   struct sockaddr_in *dg_sin;
    1752   socklen_t size;
    1753 
    1754   size = sizeof (sa);
    1755   if (recvfrom (s, (char *) &result, sizeof (result), 0, &sa, &size) < 0)
    1756     return;
    1757   /* if (dg_badinput((struct sockaddr *)&ss)) */
    1758   dg_sin = (struct sockaddr_in *) &sa;
    1759   if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST) ||
    1760       ntohs (dg_sin->sin_port) < IPPORT_RESERVED / 2)
    1761     return;
    1762   result = machtime ();
    1763   (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof (sa));
    1764 }
    1765 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME */
    1766 
    1767 
    1768 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     1723machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1724{
     1725    unsigned result;
     1726    /* struct sockaddr_storage ss; */
     1727    struct sockaddr sa;
     1728    struct sockaddr_in *dg_sin;
     1729    socklen_t size;
     1730
     1731    size = sizeof(sa);
     1732    if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)
     1733        return;
     1734    /* if (dg_badinput((struct sockaddr *)&ss)) */
     1735    dg_sin = (struct sockaddr_in *) &sa;
     1736    if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
     1737            ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)
     1738        return;
     1739    result = machtime();
     1740    (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
     1741}
     1742#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
     1743
     1744
     1745#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    17691746/* Return human-readable time of day */
    17701747/* ARGSUSED */
    1771 static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1772 {
    1773   char buffer[256];
    1774   time_t t;
    1775 
    1776   t = time (NULL);
    1777 
    1778   (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
    1779   (void) write (s, buffer, strlen (buffer));
     1748static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1749{
     1750    char buffer[32];
     1751    time_t t;
     1752
     1753    t = time(NULL);
     1754
     1755// fdprintf instead?
     1756    (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
     1757    (void) write(s, buffer, strlen(buffer));
    17801758}
    17811759
     
    17831761/* ARGSUSED */
    17841762void
    1785 daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1786 {
    1787   char buffer[256];
    1788   time_t t;
    1789   /* struct sockaddr_storage ss; */
    1790   struct sockaddr sa;
    1791   socklen_t size;
    1792 
    1793   t = time ((time_t *) 0);
    1794 
    1795   size = sizeof (sa);
    1796   if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0)
    1797     return;
    1798   if (dg_badinput ((struct sockaddr_in *) &sa))
    1799     return;
    1800   (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
    1801   (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa));
    1802 }
    1803 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
    1804 /* vi: set sw=4 ts=4: */
     1763daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1764{
     1765    char buffer[256];
     1766    time_t t;
     1767    /* struct sockaddr_storage ss; */
     1768    struct sockaddr sa;
     1769    socklen_t size;
     1770
     1771    t = time(NULL);
     1772
     1773    size = sizeof(sa);
     1774    if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
     1775        return;
     1776    if (dg_badinput((struct sockaddr_in *) &sa))
     1777        return;
     1778    (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
     1779    (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
     1780}
     1781#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
Note: See TracChangeset for help on using the changeset viewer.