After a little reflection, here are the proposed changes to inetd(8):
THE CONFIGURATION There is only one configuration file given by a path---whether on the command line or defaulting to "/etc/inetd.conf". The inclusion directive is a dot i.e. a here script: there are not different configuration files, but only one that may simply be assembled by dot'ing others. This means that all definitions have a global scope and that the feature of the default address, if not specified, is not limited to the file that is dot'ed there. The configuration has hence to be wholly correct since any failure may totally change the meaning of the directives (by changing the default address). => I will disentangle the execution of the directives from the parsing of the config (at the moment, services are launched once a line is parsed, ignoring errors). To begin any action, the configuration will have to be globally accepted. The consequence will be that it will be possible to check the config without running and without adding spaghetti code to not execute if only checking. For checking, two options will be added: -c check a config file (and does not execute). Returns 0 on success and ENOENT or EINVAL on error. -C as -c plus dump on stdout an explicit normalized config as it has been parsed. If the config is invalid, nothing is dumped: no action is taken if the config is invalid (there is no security problem if inetd is run by a not root user since the user has to have reading rights to the whole configuration to obtain any result: nothing is revealed that he would not have been able to get without the program. NORMAL BEHAVIOR In the normal behavior, an incorrect config is fatal: a message is logged via syslog, but the process exits with error (ENOENT or EINVAL). RESILIENT BEHAVIOR Since a config can be rejected and hence nothing serviced, there will be the addition of another mode: -r Resilient. At start, if the config given is invalid, try to load instead a fallback config file "/etc/inetd.fallback.conf". If this config also fails (maybe inexistent), serves nothing but keep running (the program is then still loaded, meaning resilience also against an update of the binaries). In this mode, an instruction to reload will try to reload THE config (the one defined at the beginning, not the fallback one) and if this new config fails, the process will continue to serve the previous config (since nothing is done before validating the whole configuration, the previous, as it is, continues to be serviced; if it was the no-op, it continues to be the no-op: the fallback config is not reloaded. But see below.). Note: resilient does not mean restricted. The fallback conf can be as convoluted as a "normal" conf file. But one usage (not mandatory) will probably be a safe minimal file with essential services to ensure in all cases that the minimum is accessible. CONTROL Supplementary to SIGHUP: SIGUSR1 will instruct to load the fallback conf. This doesn't change THE config (a SIGHUP following will try to reload THE config and not the fallback), but loads, now, in its stead, the fallback one. This is a way to decrease the services serviced without stopping and restarting with another config file. SIGUSR2 (or SIGINFO?) will instruct to dump the current config via syslog. (Rationale: whether for debugging purposes, or because the administrator has tampered with its config without knowing anymore what worked, offer the possibility to tell what is supposed to work now). CONFIG DUMP A config dump shall be so that its loading as config will lead to exactly the same behavior as the one obtained with the config file initially provided to the parser. MODIFICATION FROM PRESENT PARSING HANDLING A file can be loaded several times as long as there is no loop (in fact, at the moment, contrary to what is stated in the man page, loops are not detected: they are prevented by not allowing to load the same file twice---and due to bugs, this is not guaranteed). The loop detection will not use realpath(3) but dev/inode. A config file has to be a regular file (not a pipe). Its size is retrieved at opening and not more than its initial size is processed. If the process succeeds but the size of the file has changed when reaching the end (of the processing of this file), there is tampering with the file and the config fails (it does not guarantee against any tampering but at least it ensures that there will be, by file, a definite amount of data to process). The pathnames list resulting from globing will be sorted lexicographically. This means that a user, by choosing carefully the names, can ensure a definite order of inclusion of the files while having the convenience of using globbing. MONITORING There are logs with syslog facility if not just checking. In order to allow scripting the log, the messages will have a defined format (these are only for global behavior and do not include messages related to individual services): [Is there guidelines about them?] 'inetd' SPACE <action> SPACE <arguments> <action>: 'STARTING' SPACE <arg[0] arguments> 'REJECTING' SPACE <config pathname> 'SERVICING' SPACE <config pathname> 'RELOADING' SPACE <config pathname> 'KEEPING' /* the config is the one parsed; it has no name... */ 'FALLING-BACK' SPACE '/etc/inetd.fallback.conf' 'DUMPING' SPACE <explicit normalized config directive> 'EXITING' SPACE <status> -- Thierry Laronde <tlaronde +AT+ polynum +dot+ com> http://www.kergis.com/ http://kertex.kergis.com/ Key fingerprint = 0FF7 E906 FBAF FE95 FD89 250D 52B1 AE95 6006 F40C