From 587a3eb1ae3f4e39ba293b5f397b5241c0fee54d Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Sat, 2 Sep 2023 05:21:42 +0000 Subject: More doc; unify tipidee-config exit codes Signed-off-by: Laurent Bercot --- doc/tipidee-config-preprocess.html | 46 +++++++++++++++-- doc/tipidee-config.html | 91 ++++++++++++++++++++++++++++++++-- doc/tipidee.conf.html | 2 +- doc/tipideed.html | 18 +++++++ src/config/confnode.c | 1 - src/config/conftree.c | 2 - src/config/lexparse.c | 1 - src/config/tipidee-config-internal.h | 2 + src/config/tipidee-config-preprocess.c | 37 ++++++++++---- 9 files changed, 177 insertions(+), 23 deletions(-) diff --git a/doc/tipidee-config-preprocess.html b/doc/tipidee-config-preprocess.html index 86fb22e..9b6ea38 100644 --- a/doc/tipidee-config-preprocess.html +++ b/doc/tipidee-config-preprocess.html @@ -49,17 +49,55 @@ appropriately included files.
  • tipidee-config-preprocess then exits 0.
  • +

    Exit codes

    +

    - TODO: write this page. +If tipidee-config-preprocess exits nonzero, +tipidee-config will immediately exit +with the same error code.

    -

    Exit codes

    - -

    Options

    +
    +
    0
    success
    +
    1
    syntax error
    +
    2
    invalid inclusion (cycle or unauthorized duplicate)
    +
    100
    wrong usage
    +
    111
    system call failed
    +

    Detailed operation

    + +

    Notes

    + + diff --git a/doc/tipidee-config.html b/doc/tipidee-config.html index d6a6f56..66953ab 100644 --- a/doc/tipidee-config.html +++ b/doc/tipidee-config.html @@ -27,7 +27,7 @@ web server.

    Interface

    -     tipidee-config [ -i ifile ] [ -o ofile ]
    +     tipidee-config [ -i textfile ] [ -o cdbfile ] [ -m mode ]
     
    -

    - TODO: write this page. -

    -

    Exit codes

    +
    +
    0
    success
    +
    1
    syntax error
    +
    2
    invalid inclusion (cycle or unauthorized duplicate)
    +
    100
    wrong usage
    +
    111
    system call failed
    +
    129+
    tipidee-config-preprocess was killed
    +
    +

    Options

    +
    +
    -i textfile
    +
    Use textfile as input instead of /etc/tipidee.conf
    +
    -o cdbfile
    +
    Use cdbfile as output instead of /etc/tipidee.conf.cdb. +You can then use the -f cdbfile option to +tipideed.
    +
    -m mode
    +
    Create the output file with permissions mode (given in octal). +Default is 0644. Note that the output file should be readable +by the user tipideed is started as. If +tipideed is started as root and drops its privileges +itself, the file can be made private.
    +
    +

    Detailed operation

    +
      +
    • tipidee-config spawns a +tipidee-config-preprocess helper +that reads /etc/tipidee.conf, takes care of all the inclusions, and +feeds it a single stream of data. If +tipidee-config-preprocess dies +with a nonzero exit code at any point, tipidee-config exits with the same +error code, or 128 plus the signal number if +tipidee-config-preprocess was +killed by a signal.
    • +
    • It reads the data and parses it, expecting it to follow the +/etc/tipidee.conf file format.
    • + On failure, it exits nonzero with an error message. +
    • It supplies sane defaults for configuration values that have not +been provided.
    • +
    • It writes the data as a cdb file, +/etc/tipidee.conf.cdb. A previously existing file is replaced +atomically.
    • +
    • Running instances of tipideed will keep +using the old /etc/tipidee.conf.cdb data until their connection is closed; +new instances will use the new one.
    • +
    +

    Notes

    +
      +
    • It is by design that tipidee uses this unconventional "compile the +configuration file" approach. There are several benefits to it: +
        +
      • Parsing a configuration file is not very efficient. Every instance of +tipideed would have to do it on startup, and +there is an instance of tipideed for every +HTTP connection. Pre-parsing the configuration makes the initial server +response faster.
      • +
      • Data parsed by tipideed needs to use +private dirty memory for every instance, even if the data is +static — and that means incompressible RAM. By contrast, a cdb file +is mapped read-only, so its pages are shared clean, which means it's +essentially free.
      • +
      • tipideed is exposed to the network. You +want to its attack surface to be as small as possible. Taking the parsing code +out of it goes a long way — admittedly, having to parse HTTP in the +first place is more attack surface than a simple config file can ever hope +to be, but every little bit helps.
      • +
      • Run time is the worst time to detect errors. Nobody wants their +service to go down because Bob edited the live config file and made a typo. +Having the parsing done offline prevents that: tipidee-config +doubles as a syntax checker, and when it runs successfully, you know the +service will pick up the new config and be fine.
      • +
      • In general, decoupling the live configuration, which is +the one used by live services (here, /etc/tipidee.conf.cdb), from +the working configuration, which is the one that humans can +tinker with (here, /etc/tipidee.conf), is a good idea. Don't +touch production until you're ready to flip the switch atomically; +tipidee-config is the switch.
      • +
    • +
    + +

    + Just remember to run tipidee-config whenever you make +a modification to your config file. It not insurmountable. +

    + diff --git a/doc/tipidee.conf.html b/doc/tipidee.conf.html index eb2b7f4..64e3d30 100644 --- a/doc/tipidee.conf.html +++ b/doc/tipidee.conf.html @@ -366,7 +366,7 @@ Except for domain, they can only be used after a domain direct

      - domain is a special directive in that it is stateful. Instead of +
    • domain is a special directive in that it is stateful. Instead of having a direct effect on the configuration, it merely defines the domain that the next local directives will apply to. domain example.com means that a subsequent cgi /cgi-bin/ line will declare that a resource diff --git a/doc/tipideed.html b/doc/tipideed.html index 97102c5..ce8f5e5 100644 --- a/doc/tipideed.html +++ b/doc/tipideed.html @@ -48,6 +48,18 @@ current working directory, one subdirectory for every domain it hosts.
    • Exit codes

      +
      +
      0
      clean exit. The client closed the connection after a stream of +HTTP exchanges.
      +
      100
      bad usage. tipideed has been run in an incorrect way: bad command +line options, or missing environment variables, etc.
      +
      101
      cannot happen. This signals a bug in tipideed, and comes with an +error message asking you to report the bug. Please do so.
      +
      111
      system call failed. If this happens while serving a request, +tipideed likely has sent a 500 (Internal Server Error) response to the +client before exiting.
      +
      +

      Environment variables

      Options

      @@ -56,5 +68,11 @@ current working directory, one subdirectory for every domain it hosts.

      Notes

      +
        +
      • tipideed is pronounced tipi-deed. You can also say +tipi-dee-dee, but only if you're the type of person who says +PC computer, NIC card or ATM machine.
      • +
      + diff --git a/src/config/confnode.c b/src/config/confnode.c index 758e79d..2d5aeea 100644 --- a/src/config/confnode.c +++ b/src/config/confnode.c @@ -8,7 +8,6 @@ #include "tipidee-config-internal.h" -#define dienomem() strerr_diefu1sys(111, "stralloc_catb") #define diestorage() strerr_diefu2x(100, "add node to configuration tree", ": too much data") #define diefilepos() strerr_diefu2x(100, "add node to configuration tree", ": file too large") diff --git a/src/config/conftree.c b/src/config/conftree.c index fc0b5bc..4eac28e 100644 --- a/src/config/conftree.c +++ b/src/config/conftree.c @@ -11,8 +11,6 @@ #include "tipidee-config-internal.h" -#define dienomem() strerr_diefu1sys(111, "stralloc_catb") - static void *confnode_dtok (uint32_t d, void *data) { return g.storage.s + GENSETDYN_P(confnode, (gensetdyn *)data, d)->key ; diff --git a/src/config/lexparse.c b/src/config/lexparse.c index da9d7f5..99693a5 100644 --- a/src/config/lexparse.c +++ b/src/config/lexparse.c @@ -15,7 +15,6 @@ #include #include "tipidee-config-internal.h" -#define dienomem() strerr_diefu1sys(111, "stralloc_catb") #define dietoobig() strerr_diefu1sys(100, "read configuration") typedef struct mdt_s mdt, *mdt_ref ; diff --git a/src/config/tipidee-config-internal.h b/src/config/tipidee-config-internal.h index 154c6ff..7ffee8a 100644 --- a/src/config/tipidee-config-internal.h +++ b/src/config/tipidee-config-internal.h @@ -10,6 +10,8 @@ #include #include +#define dienomem() strerr_diefu1sys(111, "stralloc_catb") + typedef struct confnode_s confnode, *confnode_ref ; struct confnode_s { diff --git a/src/config/tipidee-config-preprocess.c b/src/config/tipidee-config-preprocess.c index 03b54f1..a5a47c2 100644 --- a/src/config/tipidee-config-preprocess.c +++ b/src/config/tipidee-config-preprocess.c @@ -149,23 +149,22 @@ static void includefromhere (char const *file) uint32_t d ; uint32_t line = 1 ; char buf[4096] ; - char linefmt[UINT32_FMT] = "1" ; unsigned char state = 0 ; if (!stralloc_catb(&namesa, "\004", 1) || sarealpath(&namesa, file) < 0 || !stralloc_0(&namesa)) dienomem() ; if (avltree_search(&namemap, namesa.s + namesabase + 1, &d)) { if (namesa.s[d] & 0x04) - strerr_dief3x(3, "file ", namesa.s + namesabase + 1, " is included in a cycle") ; + strerr_dief3x(2, "file ", namesa.s + namesabase + 1, " is included in a cycle") ; if (!(namesa.s[d] & 0x02)) - strerr_dief3x(3, "file ", namesa.s + namesabase + 1, " is included twice but does not declare !included: unique or !included: multiple") ; + strerr_dief3x(2, "file ", namesa.s + namesabase + 1, " is included twice but does not declare !included: unique or !included: multiple") ; namesa.len = namesabase ; if (namesa.s[d] & 0x01) return ; } else { if (namesabase > UINT32_MAX) - strerr_dief3x(3, "in ", namesa.s + d + 1, ": too many, too long filenames") ; + strerr_dief3x(100, "in ", namesa.s + d + 1, ": too many, too long filenames") ; d = namesabase ; if (!avltree_insert(&namemap, d)) dienomem() ; } @@ -197,7 +196,11 @@ static void includefromhere (char const *file) if (!stralloc_0(&sa)) dienomem() ; cmd = idcmd(sa.s + sastart) ; if (cmd == -1) - strerr_dief6x(2, "in ", namesa.s + d + 1, " line ", linefmt, ": unrecognized directive: ", sa.s + sastart) ; + { + char linefmt[UINT32_FMT] ; + linefmt[uint32_fmt(linefmt, line)] = 0 ; + strerr_dief6x(1, "in ", namesa.s + d + 1, " line ", linefmt, ": unrecognized directive: ", sa.s + sastart) ; + } sa.len = sastart ; } if (what & 0x0080) @@ -207,17 +210,28 @@ static void includefromhere (char const *file) { case 2 : if (namesa.s[d] & 2) - strerr_dief5x(3, "in ", namesa.s + d + 1, " line ", linefmt, ": extra !included: directive") ; + { + char linefmt[UINT32_FMT] ; + linefmt[uint32_fmt(linefmt, line)] = 0 ; + strerr_dief5x(1, "in ", namesa.s + d + 1, " line ", linefmt, ": extra !included: directive") ; + } if (!strcmp(sa.s + sastart, "unique")) namesa.s[d] |= 3 ; else if (!strcmp(sa.s + sastart, "multiple")) namesa.s[d] |= 2 ; - else strerr_dief6x(3, "in ", namesa.s + d + 1, " line ", linefmt, ": invalid !included: argument: ", sa.s + sastart) ; + else + { + char linefmt[UINT32_FMT] ; + linefmt[uint32_fmt(linefmt, line)] = 0 ; + strerr_dief6x(1, "in ", namesa.s + d + 1, " line ", linefmt, ": invalid !included: argument: ", sa.s + sastart) ; + } break ; case 1 : case 0 : { int fdhere = open2(".", O_RDONLY | O_DIRECTORY) ; + char linefmt[UINT32_FMT] ; if (fdhere == -1) strerr_dief3sys(111, "in ", namesa.s + d + 1, ": unable to open base directory: ") ; + linefmt[uint32_fmt(linefmt, line)] = 0 ; if (cmd & 1) { if (chdir(sa.s + sastart) == -1) @@ -239,9 +253,14 @@ static void includefromhere (char const *file) } sa.len = sastart ; } - if (c == '\n' && state <= 8) linefmt[uint32_fmt(linefmt, ++line)] = 0 ; + if (c == '\n' && state <= 8) line++ ; + } + if (state > 8) + { + char linefmt[UINT32_FMT] ; + linefmt[uint32_fmt(linefmt, line)] = 0 ; + strerr_dief5x(1, "in ", namesa.s + d + 1, " line ", linefmt, ": syntax error: invalid ! line") ; } - if (state > 8) strerr_dief5x(2, "in ", namesa.s + d + 1, " line ", linefmt, ": syntax error: invalid ! line") ; fd_close(fd) ; sa.len = sabase ; namesa.s[d] &= ~0x04 ; -- cgit v1.3.1