]> mj.ucw.cz Git - libucw.git/commitdiff
LibUCW: Added `ucw-' prefix to utils.
authorPavel Charvat <pchar@ucw.cz>
Fri, 6 Dec 2013 22:32:14 +0000 (23:32 +0100)
committerPavel Charvat <pchar@ucw.cz>
Fri, 6 Dec 2013 22:32:14 +0000 (23:32 +0100)
25 files changed:
ucw/daemon.h
ucw/default.cfg
ucw/doc/basecode.txt
ucw/doc/daemon.txt
ucw/shell/Makefile
ucw/shell/config.c [deleted file]
ucw/shell/config.t
ucw/shell/libucw.sh
ucw/shell/logger.c [deleted file]
ucw/shell/logoutput.c [deleted file]
ucw/shell/ucw-config.c [new file with mode: 0644]
ucw/shell/ucw-logger.c [new file with mode: 0644]
ucw/shell/ucw-logoutput.c [new file with mode: 0644]
ucw/utils/Makefile
ucw/utils/basecode.c [deleted file]
ucw/utils/basecode.t
ucw/utils/daemon-control.c [deleted file]
ucw/utils/daemon-helper.c [deleted file]
ucw/utils/rotate-log.pl [deleted file]
ucw/utils/ucw-basecode.c [new file with mode: 0644]
ucw/utils/ucw-daemon-control.c [new file with mode: 0644]
ucw/utils/ucw-daemon-helper.c [new file with mode: 0644]
ucw/utils/ucw-rotate-log.pl [new file with mode: 0644]
ucw/utils/ucw-urltool.c [new file with mode: 0644]
ucw/utils/urltool.c [deleted file]

index c5beacc060ca8186171e91fad6a9ef3b3878dffa..303e8c8458b6ce074cf75e9f22a0580e073ba26f 100644 (file)
@@ -95,7 +95,7 @@ enum daemon_control_action {
  **/
 enum daemon_control_status daemon_control(struct daemon_control_params *dc);
 
-// XXX: Also used as exit codes of the daemon-control utility.
+// XXX: Also used as exit codes of the ucw-daemon-control utility.
 enum daemon_control_status {
   DAEMON_STATUS_OK = 0,
   DAEMON_STATUS_ALREADY_DONE = 100,
index 7a2236da5fa4510b37d3eb4ef29d724c6857f88b..ec8feabb3ad87ecf87c8a4cce14cda95cb484add 100644 (file)
@@ -44,7 +44,7 @@ Set("CONFIG_UCW_SHELL_UTILS" => 1);
 # Include utilities
 Set("CONFIG_UCW_UTILS" => 1);
 
-# Include obsolete daemon-helper utility
+# Include obsolete ucw-daemon-helper utility
 UnSet("CONFIG_UCW_OBSOLETE_DAEMON_HELPER");
 
 # Default configuration file
index 6741470e3de7d730a16f10af93a73cad456f9036..ca2aa86eefb6f16578e573de0182375e02600f5e 100644 (file)
@@ -58,7 +58,7 @@ way as base64.
 The basecode utility
 --------------------
 You can use the encoding/decoding routines from command line, trough
-`basecode` command. You have to specify the operation by a command
+`ucw-basecode` command. You have to specify the operation by a command
 line argument and give it the data on standard input. The arguments
 are:
 
index a58c92f4065b500de1b4deb041c55d54484e1c7f..6077e6032e345bb7ef985c19919c4018a34465a2 100644 (file)
@@ -58,7 +58,7 @@ since there can be multiple instances of the daemon running simultaneously.
 
 We therefore recommend the following daemon control protocol, which prevents all such
 race conditions. Its implementation is available in form of the daemon_control() library
-function or the `daemon-control` stand-alone utility.
+function or the `ucw-daemon-control` stand-alone utility.
 
 * There exist two files:
 ** PID file (usually `/var/run/daemon.pid`), which contains the PID of the daemon
index 62ecb96891900f061d4db540dd0ac514a8f26a34..96491f73f52d16430fd27a96bb642b13129b995b 100644 (file)
@@ -1,17 +1,17 @@
 # Support routines for shell scripts
 
 DIRS+=ucw/shell
-UCW_SHELL_PROGS=$(addprefix $(o)/ucw/shell/,config logger logoutput)
+UCW_SHELL_PROGS=$(addprefix $(o)/ucw/shell/ucw-,config logger logoutput)
 PROGS+=$(UCW_SHELL_PROGS)
 DATAFILES+=$(o)/ucw/shell/libucw.sh
 
-$(o)/ucw/shell/config: $(o)/ucw/shell/config.o $(LIBUCW)
-$(o)/ucw/shell/logger: $(o)/ucw/shell/logger.o $(LIBUCW)
-$(o)/ucw/shell/logoutput: $(o)/ucw/shell/logoutput.o $(LIBUCW)
+$(o)/ucw/shell/ucw-config: $(o)/ucw/shell/ucw-config.o $(LIBUCW)
+$(o)/ucw/shell/ucw-logger: $(o)/ucw/shell/ucw-logger.o $(LIBUCW)
+$(o)/ucw/shell/ucw-logoutput: $(o)/ucw/shell/ucw-logoutput.o $(LIBUCW)
 
 TESTS+=$(addprefix $(o)/ucw/shell/,config.test)
 
-$(o)/ucw/shell/config.test: $(o)/ucw/shell/config
+$(o)/ucw/shell/config.test: $(o)/ucw/shell/ucw-config
 
 INSTALL_TARGETS+=install-ucw-shell
 install-ucw-shell:
diff --git a/ucw/shell/config.c b/ucw/shell/config.c
deleted file mode 100644 (file)
index 780ff79..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- *     UCW Library -- Shell Interface to Configuration Files
- *
- *     (c) 2002--2005 Martin Mares <mj@ucw.cz>
- *     (c) 2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2006 Pavel Charvat <pchar@ucw.cz>
- *
- *     Once we were using this beautiful Shell version, but it turned out
- *     that it doesn't work with nested config files:
- *
- *             eval `sed <cf/sherlock '/^#/d;/^ *$/d;s/ \+$//;
- *             h;s@[^  ]*@@;x;s@[      ].*@@;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G;s/\n//;
- *             /^\[SECTION\]/,/^\[/ {; /^[A-Z]/ { s/^\([^      ]\+\)[  ]*\(.*\)$/SH_\1="\2"/; p; }; };
- *             d;'`
- *
- *     This software may be freely distributed and used according to the terms
- *     of the GNU Lesser General Public License.
- */
-
-#include <ucw/lib.h>
-#include <ucw/conf.h>
-#include <ucw/getopt.h>
-#include <ucw/conf-internal.h>
-#include <ucw/clists.h>
-#include <ucw/mempool.h>
-#include <ucw/chartype.h>
-#include <ucw/bbuf.h>
-#include <ucw/string.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <alloca.h>
-
-static void
-help(void)
-{
-  fputs("\n\
-Usage: config [-C<configfile>] [-S<section>.<option>=<value>] <sections>\n\
-\n\
-<sections>\t<section>[;<sections>]\n\
-<section>\t[!]<name>{[<items>]}\n\
-<items>\t\t[-]<item>[;<items>]\n\
-<item>\t\t<static> | <array> | <list>\n\
-<static>\t<type><name>[=<value>]\n\
-<list>\t\t@<name>{[<items>]}\n\
-<array>\t\t<type><name><left-bracket>[<number>]<right-bracket>\n\
-<value>\t\t[a-zA-Z0-9.-/]* | 'string without single quotes'<value> | \"c-like string\"<value>\n\
-\n\
-Types:\n\
-<empty>\t\tString\n\
-#\t\t32-bit integer\n\
-##\t\t64-bit integer\n\
-$\t\tFloating point number\n\
-\n\
-Modifiers:\n\
-!\t\tReport unknown items as errors\n\
--\t\tDo not dump item's value\n\
-", stderr);
-  exit(1);
-}
-
-union value {
-  void *v_ptr;
-  int v_int;
-  u64 v_u64;
-  double v_double;
-  clist list;
-};
-
-#define FLAG_HIDE              0x1
-#define FLAG_NO_UNKNOWN                0x2
-
-struct item {
-  cnode node;
-  uns flags;
-  struct cf_item cf;
-  union value value;
-  uns index;
-};
-
-struct section {
-  struct item item;
-  clist list;
-  uns count;
-  uns size;
-};
-
-static struct mempool *pool;
-static clist sections;
-static byte *pos;
-
-static void
-parse_white(void)
-{
-  while (Cspace(*pos))
-    pos++;
-}
-
-static void
-parse_char(byte c)
-{
-  if (*pos++ != c)
-    die("Missing '%c'", c);
-}
-
-static byte *
-parse_name(void)
-{
-  byte *name = pos;
-  while (Cword(*pos))
-    pos++;
-  uns len = pos - name;
-  if (!len)
-    die("Expected item/section name");
-  byte *buf = mp_alloc(pool, len + 1);
-  memcpy(buf, name, len);
-  buf[len] = 0;
-  return buf;
-}
-
-static void
-parse_section(struct section *section)
-{
-#define TRY(x) do{byte *_err=(x); if (_err) die(_err); }while(0)
-  for (uns sep = 0; ; sep = 1)
-    {
-      parse_white();
-      if (!*pos || *pos == '}')
-       break;
-      if (sep)
-       parse_char(';');
-      parse_white();
-
-      struct item *item;
-
-      if (*pos == '@')
-        {
-         pos++;
-         struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
-         sec->size = sizeof(cnode);
-         clist_init(&sec->list);
-         item = &sec->item;
-         item->cf.name = parse_name();
-         item->cf.cls = CC_LIST;
-         item->cf.number = 1;
-         parse_white();
-         parse_char('{');
-         parse_section(sec);
-         parse_char('}');
-       }
-      else
-        {
-         item = mp_alloc_zero(pool, sizeof(*item));
-         if (*pos == '-')
-           {
-             item->flags |= FLAG_HIDE;
-             pos++;
-           }
-         item->cf.cls = CC_STATIC;
-         item->cf.number = 1;
-         switch (*pos)
-           {
-             case '#':
-               if (*++pos == '#')
-                 {
-                   pos++;
-                   item->cf.type = CT_U64;
-                 }
-               else
-                 item->cf.type = CT_INT;
-               break;
-             case '$':
-               pos++;
-               item->cf.type = CT_DOUBLE;
-               break;
-             default:
-               if (!Cword(*pos))
-                 die("Invalid type syntax");
-               item->cf.type = CT_STRING;
-               break;
-           }
-         parse_white();
-         item->cf.name = parse_name();
-         parse_white();
-         if (*pos == '[')
-           {
-             pos++;
-             parse_white();
-             item->cf.cls = CC_DYNAMIC;
-             byte *num = pos;
-             while (*pos && *pos != ']')
-               pos++;
-             if (!*pos)
-               die("Missing ']'");
-             *pos++ = 0;
-             if (!*num)
-               item->cf.number = CF_ANY_NUM;
-             else
-               {
-                 int inum;
-                 TRY(cf_parse_int(num, &inum));
-                 if (!inum)
-                   die("Invalid array length");
-                 item->cf.number = inum;
-               }
-             parse_white();
-           }
-         if (*pos == '=')
-           {
-             pos++;
-             parse_white();
-             if (section->item.cf.cls == CC_LIST)
-               die("List items can not have default values");
-             if (item->cf.cls == CC_DYNAMIC)
-               die("Arrays can not have default values");
-             byte *def = pos, *d = def;
-             while (*pos != ';' && *pos != '}' && !Cspace(*pos))
-               {
-                 if (*pos == '\'')
-                   {
-                     pos++;
-                     while (*pos != '\'')
-                       {
-                         if (!*pos)
-                           die("Unterminated string");
-                         *d++ = *pos++;
-                       }
-                     pos++;
-                   }
-                 else if (*pos == '"')
-                   {
-                     pos++;
-                     byte *start = d;
-                     uns esc = 0;
-                     while (*pos != '"' || esc)
-                       {
-                         if (!*pos)
-                           die("Unterminated string");
-                         if (*pos == '\\')
-                           esc ^= 1;
-                         else
-                           esc = 0;
-                         *d++ = *pos++;
-                       }
-                     pos++;
-                     *d = 0;
-                     d = str_unesc(start, start);
-                   }
-                 else
-                   *d++ = *pos++;
-               }
-             uns len = d - def;
-             byte *buf = mp_alloc(pool, len + 1);
-             memcpy(buf, def, len);
-             buf[len] = 0;
-             switch (item->cf.type)
-               {
-                 case CT_STRING:
-                   item->value.v_ptr = buf;
-                   break;
-                 case CT_INT:
-                   TRY(cf_parse_int(buf, &item->value.v_int));
-                   break;
-                 case CT_U64:
-                   TRY(cf_parse_u64(buf, &item->value.v_u64));
-                   break;
-                 case CT_DOUBLE:
-                   TRY(cf_parse_double(buf, &item->value.v_double));
-                   break;
-                 default:
-                   ASSERT(0);
-               }
-           }
-       }
-      if (section->item.cf.cls == CC_LIST)
-        {
-          item->cf.ptr = (void *)(uintptr_t)section->size;
-          section->size += sizeof(union value);
-        }
-      else
-        item->cf.ptr = &item->value;
-      clist_add_tail(&section->list, &item->node);
-      section->count++;
-    }
-#undef TRY
-}
-
-static void
-parse_outer(void)
-{
-  for (uns sep = 0; ; sep = 1)
-    {
-      parse_white();
-      if (!*pos)
-       break;
-      if (sep)
-       parse_char(';');
-      parse_white();
-      struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
-      if (*pos == '!')
-        {
-         pos++;
-         sec->item.flags |= FLAG_NO_UNKNOWN;
-       }
-      sec->item.cf.name = parse_name();
-      parse_white();
-      parse_char('{');
-      clist_add_tail(&sections, &sec->item.node);
-      clist_init(&sec->list);
-      parse_section(sec);
-      parse_char('}');
-    }
-}
-
-static struct cf_section *
-generate_section(struct section *section)
-{
-  struct cf_section *sec = mp_alloc_zero(pool, sizeof(*sec));
-  if (section->item.cf.cls == CC_LIST)
-    sec->size = section->size;
-  struct cf_item *c = sec->cfg = mp_alloc_zero(pool, sizeof(struct cf_item) * (section->count + 1));
-  CLIST_FOR_EACH(struct item *, item, section->list)
-    {
-      *c = item->cf;
-      if (c->cls == CC_LIST)
-       c->u.sec = generate_section((struct section *)item);
-      c++;
-    }
-  c->cls = CC_END;
-  return sec;
-}
-
-static bb_t path;
-
-static void
-dump_value(uns array, struct item *item, void *v)
-{
-  byte buf[128], *value = buf;
-  if (!array)
-    printf("CF_%s_%s='", path.ptr, item->cf.name);
-  else
-    printf("CF_%s_%s[%u]='", path.ptr, item->cf.name, ++item->index);
-  switch (item->cf.type)
-    {
-      case CT_INT:
-        sprintf(buf, "%d", *(int *)v);
-        break;
-      case CT_U64:
-        sprintf(buf, "%llu", (long long) *(u64 *)v);
-       break;
-      case CT_DOUBLE:
-       sprintf(buf, "%g", *(double *)v);
-       break;
-      case CT_STRING:
-        if (*(byte **)v)
-          value = *(byte **)v;
-        else
-          *value = 0;
-        break;
-      default:
-        ASSERT(0);
-    }
-  while (*value) {
-    if (*value == '\'')
-      printf("'\\''");
-    else
-      putchar(*value);
-    value++;
-  }
-  printf("'\n");
-}
-
-static void
-dump_item(struct item *item, void *ptr, uns path_len)
-{
-  if (item->flags & FLAG_HIDE)
-    return;
-  byte *val = (byte *)((uintptr_t)ptr + (uintptr_t)item->cf.ptr);
-  if (item->cf.cls == CC_LIST)
-    {
-      uns len = strlen(item->cf.name);
-      bb_grow(&path, path_len + len + 1);
-      path.ptr[path_len] = '_';
-      memcpy(path.ptr + path_len + 1, item->cf.name, len);
-      CLIST_FOR_EACH(cnode *, ptr2, *(clist *)val)
-        CLIST_FOR_EACH(struct item *, item2, ((struct section *)item)->list)
-          dump_item(item2, ptr2, path_len + len + 1);
-    }
-  else
-    {
-      bb_grow(&path, path_len + 1)[path_len] = 0;
-      if (item->cf.cls == CC_STATIC)
-       dump_value(!!ptr, item, val);
-      else
-        {
-         val = *(void **)val;
-         uns len = DARY_LEN(val);
-         uns size = cf_type_size(item->cf.type, NULL);
-         for (uns i = 0; i < len; i++, val += size)
-           dump_value(1, item, val);
-       }
-    }
-}
-
-int main(int argc, char **argv)
-{
-  log_init("config");
-  if (argc < 2)
-    help();
-  pos = argv[argc - 1];
-  argv[argc - 1] = NULL;
-
-  pool = mp_new(0x1000);
-  clist_init(&sections);
-  parse_outer();
-  CLIST_FOR_EACH(struct section *, sec, sections)
-    cf_declare_section(sec->item.cf.name, generate_section(sec), !(sec->item.flags & FLAG_NO_UNKNOWN));
-
-  if (cf_getopt(argc - 1, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
-    help();
-
-  bb_init(&path);
-  CLIST_FOR_EACH(struct section *, section, sections)
-    {
-      uns len = strlen(section->item.cf.name);
-      memcpy(bb_grow(&path, len), section->item.cf.name, len);
-      CLIST_FOR_EACH(struct item *, item, section->list)
-        dump_item(item, NULL, len);
-    }
-  bb_done(&path);
-
-  return 0;
-}
-
index a90f274461965aafc20d0ca12d8052619ddd930d..fdcfc854fa96b7b75c254c32d104c6f582f2d430 100644 (file)
@@ -1,6 +1,6 @@
 # Tests for configuration parser
 
-Run:   ../obj/ucw/shell/config -C/dev/null -S 'sec1{int1=23; long1=1234567812345678; long2=4321; str1="s1"; str2="s2"}' 'sec1 {#int1; ##long1; -str1; str2; #int2=123; ##long2=1234; #int3=0x10; #int4; $dbl1=001.100; $dbl2}; sec2{str3}'
+Run:   ../obj/ucw/shell/ucw-config -C/dev/null -S 'sec1{int1=23; long1=1234567812345678; long2=4321; str1="s1"; str2="s2"}' 'sec1 {#int1; ##long1; -str1; str2; #int2=123; ##long2=1234; #int3=0x10; #int4; $dbl1=001.100; $dbl2}; sec2{str3}'
 Out:   CF_sec1_int1='23'
        CF_sec1_long1='1234567812345678'
        CF_sec1_str2='s2'
@@ -12,13 +12,13 @@ Out:        CF_sec1_int1='23'
        CF_sec1_dbl2='0'
        CF_sec2_str3=''
 
-Run:   ../obj/ucw/shell/config -C/dev/null -S 'sec1{list1 1 a1 b1; list1:clear; list1 2 a2 b2 3 a3 b3}' 'sec1 {@list1 {#int1; str1; -str2}}'
+Run:   ../obj/ucw/shell/ucw-config -C/dev/null -S 'sec1{list1 1 a1 b1; list1:clear; list1 2 a2 b2 3 a3 b3}' 'sec1 {@list1 {#int1; str1; -str2}}'
 Out:   CF_sec1_list1_int1[1]='2'
        CF_sec1_list1_str1[1]='a2'
        CF_sec1_list1_int1[2]='3'
        CF_sec1_list1_str1[2]='a3'
 
-Run:   ../obj/ucw/shell/config -C/dev/null -S 'sec1{ar1 a b c d; ar1 a b c; ar2 1 2; ar3 1.1}' 'sec1 {ar1[]; #ar2[2]; $ar3[-2]}'
+Run:   ../obj/ucw/shell/ucw-config -C/dev/null -S 'sec1{ar1 a b c d; ar1 a b c; ar2 1 2; ar3 1.1}' 'sec1 {ar1[]; #ar2[2]; $ar3[-2]}'
 Out:   CF_sec1_ar1[1]='a'
        CF_sec1_ar1[2]='b'
        CF_sec1_ar1[3]='c'
@@ -26,7 +26,7 @@ Out:  CF_sec1_ar1[1]='a'
        CF_sec1_ar2[2]='2'
        CF_sec1_ar3[1]='1.1'
 
-Run:   ../obj/ucw/shell/config -C/dev/null -S 'sec1{list1 {str1=1; list2=a b c}; list1 {str1=2; list2=d e}}' 'sec1 {@list1 {str1; @list2{str2}}}'
+Run:   ../obj/ucw/shell/ucw-config -C/dev/null -S 'sec1{list1 {str1=1; list2=a b c}; list1 {str1=2; list2=d e}}' 'sec1 {@list1 {str1; @list2{str2}}}'
 Out:   CF_sec1_list1_str1[1]='1'
        CF_sec1_list1_list2_str2[1]='a'
        CF_sec1_list1_list2_str2[2]='b'
@@ -35,5 +35,5 @@ Out:  CF_sec1_list1_str1[1]='1'
        CF_sec1_list1_list2_str2[4]='d'
        CF_sec1_list1_list2_str2[5]='e'
 
-Run:   ../obj/ucw/shell/config -C/dev/null 'sec{str=a'\''b"c'\''d"\\e'\''f"g}'
+Run:   ../obj/ucw/shell/ucw-config -C/dev/null 'sec{str=a'\''b"c'\''d"\\e'\''f"g}'
 Out:   CF_sec_str='ab"cd\e'\''fg'
index b02230cf85cdf5dec3c5421fc62eacc71dc8ec0f..143e431e2f5ac687ebbe204830b8c31d80a967a3 100644 (file)
@@ -17,26 +17,26 @@ done
 
 function log # msg
 {
-       bin/logger $UCW_PROGNAME I "$1"
+       bin/ucw-logger $UCW_PROGNAME I "$1"
 }
 
 function errlog # msg
 {
-       bin/logger $UCW_PROGNAME E "$1"
+       bin/ucw-logger $UCW_PROGNAME E "$1"
 }
 
 function warnlog # msg
 {
-       bin/logger $UCW_PROGNAME E "$1"
+       bin/ucw-logger $UCW_PROGNAME E "$1"
 }
 
 function die # msg
 {
-       bin/logger $UCW_PROGNAME ! "$1"
+       bin/ucw-logger $UCW_PROGNAME ! "$1"
        exit 1
 }
 
 function parse-config # section vars...
 {
-       eval `bin/config$UCW_CF "$@"`
+       eval `bin/ucw-config$UCW_CF "$@"`
 }
diff --git a/ucw/shell/logger.c b/ucw/shell/logger.c
deleted file mode 100644 (file)
index 4cb7687..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *     UCW Library Utilities -- A Simple Logger for use in shell scripts
- *
- *     (c) 2001--2009 Martin Mares <mj@ucw.cz>
- *
- *     This software may be freely distributed and used according to the terms
- *     of the GNU Lesser General Public License.
- */
-
-#include <ucw/lib.h>
-#include <ucw/log.h>
-
-#include <stdio.h>
-#include <string.h>
-
-int
-main(int argc, char **argv)
-{
-  byte buf[1024], *c;
-
-  log_init("logger");
-  if (argc < 3 || argc > 4 || strlen(argv[2]) != 1)
-    die("Usage: logger [<logname>:]<progname> <level> [<text>]");
-  if (c = strchr(argv[1], ':'))
-    {
-      *c++ = 0;
-      log_init(c);
-      log_file(argv[1]);
-    }
-  else
-    log_init(argv[1]);
-
-  uns level = 0;
-  while (level < L_MAX && LS_LEVEL_LETTER(level) != argv[2][0])
-    level++;
-  if (level >= L_MAX)
-    die("Unknown logging level `%s'", argv[2]);
-
-  if (argc > 3)
-    msg(level, argv[3]);
-  else
-    while (fgets(buf, sizeof(buf), stdin))
-      {
-       c = strchr(buf, '\n');
-       if (c)
-         *c = 0;
-       msg(level, buf);
-      }
-  return 0;
-}
diff --git a/ucw/shell/logoutput.c b/ucw/shell/logoutput.c
deleted file mode 100644 (file)
index 7b9ed80..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- *     UCW Library Utilities -- A Simple Logger for use in shell scripts
- *
- *     (c) 2001--2009 Martin Mares <mj@ucw.cz>
- *      (c) 2011 Tomas Ebenlendr <ebik@ucw.cz>
- *
- *     This software may be freely distributed and used according to the terms
- *     of the GNU Lesser General Public License.
- */
-
-#undef LOCAL_DEBUG
-
-#include <ucw/lib.h>
-#include <ucw/log.h>
-#include <ucw/mainloop.h>
-#include <ucw/clists.h>
-#include <ucw/getopt.h>
-#include <ucw/conf.h>
-#include <ucw/process.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <errno.h>
-
-static uns max_line = 1024;
-static int launch_finish_messages = 1;
-static int nonzero_status_message = 1;
-
-static struct cf_section cfsec_logoutput = {
-  CF_ITEMS {
-    CF_UNS("LineMax", &max_line),
-    CF_END
-  }
-};
-
-static clist filedescriptors;
-
-struct fds {
-  cnode node;
-  int pipe[2];
-  int fdnum;
-  uns level;
-  int long_continue;
-  struct main_rec_io rio;
-};
-
-static void
-close_fd(struct fds *fd)
-{
-  rec_io_del(&fd->rio);
-  close(fd->fdnum);
-  clist_remove(&fd->node);
-  if (clist_empty(&filedescriptors))
-    main_shut_down();
-}
-
-
-static void
-do_msg (struct fds *fd, char *l_msg, int long_continue)
-{
-  msg(fd->level, "%s%s", (fd->long_continue ? "... " : ""), l_msg);
-  fd->long_continue = long_continue;
-}
-
-static uns
-handle_read(struct main_rec_io *r)
-{
-  char buf[max_line + 5];
-  byte *eol = memchr((char *)r->read_rec_start + r->read_prev_avail, '\n', r->read_avail - r->read_prev_avail);
-  if (eol == NULL) {
-    if (r->read_avail >= max_line) {
-      memcpy(buf, r->read_rec_start, max_line);
-      memcpy(buf + max_line, " ...", 5);
-      do_msg(r->data, buf, 1);
-      return max_line;
-    } else
-      return 0;
-  }
-  *eol = 0;
-  byte *b = r->read_rec_start;
-  while ((uns)(eol - b) > max_line) {
-    char cc = b[max_line];
-    b[max_line]=0;
-    do_msg(r->data, b, 1);
-    b[max_line]=cc;
-    b+=max_line;
-  }
-  do_msg(r->data, (char *)b, 0);
-  return eol - r->read_rec_start + 1;
-}
-
-static int
-handle_notify(struct main_rec_io *r, int status)
-{
-  struct fds *fd = r->data;
-  switch (status) {
-    case RIO_ERR_READ:
-    case RIO_EVENT_EOF:
-      if (r->read_avail) {
-        char buf[max_line + 10];
-        memcpy(buf, r->read_rec_start, r->read_avail);
-        memcpy(buf + r->read_avail, " [no eol]", 10);
-        do_msg(r->data, buf, 0);
-      } else if (fd->long_continue) {
-       do_msg(r->data, "[no eol]", 0);
-      }
-      close_fd(fd);
-      return HOOK_DONE;
-    default:
-      ASSERT(0);
-  }
-  return HOOK_IDLE;
-}
-
-
-static void
-add_level_fd(int fdnum, int level)
-{
-  struct fds *fd = xmalloc_zero(sizeof(*fd));
-  fd->level = level;
-  fd->pipe[0] = -1;
-  fd->pipe[1] = -1;
-  fd->fdnum = fdnum;
-  fd->rio.read_handler = handle_read;
-  fd->rio.data = fd;
-  fd->rio.notify_handler = handle_notify;
-  fd->long_continue = 0;
-  clist_add_tail(&filedescriptors, &fd->node);
-}
-
-static int
-xdup(int fd)
-{
-  int rfd = dup(fd);
-  if (rfd == -1)
-    die("Cannot dup(): %m");
-  DBG("  Dup(%i) -> %i", fd, rfd);
-  return rfd;
-}
-
-static int
-xdup2(int fd1, int fd2)
-{
-  int rfd = dup2(fd1, fd2);
-  if (rfd == -1)
-    die("Cannot dup2(): %m");
-  DBG("  Dup2(%i, %i) -> %i", fd1, fd2, rfd);
-  return rfd;
-}
-
-static void
-xdupavoid(int *fd1, int fd2)
-{
-  DBG("Dupavoid: !%i -> %i", fd2, *fd1);
-  int ofd = *fd1;
-  if (ofd == fd2) {
-    *fd1 = xdup(ofd);
-    DBG("  Close: %i", ofd);
-    close(ofd);
-  }
-}
-
-static void
-xdupto(int *fd1, int fd2)
-{
-  DBG("Dupto: %i -> %i", *fd1, fd2);
-  if (*fd1 == fd2)
-    return;
-  DBG("  Close: %i", fd2);
-  close(fd2);
-  xdup2(*fd1, fd2);
-  DBG("  Close: %i", *fd1);
-  close(*fd1);
-  *fd1 = fd2;
-}
-
-static void
-set_cloexec_flag(int fd, int value)
-{
-  int flags = fcntl(fd, F_GETFD, 0);
-  if (flags < 0)
-    die("fcntl(..., F_GETFD, ...) : %m");
-  flags = (value) ? flags | FD_CLOEXEC : flags & ~FD_CLOEXEC;
-  if (fcntl(fd, F_SETFD, flags) < 0)
-    die("fcntl(..., F_SETFD, ...) : %m");
-}
-
-/* The "+" stands for end at first argument (i.e. do not parse options after
-   first argument.) */
-#define MY_SHORT_OPTS "+" CF_SHORT_OPTS "f:n:l:ih"
-const struct option my_long_opts[] = {
-  CF_LONG_OPTS
-  { "help", 0, 0, 'h'},
-  { "input", 0, 0, 'i'},
-  { "logfile", 1, 0, 'f'},
-  { "logname", 1, 0, 'n'},
-  { "descriptor", 1, 0, 'l'},
-  { "nv", 0, 0, 'q'},
-  { "nonverbose", 0, 0, 'q'},
-  { "non-verbose", 0, 0, 'q'},
-  { "non_verbose", 0, 0, 'q'},
-  { "silent", 0, 0, 's'},
-  { NULL, 0, 0, 0}
-};
-
-#undef CF_USAGE_TAB
-#define CF_USAGE_TAB "\t   "
-static char usage[] =
-  "Usage:\n"
-  "logoutput -h|--help\t\t   This help.\n"
-  "logoutput <options> -i|--input\t   Read file descriptors and log them.\n"
-  "\t\t\t\t   default: stdin at level I.\n"
-  "logoutput <opts> [--] <cmd> [arguments for cmd ...]\n"
-  "\t\t\t\t   Open file descriptors for writing for command <cmd> and log them.\n"
-  "\t\t\t\t   default: stdout:I, stderr:W.\n\n"
-  "Options:\n"
-  CF_USAGE
-  "-n, --logname <name>\t\t   Use <name> as program name in logs.\n"
-  "-l, --descriptor <fdnum>:<level>   Open file descriptor <fdnum> and log it at level <level> (replaces defaults).\n"
-  "-f, --logfile <logfile>\t\t   Log to file <logfile>.\n"
-  "-q, --nv, --nonverbose\t\t   Suppress launching and successful finish messages.\n"
-  "-s, --silent\t\t\t   Suppress launching message and all finish messages.\n"
-  "\t\t\t\t   (i.e., no warning if it terminates with a nonzero exit code or by a signal)\n";
-
-int
-main(int argc, char **argv)
-{
-  int register_default = 1;
-  int loginput = 0;
-  char *logfile = NULL;
-  char *logname = NULL;
-  struct fds *stderrfd = NULL;
-  int help = 0;
-
-  log_init("logoutput");
-  clist_init(&filedescriptors);
-  cf_declare_section("LogOutput", &cfsec_logoutput, 0);
-
-  while (1) {
-    int opt = cf_getopt(argc, argv, MY_SHORT_OPTS, my_long_opts, NULL);
-    switch (opt) {
-      case -1:
-       goto opt_done;
-
-      case 'h':
-       help = 1;
-       break;
-
-      case 'i':
-       loginput = 1;
-       break;
-
-      case 'f':
-       logfile = optarg;
-       break;
-
-      case 'n':
-       logname = optarg;
-       break;
-
-      case 'l':
-       {
-         char *c = optarg;
-
-         register_default = 0;
-         int fdnum = 0;
-         int parseerror = 0;
-         if ( (c[0]<'0') || (c[0] > '9') )
-           parseerror = 1;
-         while ( (!parseerror) && (c[0] >= '0') && (c[0] <= '9') )
-           { fdnum = fdnum*10 + c[0] - '0'; c++; }
-         if ( (!parseerror) && (c[0] != ':') )
-           parseerror = 1;
-         c++;
-         if ( (!parseerror) && (c[0] == 0) )
-           parseerror = 1;
-         if ( (!parseerror) && (c[1] != 0) )
-           parseerror = 1;
-         if (parseerror) die("Bad argument `%s' to -l, expects number:letter.", optarg);
-
-         uns level = 0;
-         while (level < L_MAX && LS_LEVEL_LETTER(level) != c[0])
-           level++;
-         if (level >= L_MAX)
-           die("Unknown logging level `%s'", c);
-
-         add_level_fd(fdnum, level);
-       }
-       break;
-
-      case 's':
-       nonzero_status_message = 0;
-       /* fallthrough */
-      case 'q':
-       launch_finish_messages = 0;
-       break;
-
-      default:
-       optind--;
-       goto opt_done;
-    }
-  }
-opt_done:
-
-  if (!help) {
-    if (loginput && (optind < argc))
-      die("No cmd is allowed for -i. Use -h for help.");
-
-    if ((!loginput) && (optind >= argc)) {
-      msg(L_FATAL, "Either command or --input expected.");
-      help = 2;
-    }
-  }
-  if (help) {
-    write(2, usage, sizeof(usage));
-    return (help == 1) ? 0 : 1;
-  }
-
-  if (register_default) {
-    if (loginput) {
-      add_level_fd(0, L_INFO);
-    } else {
-      add_level_fd(1, L_INFO);
-      add_level_fd(2, L_WARN);
-    }
-  }
-
-  if (loginput) {
-    /* Just check, that we don't want open stderr for reading. */
-    CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
-      if (fd->fdnum == 2)
-        die("Stderr is reserved for output");
-    }
-  } else {
-    /* Open all filedescriptors and their duplicates. */
-    CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
-      CLIST_FOR_EACH(struct fds *, fdcheck, filedescriptors) {
-        /* We do a dummy check for collisions of filedescriptors. */
-        if (fdcheck == fd)
-         break;
-        if (fdcheck->fdnum == fd->fdnum) {
-          die("Duplicate filedescriptor %i", fd->fdnum);
-        }
-        xdupavoid(fdcheck->pipe + 0, fd->fdnum);
-        xdupavoid(fdcheck->pipe + 1, fd->fdnum);
-      }
-      if (pipe(fd->pipe) == -1)
-        die("Cannot create pipe: %m");
-      DBG("Pipe [%i, %i] for %i", fd->pipe[0], fd->pipe[1], fd->fdnum);
-      xdupavoid(fd->pipe + 0, fd->fdnum);
-
-      if (fd->fdnum == 2) {
-        stderrfd = fd; //We need to redirect stderr later.
-      } else {
-        xdupto(fd->pipe + 1, fd->fdnum);
-      }
-      DBG("---> [%i, %i] for %i", fd->pipe[0], fd->pipe[1], fd->fdnum);
-      set_cloexec_flag(fd->pipe[0], 1);
-      set_cloexec_flag(fd->pipe[1], 0);
-    }
-  }
-
-  /* Initialize main loop. */
-  main_init();
-
-  CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
-    /* Our pipe is created, let fd->fdnum be the reading end. */
-    if (!loginput)
-      fd->fdnum = fd->pipe[0];
-    fd->rio.read_rec_max = max_line + 1;
-    rec_io_add(&fd->rio, fd->fdnum);
-  }
-
-  int pid = -1;
-  if (!loginput) {
-    /* Launch the child and close filedescriptors. */
-    pid = fork();
-    if (pid == -1)
-      die("Cannot fork: %m");
-    if (pid == 0 ) {
-      /* Child */
-
-      /* Move stderr where it should be. */
-      if (stderrfd)
-        xdupto(stderrfd->pipe + 1, 2);
-
-      execvp(argv[optind], argv + optind);
-      if (stderrfd) {
-        /* We translate stderr, just print. */
-        perror("Cannot exec child");
-        return 127;
-      }
-      /* No stderr translation: use logging function. */
-      die("Cannot exec child: %m");
-    }
-
-    /* Close writing filedescriptors. */
-    CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
-      close(fd->pipe[1]);
-    }
-  }
-
-  /* Open logfile or stderr. */
-  if (logfile) {
-    log_file(logfile);
-    close(2);
-  }
-
-  if (!loginput) {
-    /* Inform about launching of the command. */
-    int buflen = 0;
-    for (int i = optind; i < argc; i++) buflen += strlen(argv[i]) + 1;
-    char *buf = xmalloc(buflen);
-    char *buf2 = buf;
-    for (int i = optind; i < argc; i++) {
-      strcpy(buf2, argv[i]);
-      buf2 += strlen(argv[i]);
-      buf2[0] = ' ';
-      buf2++;
-    }
-    buf2[-1] = 0;
-
-    if (launch_finish_messages)
-      msg(L_INFO, "Launching command: %s", buf);
-  }
-
-  /* Set logname. */
-  if (logname)
-    log_init(logname);
-  else if (!loginput)
-    log_init(argv[optind]);
-
-  /* Start reading from pipes. */
-  CLIST_FOR_EACH(struct fds *, fd, filedescriptors)
-    rec_io_start_read(&fd->rio);
-  main_loop();
-
-  if (!loginput) {
-    /* Unset logname. */
-    log_init("logoutput");
-
-    /* Wait for status of the child and inform about finish. */
-    int status;
-    char buf[256];
-
-    while (waitpid(pid, &status, 0) == -1) {
-      if (errno != EINTR)
-        die("Cannot wait for child: %m");
-    }
-
-    if (format_exit_status(buf, status)) {
-      if (nonzero_status_message)
-       msg(L_WARN, "Child %s", buf);
-      return WIFEXITED(status) ? WEXITSTATUS(status) : 127;
-    } else {
-      if (launch_finish_messages)
-       msg(L_INFO, "Child terminated successfully.");
-      return 0;
-    }
-  }
-
-  return 0;
-}
diff --git a/ucw/shell/ucw-config.c b/ucw/shell/ucw-config.c
new file mode 100644 (file)
index 0000000..6217ac6
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ *     UCW Library -- Shell Interface to Configuration Files
+ *
+ *     (c) 2002--2005 Martin Mares <mj@ucw.cz>
+ *     (c) 2006 Robert Spalek <robert@ucw.cz>
+ *     (c) 2006 Pavel Charvat <pchar@ucw.cz>
+ *
+ *     Once we were using this beautiful Shell version, but it turned out
+ *     that it doesn't work with nested config files:
+ *
+ *             eval `sed <cf/sherlock '/^#/d;/^ *$/d;s/ \+$//;
+ *             h;s@[^  ]*@@;x;s@[      ].*@@;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G;s/\n//;
+ *             /^\[SECTION\]/,/^\[/ {; /^[A-Z]/ { s/^\([^      ]\+\)[  ]*\(.*\)$/SH_\1="\2"/; p; }; };
+ *             d;'`
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#include <ucw/lib.h>
+#include <ucw/conf.h>
+#include <ucw/getopt.h>
+#include <ucw/conf-internal.h>
+#include <ucw/clists.h>
+#include <ucw/mempool.h>
+#include <ucw/chartype.h>
+#include <ucw/bbuf.h>
+#include <ucw/string.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <alloca.h>
+
+static void
+help(void)
+{
+  fputs("\n\
+Usage: ucw-config [-C<configfile>] [-S<section>.<option>=<value>] <sections>\n\
+\n\
+<sections>\t<section>[;<sections>]\n\
+<section>\t[!]<name>{[<items>]}\n\
+<items>\t\t[-]<item>[;<items>]\n\
+<item>\t\t<static> | <array> | <list>\n\
+<static>\t<type><name>[=<value>]\n\
+<list>\t\t@<name>{[<items>]}\n\
+<array>\t\t<type><name><left-bracket>[<number>]<right-bracket>\n\
+<value>\t\t[a-zA-Z0-9.-/]* | 'string without single quotes'<value> | \"c-like string\"<value>\n\
+\n\
+Types:\n\
+<empty>\t\tString\n\
+#\t\t32-bit integer\n\
+##\t\t64-bit integer\n\
+$\t\tFloating point number\n\
+\n\
+Modifiers:\n\
+!\t\tReport unknown items as errors\n\
+-\t\tDo not dump item's value\n\
+", stderr);
+  exit(1);
+}
+
+union value {
+  void *v_ptr;
+  int v_int;
+  u64 v_u64;
+  double v_double;
+  clist list;
+};
+
+#define FLAG_HIDE              0x1
+#define FLAG_NO_UNKNOWN                0x2
+
+struct item {
+  cnode node;
+  uns flags;
+  struct cf_item cf;
+  union value value;
+  uns index;
+};
+
+struct section {
+  struct item item;
+  clist list;
+  uns count;
+  uns size;
+};
+
+static struct mempool *pool;
+static clist sections;
+static byte *pos;
+
+static void
+parse_white(void)
+{
+  while (Cspace(*pos))
+    pos++;
+}
+
+static void
+parse_char(byte c)
+{
+  if (*pos++ != c)
+    die("Missing '%c'", c);
+}
+
+static byte *
+parse_name(void)
+{
+  byte *name = pos;
+  while (Cword(*pos))
+    pos++;
+  uns len = pos - name;
+  if (!len)
+    die("Expected item/section name");
+  byte *buf = mp_alloc(pool, len + 1);
+  memcpy(buf, name, len);
+  buf[len] = 0;
+  return buf;
+}
+
+static void
+parse_section(struct section *section)
+{
+#define TRY(x) do{byte *_err=(x); if (_err) die(_err); }while(0)
+  for (uns sep = 0; ; sep = 1)
+    {
+      parse_white();
+      if (!*pos || *pos == '}')
+       break;
+      if (sep)
+       parse_char(';');
+      parse_white();
+
+      struct item *item;
+
+      if (*pos == '@')
+        {
+         pos++;
+         struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
+         sec->size = sizeof(cnode);
+         clist_init(&sec->list);
+         item = &sec->item;
+         item->cf.name = parse_name();
+         item->cf.cls = CC_LIST;
+         item->cf.number = 1;
+         parse_white();
+         parse_char('{');
+         parse_section(sec);
+         parse_char('}');
+       }
+      else
+        {
+         item = mp_alloc_zero(pool, sizeof(*item));
+         if (*pos == '-')
+           {
+             item->flags |= FLAG_HIDE;
+             pos++;
+           }
+         item->cf.cls = CC_STATIC;
+         item->cf.number = 1;
+         switch (*pos)
+           {
+             case '#':
+               if (*++pos == '#')
+                 {
+                   pos++;
+                   item->cf.type = CT_U64;
+                 }
+               else
+                 item->cf.type = CT_INT;
+               break;
+             case '$':
+               pos++;
+               item->cf.type = CT_DOUBLE;
+               break;
+             default:
+               if (!Cword(*pos))
+                 die("Invalid type syntax");
+               item->cf.type = CT_STRING;
+               break;
+           }
+         parse_white();
+         item->cf.name = parse_name();
+         parse_white();
+         if (*pos == '[')
+           {
+             pos++;
+             parse_white();
+             item->cf.cls = CC_DYNAMIC;
+             byte *num = pos;
+             while (*pos && *pos != ']')
+               pos++;
+             if (!*pos)
+               die("Missing ']'");
+             *pos++ = 0;
+             if (!*num)
+               item->cf.number = CF_ANY_NUM;
+             else
+               {
+                 int inum;
+                 TRY(cf_parse_int(num, &inum));
+                 if (!inum)
+                   die("Invalid array length");
+                 item->cf.number = inum;
+               }
+             parse_white();
+           }
+         if (*pos == '=')
+           {
+             pos++;
+             parse_white();
+             if (section->item.cf.cls == CC_LIST)
+               die("List items can not have default values");
+             if (item->cf.cls == CC_DYNAMIC)
+               die("Arrays can not have default values");
+             byte *def = pos, *d = def;
+             while (*pos != ';' && *pos != '}' && !Cspace(*pos))
+               {
+                 if (*pos == '\'')
+                   {
+                     pos++;
+                     while (*pos != '\'')
+                       {
+                         if (!*pos)
+                           die("Unterminated string");
+                         *d++ = *pos++;
+                       }
+                     pos++;
+                   }
+                 else if (*pos == '"')
+                   {
+                     pos++;
+                     byte *start = d;
+                     uns esc = 0;
+                     while (*pos != '"' || esc)
+                       {
+                         if (!*pos)
+                           die("Unterminated string");
+                         if (*pos == '\\')
+                           esc ^= 1;
+                         else
+                           esc = 0;
+                         *d++ = *pos++;
+                       }
+                     pos++;
+                     *d = 0;
+                     d = str_unesc(start, start);
+                   }
+                 else
+                   *d++ = *pos++;
+               }
+             uns len = d - def;
+             byte *buf = mp_alloc(pool, len + 1);
+             memcpy(buf, def, len);
+             buf[len] = 0;
+             switch (item->cf.type)
+               {
+                 case CT_STRING:
+                   item->value.v_ptr = buf;
+                   break;
+                 case CT_INT:
+                   TRY(cf_parse_int(buf, &item->value.v_int));
+                   break;
+                 case CT_U64:
+                   TRY(cf_parse_u64(buf, &item->value.v_u64));
+                   break;
+                 case CT_DOUBLE:
+                   TRY(cf_parse_double(buf, &item->value.v_double));
+                   break;
+                 default:
+                   ASSERT(0);
+               }
+           }
+       }
+      if (section->item.cf.cls == CC_LIST)
+        {
+          item->cf.ptr = (void *)(uintptr_t)section->size;
+          section->size += sizeof(union value);
+        }
+      else
+        item->cf.ptr = &item->value;
+      clist_add_tail(&section->list, &item->node);
+      section->count++;
+    }
+#undef TRY
+}
+
+static void
+parse_outer(void)
+{
+  for (uns sep = 0; ; sep = 1)
+    {
+      parse_white();
+      if (!*pos)
+       break;
+      if (sep)
+       parse_char(';');
+      parse_white();
+      struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
+      if (*pos == '!')
+        {
+         pos++;
+         sec->item.flags |= FLAG_NO_UNKNOWN;
+       }
+      sec->item.cf.name = parse_name();
+      parse_white();
+      parse_char('{');
+      clist_add_tail(&sections, &sec->item.node);
+      clist_init(&sec->list);
+      parse_section(sec);
+      parse_char('}');
+    }
+}
+
+static struct cf_section *
+generate_section(struct section *section)
+{
+  struct cf_section *sec = mp_alloc_zero(pool, sizeof(*sec));
+  if (section->item.cf.cls == CC_LIST)
+    sec->size = section->size;
+  struct cf_item *c = sec->cfg = mp_alloc_zero(pool, sizeof(struct cf_item) * (section->count + 1));
+  CLIST_FOR_EACH(struct item *, item, section->list)
+    {
+      *c = item->cf;
+      if (c->cls == CC_LIST)
+       c->u.sec = generate_section((struct section *)item);
+      c++;
+    }
+  c->cls = CC_END;
+  return sec;
+}
+
+static bb_t path;
+
+static void
+dump_value(uns array, struct item *item, void *v)
+{
+  byte buf[128], *value = buf;
+  if (!array)
+    printf("CF_%s_%s='", path.ptr, item->cf.name);
+  else
+    printf("CF_%s_%s[%u]='", path.ptr, item->cf.name, ++item->index);
+  switch (item->cf.type)
+    {
+      case CT_INT:
+        sprintf(buf, "%d", *(int *)v);
+        break;
+      case CT_U64:
+        sprintf(buf, "%llu", (long long) *(u64 *)v);
+       break;
+      case CT_DOUBLE:
+       sprintf(buf, "%g", *(double *)v);
+       break;
+      case CT_STRING:
+        if (*(byte **)v)
+          value = *(byte **)v;
+        else
+          *value = 0;
+        break;
+      default:
+        ASSERT(0);
+    }
+  while (*value) {
+    if (*value == '\'')
+      printf("'\\''");
+    else
+      putchar(*value);
+    value++;
+  }
+  printf("'\n");
+}
+
+static void
+dump_item(struct item *item, void *ptr, uns path_len)
+{
+  if (item->flags & FLAG_HIDE)
+    return;
+  byte *val = (byte *)((uintptr_t)ptr + (uintptr_t)item->cf.ptr);
+  if (item->cf.cls == CC_LIST)
+    {
+      uns len = strlen(item->cf.name);
+      bb_grow(&path, path_len + len + 1);
+      path.ptr[path_len] = '_';
+      memcpy(path.ptr + path_len + 1, item->cf.name, len);
+      CLIST_FOR_EACH(cnode *, ptr2, *(clist *)val)
+        CLIST_FOR_EACH(struct item *, item2, ((struct section *)item)->list)
+          dump_item(item2, ptr2, path_len + len + 1);
+    }
+  else
+    {
+      bb_grow(&path, path_len + 1)[path_len] = 0;
+      if (item->cf.cls == CC_STATIC)
+       dump_value(!!ptr, item, val);
+      else
+        {
+         val = *(void **)val;
+         uns len = DARY_LEN(val);
+         uns size = cf_type_size(item->cf.type, NULL);
+         for (uns i = 0; i < len; i++, val += size)
+           dump_value(1, item, val);
+       }
+    }
+}
+
+int main(int argc, char **argv)
+{
+  log_init("ucw-config");
+  if (argc < 2)
+    help();
+  pos = argv[argc - 1];
+  argv[argc - 1] = NULL;
+
+  pool = mp_new(0x1000);
+  clist_init(&sections);
+  parse_outer();
+  CLIST_FOR_EACH(struct section *, sec, sections)
+    cf_declare_section(sec->item.cf.name, generate_section(sec), !(sec->item.flags & FLAG_NO_UNKNOWN));
+
+  if (cf_getopt(argc - 1, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
+    help();
+
+  bb_init(&path);
+  CLIST_FOR_EACH(struct section *, section, sections)
+    {
+      uns len = strlen(section->item.cf.name);
+      memcpy(bb_grow(&path, len), section->item.cf.name, len);
+      CLIST_FOR_EACH(struct item *, item, section->list)
+        dump_item(item, NULL, len);
+    }
+  bb_done(&path);
+
+  return 0;
+}
+
diff --git a/ucw/shell/ucw-logger.c b/ucw/shell/ucw-logger.c
new file mode 100644 (file)
index 0000000..fba6f5d
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *     UCW Library Utilities -- A Simple Logger for use in shell scripts
+ *
+ *     (c) 2001--2009 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#include <ucw/lib.h>
+#include <ucw/log.h>
+
+#include <stdio.h>
+#include <string.h>
+
+int
+main(int argc, char **argv)
+{
+  byte buf[1024], *c;
+
+  log_init("ucw-logger");
+  if (argc < 3 || argc > 4 || strlen(argv[2]) != 1)
+    die("Usage: ucw-logger [<logname>:]<progname> <level> [<text>]");
+  if (c = strchr(argv[1], ':'))
+    {
+      *c++ = 0;
+      log_init(c);
+      log_file(argv[1]);
+    }
+  else
+    log_init(argv[1]);
+
+  uns level = 0;
+  while (level < L_MAX && LS_LEVEL_LETTER(level) != argv[2][0])
+    level++;
+  if (level >= L_MAX)
+    die("Unknown logging level `%s'", argv[2]);
+
+  if (argc > 3)
+    msg(level, argv[3]);
+  else
+    while (fgets(buf, sizeof(buf), stdin))
+      {
+       c = strchr(buf, '\n');
+       if (c)
+         *c = 0;
+       msg(level, buf);
+      }
+  return 0;
+}
diff --git a/ucw/shell/ucw-logoutput.c b/ucw/shell/ucw-logoutput.c
new file mode 100644 (file)
index 0000000..93afcd3
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ *     UCW Library Utilities -- A Simple Logger for use in shell scripts
+ *
+ *     (c) 2001--2009 Martin Mares <mj@ucw.cz>
+ *      (c) 2011 Tomas Ebenlendr <ebik@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#undef LOCAL_DEBUG
+
+#include <ucw/lib.h>
+#include <ucw/log.h>
+#include <ucw/mainloop.h>
+#include <ucw/clists.h>
+#include <ucw/getopt.h>
+#include <ucw/conf.h>
+#include <ucw/process.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+static uns max_line = 1024;
+static int launch_finish_messages = 1;
+static int nonzero_status_message = 1;
+
+static struct cf_section cfsec_logoutput = {
+  CF_ITEMS {
+    CF_UNS("LineMax", &max_line),
+    CF_END
+  }
+};
+
+static clist filedescriptors;
+
+struct fds {
+  cnode node;
+  int pipe[2];
+  int fdnum;
+  uns level;
+  int long_continue;
+  struct main_rec_io rio;
+};
+
+static void
+close_fd(struct fds *fd)
+{
+  rec_io_del(&fd->rio);
+  close(fd->fdnum);
+  clist_remove(&fd->node);
+  if (clist_empty(&filedescriptors))
+    main_shut_down();
+}
+
+
+static void
+do_msg (struct fds *fd, char *l_msg, int long_continue)
+{
+  msg(fd->level, "%s%s", (fd->long_continue ? "... " : ""), l_msg);
+  fd->long_continue = long_continue;
+}
+
+static uns
+handle_read(struct main_rec_io *r)
+{
+  char buf[max_line + 5];
+  byte *eol = memchr((char *)r->read_rec_start + r->read_prev_avail, '\n', r->read_avail - r->read_prev_avail);
+  if (eol == NULL) {
+    if (r->read_avail >= max_line) {
+      memcpy(buf, r->read_rec_start, max_line);
+      memcpy(buf + max_line, " ...", 5);
+      do_msg(r->data, buf, 1);
+      return max_line;
+    } else
+      return 0;
+  }
+  *eol = 0;
+  byte *b = r->read_rec_start;
+  while ((uns)(eol - b) > max_line) {
+    char cc = b[max_line];
+    b[max_line]=0;
+    do_msg(r->data, b, 1);
+    b[max_line]=cc;
+    b+=max_line;
+  }
+  do_msg(r->data, (char *)b, 0);
+  return eol - r->read_rec_start + 1;
+}
+
+static int
+handle_notify(struct main_rec_io *r, int status)
+{
+  struct fds *fd = r->data;
+  switch (status) {
+    case RIO_ERR_READ:
+    case RIO_EVENT_EOF:
+      if (r->read_avail) {
+        char buf[max_line + 10];
+        memcpy(buf, r->read_rec_start, r->read_avail);
+        memcpy(buf + r->read_avail, " [no eol]", 10);
+        do_msg(r->data, buf, 0);
+      } else if (fd->long_continue) {
+       do_msg(r->data, "[no eol]", 0);
+      }
+      close_fd(fd);
+      return HOOK_DONE;
+    default:
+      ASSERT(0);
+  }
+  return HOOK_IDLE;
+}
+
+
+static void
+add_level_fd(int fdnum, int level)
+{
+  struct fds *fd = xmalloc_zero(sizeof(*fd));
+  fd->level = level;
+  fd->pipe[0] = -1;
+  fd->pipe[1] = -1;
+  fd->fdnum = fdnum;
+  fd->rio.read_handler = handle_read;
+  fd->rio.data = fd;
+  fd->rio.notify_handler = handle_notify;
+  fd->long_continue = 0;
+  clist_add_tail(&filedescriptors, &fd->node);
+}
+
+static int
+xdup(int fd)
+{
+  int rfd = dup(fd);
+  if (rfd == -1)
+    die("Cannot dup(): %m");
+  DBG("  Dup(%i) -> %i", fd, rfd);
+  return rfd;
+}
+
+static int
+xdup2(int fd1, int fd2)
+{
+  int rfd = dup2(fd1, fd2);
+  if (rfd == -1)
+    die("Cannot dup2(): %m");
+  DBG("  Dup2(%i, %i) -> %i", fd1, fd2, rfd);
+  return rfd;
+}
+
+static void
+xdupavoid(int *fd1, int fd2)
+{
+  DBG("Dupavoid: !%i -> %i", fd2, *fd1);
+  int ofd = *fd1;
+  if (ofd == fd2) {
+    *fd1 = xdup(ofd);
+    DBG("  Close: %i", ofd);
+    close(ofd);
+  }
+}
+
+static void
+xdupto(int *fd1, int fd2)
+{
+  DBG("Dupto: %i -> %i", *fd1, fd2);
+  if (*fd1 == fd2)
+    return;
+  DBG("  Close: %i", fd2);
+  close(fd2);
+  xdup2(*fd1, fd2);
+  DBG("  Close: %i", *fd1);
+  close(*fd1);
+  *fd1 = fd2;
+}
+
+static void
+set_cloexec_flag(int fd, int value)
+{
+  int flags = fcntl(fd, F_GETFD, 0);
+  if (flags < 0)
+    die("fcntl(..., F_GETFD, ...) : %m");
+  flags = (value) ? flags | FD_CLOEXEC : flags & ~FD_CLOEXEC;
+  if (fcntl(fd, F_SETFD, flags) < 0)
+    die("fcntl(..., F_SETFD, ...) : %m");
+}
+
+/* The "+" stands for end at first argument (i.e. do not parse options after
+   first argument.) */
+#define MY_SHORT_OPTS "+" CF_SHORT_OPTS "f:n:l:ih"
+const struct option my_long_opts[] = {
+  CF_LONG_OPTS
+  { "help", 0, 0, 'h'},
+  { "input", 0, 0, 'i'},
+  { "logfile", 1, 0, 'f'},
+  { "logname", 1, 0, 'n'},
+  { "descriptor", 1, 0, 'l'},
+  { "nv", 0, 0, 'q'},
+  { "nonverbose", 0, 0, 'q'},
+  { "non-verbose", 0, 0, 'q'},
+  { "non_verbose", 0, 0, 'q'},
+  { "silent", 0, 0, 's'},
+  { NULL, 0, 0, 0}
+};
+
+#undef CF_USAGE_TAB
+#define CF_USAGE_TAB "\t   "
+static char usage[] =
+  "Usage:\n"
+  "ucw-logoutput -h|--help\t\t   This help.\n"
+  "ucw-logoutput <options> -i|--input   Read file descriptors and log them.\n"
+  "\t\t\t\t   default: stdin at level I.\n"
+  "ucw-logoutput <opts> [--] <cmd> [arguments for cmd ...]\n"
+  "\t\t\t\t   Open file descriptors for writing for command <cmd> and log them.\n"
+  "\t\t\t\t   default: stdout:I, stderr:W.\n\n"
+  "Options:\n"
+  CF_USAGE
+  "-n, --logname <name>\t\t   Use <name> as program name in logs.\n"
+  "-l, --descriptor <fdnum>:<level>   Open file descriptor <fdnum> and log it at level <level> (replaces defaults).\n"
+  "-f, --logfile <logfile>\t\t   Log to file <logfile>.\n"
+  "-q, --nv, --nonverbose\t\t   Suppress launching and successful finish messages.\n"
+  "-s, --silent\t\t\t   Suppress launching message and all finish messages.\n"
+  "\t\t\t\t   (i.e., no warning if it terminates with a nonzero exit code or by a signal)\n";
+
+int
+main(int argc, char **argv)
+{
+  int register_default = 1;
+  int loginput = 0;
+  char *logfile = NULL;
+  char *logname = NULL;
+  struct fds *stderrfd = NULL;
+  int help = 0;
+
+  log_init("ucw-logoutput");
+  clist_init(&filedescriptors);
+  cf_declare_section("LogOutput", &cfsec_logoutput, 0);
+
+  while (1) {
+    int opt = cf_getopt(argc, argv, MY_SHORT_OPTS, my_long_opts, NULL);
+    switch (opt) {
+      case -1:
+       goto opt_done;
+
+      case 'h':
+       help = 1;
+       break;
+
+      case 'i':
+       loginput = 1;
+       break;
+
+      case 'f':
+       logfile = optarg;
+       break;
+
+      case 'n':
+       logname = optarg;
+       break;
+
+      case 'l':
+       {
+         char *c = optarg;
+
+         register_default = 0;
+         int fdnum = 0;
+         int parseerror = 0;
+         if ( (c[0]<'0') || (c[0] > '9') )
+           parseerror = 1;
+         while ( (!parseerror) && (c[0] >= '0') && (c[0] <= '9') )
+           { fdnum = fdnum*10 + c[0] - '0'; c++; }
+         if ( (!parseerror) && (c[0] != ':') )
+           parseerror = 1;
+         c++;
+         if ( (!parseerror) && (c[0] == 0) )
+           parseerror = 1;
+         if ( (!parseerror) && (c[1] != 0) )
+           parseerror = 1;
+         if (parseerror) die("Bad argument `%s' to -l, expects number:letter.", optarg);
+
+         uns level = 0;
+         while (level < L_MAX && LS_LEVEL_LETTER(level) != c[0])
+           level++;
+         if (level >= L_MAX)
+           die("Unknown logging level `%s'", c);
+
+         add_level_fd(fdnum, level);
+       }
+       break;
+
+      case 's':
+       nonzero_status_message = 0;
+       /* fallthrough */
+      case 'q':
+       launch_finish_messages = 0;
+       break;
+
+      default:
+       optind--;
+       goto opt_done;
+    }
+  }
+opt_done:
+
+  if (!help) {
+    if (loginput && (optind < argc))
+      die("No cmd is allowed for -i. Use -h for help.");
+
+    if ((!loginput) && (optind >= argc)) {
+      msg(L_FATAL, "Either command or --input expected.");
+      help = 2;
+    }
+  }
+  if (help) {
+    write(2, usage, sizeof(usage));
+    return (help == 1) ? 0 : 1;
+  }
+
+  if (register_default) {
+    if (loginput) {
+      add_level_fd(0, L_INFO);
+    } else {
+      add_level_fd(1, L_INFO);
+      add_level_fd(2, L_WARN);
+    }
+  }
+
+  if (loginput) {
+    /* Just check, that we don't want open stderr for reading. */
+    CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
+      if (fd->fdnum == 2)
+        die("Stderr is reserved for output");
+    }
+  } else {
+    /* Open all filedescriptors and their duplicates. */
+    CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
+      CLIST_FOR_EACH(struct fds *, fdcheck, filedescriptors) {
+        /* We do a dummy check for collisions of filedescriptors. */
+        if (fdcheck == fd)
+         break;
+        if (fdcheck->fdnum == fd->fdnum) {
+          die("Duplicate filedescriptor %i", fd->fdnum);
+        }
+        xdupavoid(fdcheck->pipe + 0, fd->fdnum);
+        xdupavoid(fdcheck->pipe + 1, fd->fdnum);
+      }
+      if (pipe(fd->pipe) == -1)
+        die("Cannot create pipe: %m");
+      DBG("Pipe [%i, %i] for %i", fd->pipe[0], fd->pipe[1], fd->fdnum);
+      xdupavoid(fd->pipe + 0, fd->fdnum);
+
+      if (fd->fdnum == 2) {
+        stderrfd = fd; //We need to redirect stderr later.
+      } else {
+        xdupto(fd->pipe + 1, fd->fdnum);
+      }
+      DBG("---> [%i, %i] for %i", fd->pipe[0], fd->pipe[1], fd->fdnum);
+      set_cloexec_flag(fd->pipe[0], 1);
+      set_cloexec_flag(fd->pipe[1], 0);
+    }
+  }
+
+  /* Initialize main loop. */
+  main_init();
+
+  CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
+    /* Our pipe is created, let fd->fdnum be the reading end. */
+    if (!loginput)
+      fd->fdnum = fd->pipe[0];
+    fd->rio.read_rec_max = max_line + 1;
+    rec_io_add(&fd->rio, fd->fdnum);
+  }
+
+  int pid = -1;
+  if (!loginput) {
+    /* Launch the child and close filedescriptors. */
+    pid = fork();
+    if (pid == -1)
+      die("Cannot fork: %m");
+    if (pid == 0 ) {
+      /* Child */
+
+      /* Move stderr where it should be. */
+      if (stderrfd)
+        xdupto(stderrfd->pipe + 1, 2);
+
+      execvp(argv[optind], argv + optind);
+      if (stderrfd) {
+        /* We translate stderr, just print. */
+        perror("Cannot exec child");
+        return 127;
+      }
+      /* No stderr translation: use logging function. */
+      die("Cannot exec child: %m");
+    }
+
+    /* Close writing filedescriptors. */
+    CLIST_FOR_EACH(struct fds *, fd, filedescriptors) {
+      close(fd->pipe[1]);
+    }
+  }
+
+  /* Open logfile or stderr. */
+  if (logfile) {
+    log_file(logfile);
+    close(2);
+  }
+
+  if (!loginput) {
+    /* Inform about launching of the command. */
+    int buflen = 0;
+    for (int i = optind; i < argc; i++) buflen += strlen(argv[i]) + 1;
+    char *buf = xmalloc(buflen);
+    char *buf2 = buf;
+    for (int i = optind; i < argc; i++) {
+      strcpy(buf2, argv[i]);
+      buf2 += strlen(argv[i]);
+      buf2[0] = ' ';
+      buf2++;
+    }
+    buf2[-1] = 0;
+
+    if (launch_finish_messages)
+      msg(L_INFO, "Launching command: %s", buf);
+  }
+
+  /* Set logname. */
+  if (logname)
+    log_init(logname);
+  else if (!loginput)
+    log_init(argv[optind]);
+
+  /* Start reading from pipes. */
+  CLIST_FOR_EACH(struct fds *, fd, filedescriptors)
+    rec_io_start_read(&fd->rio);
+  main_loop();
+
+  if (!loginput) {
+    /* Unset logname. */
+    log_init("ucw-logoutput");
+
+    /* Wait for status of the child and inform about finish. */
+    int status;
+    char buf[256];
+
+    while (waitpid(pid, &status, 0) == -1) {
+      if (errno != EINTR)
+        die("Cannot wait for child: %m");
+    }
+
+    if (format_exit_status(buf, status)) {
+      if (nonzero_status_message)
+       msg(L_WARN, "Child %s", buf);
+      return WIFEXITED(status) ? WEXITSTATUS(status) : 127;
+    } else {
+      if (launch_finish_messages)
+       msg(L_INFO, "Child terminated successfully.");
+      return 0;
+    }
+  }
+
+  return 0;
+}
index b0068726712184007c56da4ae1071062fcb566e8..1ba0449a2f027ca884b9ee9f5b66b39f6f40dc80 100644 (file)
@@ -1,20 +1,20 @@
 # Makefile for the UCW utilities (c) 2008 Michal Vaner <vorner@ucw.cz>
 
-UCW_UTILS=$(addprefix $(o)/ucw/utils/,basecode daemon-control rotate-log urltool)
+UCW_UTILS=$(addprefix $(o)/ucw/utils/ucw-,basecode daemon-control rotate-log urltool)
 PROGS+=$(UCW_UTILS)
 DIRS+=ucw/utils
 
 ifdef CONFIG_UCW_OBSOLETE_DAEMON_HELPER
-PROGS+=$(o)/ucw/utils/daemon-helper
+PROGS+=$(o)/ucw/utils/ucw-daemon-helper
 endif
 
-$(o)/ucw/utils/basecode: $(o)/ucw/utils/basecode.o $(LIBUCW)
-$(o)/ucw/utils/daemon-helper: $(o)/ucw/utils/daemon-helper.o $(LIBUCW)
-$(o)/ucw/utils/daemon-control: $(o)/ucw/utils/daemon-control.o $(LIBUCW)
-$(o)/ucw/utils/urltool: $(o)/ucw/utils/urltool.o $(LIBUCW)
+$(o)/ucw/utils/ucw-basecode: $(o)/ucw/utils/ucw-basecode.o $(LIBUCW)
+$(o)/ucw/utils/ucw-daemon-helper: $(o)/ucw/utils/ucw-daemon-helper.o $(LIBUCW)
+$(o)/ucw/utils/ucw-daemon-control: $(o)/ucw/utils/ucw-daemon-control.o $(LIBUCW)
+$(o)/ucw/utils/ucw-urltool: $(o)/ucw/utils/ucw-urltool.o $(LIBUCW)
 
 TESTS+=$(o)/ucw/utils/basecode.test
-$(o)/ucw/utils/basecode.test: $(o)/ucw/utils/basecode
+$(o)/ucw/utils/basecode.test: $(o)/ucw/utils/ucw-basecode
 
 INSTALL_TARGETS+=install-ucw-utils
 install-ucw-utils:
diff --git a/ucw/utils/basecode.c b/ucw/utils/basecode.c
deleted file mode 100644 (file)
index 5990a9a..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *     UCW Library -- Line utility for encoding and decoding base64 & base224
- *
- *     (c) 2008, Michal Vaner <vorner@ucw.cz>
- *
- *     This software may be freely distributed and used according to the terms
- *     of the GNU Lesser General Public License.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <ucw/lib.h>
-#include <ucw/base64.h>
-#include <ucw/base224.h>
-#include <ucw/fastbuf.h>
-#include <ucw/getopt.h>
-
-static struct option opts[] = {
-  { "encode64", 0, 0, 'e' },
-  { "decode64", 0, 0, 'd' },
-  { "encode224", 0, 0, 'E' },
-  { "decode224", 0, 0, 'D' },
-  { "prefix", 1, 0, 'p' },
-  { "blocks", 1, 0, 'b' },
-  { 0, 0, 0, 0 }
-};
-
-static const struct {
-  uns (*function)(byte *, const byte *, uns);
-  uns in_block, out_block, num_blocks;
-  uns add_prefix;
-} actions[] = {
-  {
-    base64_encode,
-    BASE64_IN_CHUNK, BASE64_OUT_CHUNK, 20,
-    1
-  },
-  {
-    base64_decode,
-    BASE64_OUT_CHUNK, BASE64_IN_CHUNK, 20,
-    0
-  },
-  {
-    base224_encode,
-    BASE224_IN_CHUNK, BASE64_OUT_CHUNK, 6,
-    1
-  },
-  {
-    base224_decode,
-    BASE224_OUT_CHUNK, BASE224_IN_CHUNK, 6,
-    0
-  }
-};
-
-int main(int argc, char **argv)
-{
-  // Choose mode
-  int mode = -1;
-  char *prefix = NULL;
-  uns blocks = 0;
-  int opt;
-  while ((opt = getopt_long(argc, argv, "edEDp:b:", opts, NULL)) >= 0)
-    switch (opt)
-    {
-      case 'e': mode = 0; break;
-      case 'd': mode = 1; break;
-      case 'E': mode = 2; break;
-      case 'D': mode = 3; break;
-      case 'p': prefix = optarg; break;
-      case 'b':
-        {
-          char *end;
-          blocks = strtol(optarg, &end, 0);
-          if ((blocks > 0) && !*end)
-            break;
-        }
-      default: goto usage;
-    }
-
-  if (mode == -1)
-  {
-    usage:
-    fprintf(stderr, "basecode mode [--prefix=prefix] [--blocks=number_of_blocks]\nMode is one of:\n\t--encode64 (-e)\n\t--decode64 (-d)\n\t--encode224 (-E)\n\t--decode224 (-D)\n");
-    return 1;
-  }
-  if (!blocks)
-    blocks = actions[mode].num_blocks;
-
-  // Prepare buffers
-  struct fastbuf *in = bfdopen_shared(0, 4096);
-  struct fastbuf *out = bfdopen_shared(1, 4096);
-  int has_offset = !actions[mode].add_prefix && prefix;
-  uns offset = has_offset ? strlen(prefix) : 0;
-  uns read_size = actions[mode].in_block * blocks + offset + has_offset;
-  uns write_size = actions[mode].out_block * blocks;
-  byte in_buff[read_size], out_buff[write_size];
-  uns isize;
-
-  // Recode it
-  while (isize = bread(in, in_buff, read_size))
-  {
-    if (prefix)
-    {
-      if (actions[mode].add_prefix)
-        bputs(out, prefix);
-      else
-        if ((isize < offset) || (in_buff[isize-1] != '\n')
-            || (strncmp(prefix, in_buff, offset)))
-          die("Invalid line syntax");
-    }
-    uns osize = actions[mode].function(out_buff, in_buff + offset, isize - offset - has_offset);
-    bwrite(out, out_buff, osize);
-    if (actions[mode].add_prefix && prefix)
-      bputc(out, '\n');
-  }
-
-  bclose(in);
-  bclose(out);
-  return 0;
-}
index beb84eb7d448d111f5b1b19cc8c5b438226d3379..76d1d0e72f480af0f22ea60c68b8d43cec2df0dc 100644 (file)
@@ -1,16 +1,16 @@
 # Tests for base64 and base224 modules
 
 Name:  Base64 encode
-Run:   ../obj/ucw/utils/basecode -e
+Run:   ../obj/ucw/utils/ucw-basecode -e
 In:    Here are some test data
 Out:   SGVyZSBhcmUgc29tZSB0ZXN0IGRhdGEK
 
 Name:  Base64 decode
-Run:   ../obj/ucw/utils/basecode -d
+Run:   ../obj/ucw/utils/ucw-basecode -d
 In:    SGVyZSBhcmUgc29tZSB0ZXN0IGRhdGEK
 Out:   Here are some test data
 
 Name:  Base224 encode & decode
-Run:   ../obj/ucw/utils/basecode -E | ../obj/ucw/utils/basecode -D
+Run:   ../obj/ucw/utils/ucw-basecode -E | ../obj/ucw/utils/ucw-basecode -D
 In:    Some more test data for 224 encoding
 Out:   Some more test data for 224 encoding
diff --git a/ucw/utils/daemon-control.c b/ucw/utils/daemon-control.c
deleted file mode 100644 (file)
index 5174919..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *     A Simple Utility for Controlling Daemons
- *
- *     (c) 2012 Martin Mares <mj@ucw.cz>
- *
- *     For more information, see ucw/doc/daemon.txt.
- *
- *     Return codes:
- *     100     already done
- *     101     not running
- *     102     error
- */
-
-#include <ucw/lib.h>
-#include <ucw/daemon.h>
-#include <ucw/signames.h>
-#include <ucw/string.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <getopt.h>
-
-static int action;
-
-static struct option options[] = {
-  { "pid-file",                required_argument,      NULL,           'p' },
-  { "guard-file",      required_argument,      NULL,           'g' },
-  { "signal",          required_argument,      NULL,           's' },
-  { "start",           no_argument,            &action,        DAEMON_CONTROL_START },
-  { "stop",            no_argument,            &action,        DAEMON_CONTROL_STOP },
-  { "check",           no_argument,            &action,        DAEMON_CONTROL_CHECK },
-  { "reload",          no_argument,            &action,        DAEMON_CONTROL_SIGNAL },
-  { NULL,              no_argument,            NULL,           0 }
-};
-
-static void NONRET
-usage(void)
-{
-  fputs("\n\
-Usage: daemon-control --start <options> -- <daemon> <args>\n\
-   or: daemon-control --stop <options>\n\
-   or: daemon-control --reload <options>\n\
-   or: daemon-control --check <options>\n\
-\n\
-Options:\n\
---pid-file <name>      Name of PID file for this daemon (mandatory)\n\
---guard-file <name>    Name of guard file (default: derived from --pid-file)\n\
---signal <sig>         Send a signal of a given name or number\n\
-                       Default: SIGTERM for --stop, SIGHUP for --reload\n\
-\n\
-Exit codes:\n\
-0                      Successfully completed\n\
-1                      Invalid arguments\n\
-100                    The action was null (e.g., --stop on a stopped daemon)\n\
-101                    The daemon was not running (on --reload or --check)\n\
-102                    The action has failed (error message was printed to stderr)\n\
-103                    The daemon was in an undefined state (e.g., stale PID file)\n\
-", stderr);
-  exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, sig;
-  struct daemon_control_params dc = { };
-
-  while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
-    switch (c)
-      {
-      case 0:
-       break;
-      case 'p':
-       dc.pid_file = optarg;
-       break;
-      case 'g':
-       dc.guard_file = optarg;
-       break;
-      case 's':
-       sig = sig_name_to_number(optarg);
-       if (sig < 0)
-         {
-           fprintf(stderr, "%s: Unknown signal %s\n", argv[0], optarg);
-           return 1;
-         }
-       dc.signal = sig;
-       break;
-      default:
-       usage();
-      }
-  if (!dc.pid_file || !action)
-    usage();
-  dc.action = action;
-
-  if (action == DAEMON_CONTROL_START)
-    {
-      if (optind >= argc)
-       usage();
-      dc.argv = argv + optind;
-    }
-  else if (optind < argc)
-    usage();
-
-  if (!dc.guard_file)
-    {
-      if (!str_has_suffix(dc.pid_file, ".pid"))
-       {
-         fprintf(stderr, "%s: For automatic choice of --guard-file, the --pid-file must end with `.pid'\n", argv[0]);
-         return 1;
-       }
-      int len = strlen(dc.pid_file);
-      char *buf = xmalloc(len + 2);
-      sprintf(buf, "%.*s.lock", len-4, dc.pid_file);
-      dc.guard_file = buf;
-    }
-
-  int err = daemon_control(&dc);
-  if (err == DAEMON_STATUS_ERROR)
-    fprintf(stderr, "%s: %s\n", argv[0], dc.error_msg);
-  return err;
-}
diff --git a/ucw/utils/daemon-helper.c b/ucw/utils/daemon-helper.c
deleted file mode 100644 (file)
index 2e7e682..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *     A Simple Wrapper for Starting and Stopping of Daemons
- *
- *     (c) 2003 Martin Mares <mj@ucw.cz>
- *
- *     It would seem that we are reinventing the wheel and the
- *     start-stop-daemon command present in most Linux distributions
- *     is just what we need, but the usual "does the process already
- *     exist?" strategies fail in presence of multiple running daemons.
- *
- *     Return codes:
- *     101     already running
- *     102     not running
- *
- *     NOTE: This utility is obsolete and has been replaced by daemon-control.
- *     You need to enable CONFIG_UCW_OBSOLETE_DAEMON_HELPER to compile it.
- */
-
-#include <ucw/lib.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <errno.h>
-#include <alloca.h>
-
-enum action {
-  ACTION_NONE,
-  ACTION_START,
-  ACTION_STOP,
-  ACTION_FORCE_STOP,
-  ACTION_CHECK,
-  ACTION_RELOAD
-};
-
-static int action;
-
-static struct option options[] = {
-  { "pid-file",                required_argument,      NULL, 'p' },
-  { "status-file",     required_argument,      NULL, 's' },
-  { "start",           no_argument,            &action, ACTION_START },
-  { "stop",            no_argument,            &action, ACTION_STOP },
-  { "force-stop",      no_argument,            &action, ACTION_FORCE_STOP },
-  { "check",           no_argument,            &action, ACTION_CHECK },
-  { "reload",          no_argument,            &action, ACTION_RELOAD },
-  { NULL,              no_argument,            NULL, 0 }
-};
-
-static void NONRET
-usage(void)
-{
-  fputs("\n\
-Usage: daemon-helper --start <options> -- <daemon> <args>\n\
-   or: daemon-helper --stop <options>\n\
-   or: daemon-helper --force-stop <options>\n\
-   or: daemon-helper --reload <options>\n\
-   or: daemon-helper --check <options>\n\
-\n\
-Options:\n\
---pid-file <name>      Name of PID file for this daemon (mandatory)\n\
---status-file <name>   Status file used by the daemon (deleted just before starting)\n\
-", stderr);
-  exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, fd;
-  char *pidfile = NULL;
-  char *statfile = NULL;
-  struct flock fl;
-  char buf[64];
-
-  while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
-    switch (c)
-      {
-      case 0:
-       break;
-      case 'p':
-       pidfile = optarg;
-       break;
-      case 's':
-       statfile = optarg;
-       break;
-      default:
-       usage();
-      }
-  if (!pidfile)
-    usage();
-
-  bzero(&fl, sizeof(fl));
-  fl.l_type = F_WRLCK;
-  fl.l_whence = SEEK_SET;
-
-  switch (action)
-    {
-    case ACTION_START:
-      if (optind >= argc)
-       usage();
-      fd = open(pidfile, O_RDWR | O_CREAT, 0666);
-      if (fd < 0)
-       die("Unable to create %s: %m", pidfile);
-      if ((c = fcntl(fd, F_SETLK, &fl)) < 0)
-       {
-         if (errno == EAGAIN || errno == EACCES)
-           return 101;
-         else
-           die("fcntl lock on %s failed: %m", pidfile);
-       }
-      c = sprintf(buf, "%d\n", getpid());
-      if (write(fd, buf, c) != c)
-       die("write on %s failed: %m", pidfile);
-      if (ftruncate(fd, c) < 0)
-       die("truncate on %s failed: %m", pidfile);
-      if (statfile && unlink(statfile) < 0 && errno != ENOENT)
-       die("unlink(%s) failed: %m", statfile);
-      setsid();
-      /* Disconnect from stdin and stdout, leave stderr to the daemon. */
-      close(0);
-      open("/dev/null", O_RDWR, 0);
-      dup2(0, 1);
-      argv += optind;
-      argc -= optind;
-      char **a = alloca(sizeof(char *) * (argc+1));
-      memcpy(a, argv, sizeof(char *) * argc);
-      a[argc] = NULL;
-      execv(a[0], a);
-      die("Cannot execute %s: %m", a[0]);
-    case ACTION_STOP:
-    case ACTION_FORCE_STOP:
-    case ACTION_CHECK:
-    case ACTION_RELOAD:
-      if (optind < argc)
-       usage();
-      fd = open(pidfile, O_RDWR);
-      if (fd < 0)
-       {
-         if (errno == ENOENT)
-           return 102;
-         else
-           die("Unable to open %s: %m", pidfile);
-       }
-      if ((c = fcntl(fd, F_SETLK, &fl)) >= 0)
-       {
-       nopid:
-         unlink(pidfile);
-         return 102;
-       }
-      if (errno != EAGAIN && errno != EACCES)
-       die("fcntl lock on %s failed: %m", pidfile);
-      if ((c = read(fd, buf, sizeof(buf))) < 0)
-       die("read on %s failed: %m", pidfile);
-      if (!c)
-       goto nopid;
-      if (c >= (int) sizeof(buf) || sscanf(buf, "%d", &c) != 1)
-       die("PID file syntax error");
-      int sig = 0;
-      if (action == ACTION_CHECK || action == ACTION_RELOAD)
-       {
-         if (action == ACTION_RELOAD)
-           sig = SIGHUP;
-         if (kill(c, sig) < 0 && errno == ESRCH)
-           goto nopid;
-         return 0;
-       }
-      sig = (action == ACTION_STOP) ? SIGTERM : SIGQUIT;
-      if (kill(c, sig) < 0)
-       {
-         if (errno == ESRCH)
-           goto nopid;
-         die("Cannot kill process %d: %m", c);
-       }
-      if ((c = fcntl(fd, F_SETLKW, &fl)) < 0)
-       die("Cannot lock %s: %m", pidfile);
-      if (statfile)
-       unlink(statfile);
-      if (unlink(pidfile) < 0)
-       die("Cannot unlink %s: %m", pidfile);
-      return 0;
-    default:
-      usage();
-    }
-}
diff --git a/ucw/utils/rotate-log.pl b/ucw/utils/rotate-log.pl
deleted file mode 100644 (file)
index e4c9b10..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/perl
-
-#      Rotate Sherlock logs
-#      (c) 2001--2002 Martin Mares <mj@ucw.cz>
-
-use File::stat;
-
-@ARGV >= 3 or die "Usage: rotate-log <days-to-compress> <date-to-delete> <logs...>";
-
-$now = time;
-$cps = shift @ARGV;
-$del = shift @ARGV;
-
-$compress_thr = $now - 86400 * $cps;
-$delete_thr = $now - 86400 * $del;
-foreach $f (@ARGV) {
-       -f $f or next;
-       $st = stat $f or next;
-       if ($del > 0 && $st->mtime < $delete_thr) {
-               print "Deleting $f\n";
-               unlink $f || die "Delete FAILED: $!";
-       } elsif ($cps > 0 && $st->mtime < $compress_thr && $f !~ /\.(gz|bz2)$/) {
-               print "Compressing $f\n";
-               `gzip -f $f`;
-               $? && die "Compression FAILED: $!";
-       }
-}
diff --git a/ucw/utils/ucw-basecode.c b/ucw/utils/ucw-basecode.c
new file mode 100644 (file)
index 0000000..dda3688
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *     UCW Library -- Line utility for encoding and decoding base64 & base224
+ *
+ *     (c) 2008, Michal Vaner <vorner@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <ucw/lib.h>
+#include <ucw/base64.h>
+#include <ucw/base224.h>
+#include <ucw/fastbuf.h>
+#include <ucw/getopt.h>
+
+static struct option opts[] = {
+  { "encode64", 0, 0, 'e' },
+  { "decode64", 0, 0, 'd' },
+  { "encode224", 0, 0, 'E' },
+  { "decode224", 0, 0, 'D' },
+  { "prefix", 1, 0, 'p' },
+  { "blocks", 1, 0, 'b' },
+  { 0, 0, 0, 0 }
+};
+
+static const struct {
+  uns (*function)(byte *, const byte *, uns);
+  uns in_block, out_block, num_blocks;
+  uns add_prefix;
+} actions[] = {
+  {
+    base64_encode,
+    BASE64_IN_CHUNK, BASE64_OUT_CHUNK, 20,
+    1
+  },
+  {
+    base64_decode,
+    BASE64_OUT_CHUNK, BASE64_IN_CHUNK, 20,
+    0
+  },
+  {
+    base224_encode,
+    BASE224_IN_CHUNK, BASE64_OUT_CHUNK, 6,
+    1
+  },
+  {
+    base224_decode,
+    BASE224_OUT_CHUNK, BASE224_IN_CHUNK, 6,
+    0
+  }
+};
+
+int main(int argc, char **argv)
+{
+  // Choose mode
+  int mode = -1;
+  char *prefix = NULL;
+  uns blocks = 0;
+  int opt;
+  while ((opt = getopt_long(argc, argv, "edEDp:b:", opts, NULL)) >= 0)
+    switch (opt)
+    {
+      case 'e': mode = 0; break;
+      case 'd': mode = 1; break;
+      case 'E': mode = 2; break;
+      case 'D': mode = 3; break;
+      case 'p': prefix = optarg; break;
+      case 'b':
+        {
+          char *end;
+          blocks = strtol(optarg, &end, 0);
+          if ((blocks > 0) && !*end)
+            break;
+        }
+      default: goto usage;
+    }
+
+  if (mode == -1)
+  {
+    usage:
+    fprintf(stderr, "ucw-basecode mode [--prefix=prefix] [--blocks=number_of_blocks]\nMode is one of:\n\t--encode64 (-e)\n\t--decode64 (-d)\n\t--encode224 (-E)\n\t--decode224 (-D)\n");
+    return 1;
+  }
+  if (!blocks)
+    blocks = actions[mode].num_blocks;
+
+  // Prepare buffers
+  struct fastbuf *in = bfdopen_shared(0, 4096);
+  struct fastbuf *out = bfdopen_shared(1, 4096);
+  int has_offset = !actions[mode].add_prefix && prefix;
+  uns offset = has_offset ? strlen(prefix) : 0;
+  uns read_size = actions[mode].in_block * blocks + offset + has_offset;
+  uns write_size = actions[mode].out_block * blocks;
+  byte in_buff[read_size], out_buff[write_size];
+  uns isize;
+
+  // Recode it
+  while (isize = bread(in, in_buff, read_size))
+  {
+    if (prefix)
+    {
+      if (actions[mode].add_prefix)
+        bputs(out, prefix);
+      else
+        if ((isize < offset) || (in_buff[isize-1] != '\n')
+            || (strncmp(prefix, in_buff, offset)))
+          die("Invalid line syntax");
+    }
+    uns osize = actions[mode].function(out_buff, in_buff + offset, isize - offset - has_offset);
+    bwrite(out, out_buff, osize);
+    if (actions[mode].add_prefix && prefix)
+      bputc(out, '\n');
+  }
+
+  bclose(in);
+  bclose(out);
+  return 0;
+}
diff --git a/ucw/utils/ucw-daemon-control.c b/ucw/utils/ucw-daemon-control.c
new file mode 100644 (file)
index 0000000..b7be71c
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *     A Simple Utility for Controlling Daemons
+ *
+ *     (c) 2012 Martin Mares <mj@ucw.cz>
+ *
+ *     For more information, see ucw/doc/daemon.txt.
+ *
+ *     Return codes:
+ *     100     already done
+ *     101     not running
+ *     102     error
+ */
+
+#include <ucw/lib.h>
+#include <ucw/daemon.h>
+#include <ucw/signames.h>
+#include <ucw/string.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+
+static int action;
+
+static struct option options[] = {
+  { "pid-file",                required_argument,      NULL,           'p' },
+  { "guard-file",      required_argument,      NULL,           'g' },
+  { "signal",          required_argument,      NULL,           's' },
+  { "start",           no_argument,            &action,        DAEMON_CONTROL_START },
+  { "stop",            no_argument,            &action,        DAEMON_CONTROL_STOP },
+  { "check",           no_argument,            &action,        DAEMON_CONTROL_CHECK },
+  { "reload",          no_argument,            &action,        DAEMON_CONTROL_SIGNAL },
+  { NULL,              no_argument,            NULL,           0 }
+};
+
+static void NONRET
+usage(void)
+{
+  fputs("\n\
+Usage: ucw-daemon-control --start <options> -- <daemon> <args>\n\
+   or: ucw-daemon-control --stop <options>\n\
+   or: ucw-daemon-control --reload <options>\n\
+   or: ucw-daemon-control --check <options>\n\
+\n\
+Options:\n\
+--pid-file <name>      Name of PID file for this daemon (mandatory)\n\
+--guard-file <name>    Name of guard file (default: derived from --pid-file)\n\
+--signal <sig>         Send a signal of a given name or number\n\
+                       Default: SIGTERM for --stop, SIGHUP for --reload\n\
+\n\
+Exit codes:\n\
+0                      Successfully completed\n\
+1                      Invalid arguments\n\
+100                    The action was null (e.g., --stop on a stopped daemon)\n\
+101                    The daemon was not running (on --reload or --check)\n\
+102                    The action has failed (error message was printed to stderr)\n\
+103                    The daemon was in an undefined state (e.g., stale PID file)\n\
+", stderr);
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, sig;
+  struct daemon_control_params dc = { };
+
+  while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+    switch (c)
+      {
+      case 0:
+       break;
+      case 'p':
+       dc.pid_file = optarg;
+       break;
+      case 'g':
+       dc.guard_file = optarg;
+       break;
+      case 's':
+       sig = sig_name_to_number(optarg);
+       if (sig < 0)
+         {
+           fprintf(stderr, "%s: Unknown signal %s\n", argv[0], optarg);
+           return 1;
+         }
+       dc.signal = sig;
+       break;
+      default:
+       usage();
+      }
+  if (!dc.pid_file || !action)
+    usage();
+  dc.action = action;
+
+  if (action == DAEMON_CONTROL_START)
+    {
+      if (optind >= argc)
+       usage();
+      dc.argv = argv + optind;
+    }
+  else if (optind < argc)
+    usage();
+
+  if (!dc.guard_file)
+    {
+      if (!str_has_suffix(dc.pid_file, ".pid"))
+       {
+         fprintf(stderr, "%s: For automatic choice of --guard-file, the --pid-file must end with `.pid'\n", argv[0]);
+         return 1;
+       }
+      int len = strlen(dc.pid_file);
+      char *buf = xmalloc(len + 2);
+      sprintf(buf, "%.*s.lock", len-4, dc.pid_file);
+      dc.guard_file = buf;
+    }
+
+  int err = daemon_control(&dc);
+  if (err == DAEMON_STATUS_ERROR)
+    fprintf(stderr, "%s: %s\n", argv[0], dc.error_msg);
+  return err;
+}
diff --git a/ucw/utils/ucw-daemon-helper.c b/ucw/utils/ucw-daemon-helper.c
new file mode 100644 (file)
index 0000000..61051ee
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *     A Simple Wrapper for Starting and Stopping of Daemons
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     It would seem that we are reinventing the wheel and the
+ *     start-stop-daemon command present in most Linux distributions
+ *     is just what we need, but the usual "does the process already
+ *     exist?" strategies fail in presence of multiple running daemons.
+ *
+ *     Return codes:
+ *     101     already running
+ *     102     not running
+ *
+ *     NOTE: This utility is obsolete and has been replaced by ucw-daemon-control.
+ *     You need to enable CONFIG_UCW_OBSOLETE_DAEMON_HELPER to compile it.
+ */
+
+#include <ucw/lib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <errno.h>
+#include <alloca.h>
+
+enum action {
+  ACTION_NONE,
+  ACTION_START,
+  ACTION_STOP,
+  ACTION_FORCE_STOP,
+  ACTION_CHECK,
+  ACTION_RELOAD
+};
+
+static int action;
+
+static struct option options[] = {
+  { "pid-file",                required_argument,      NULL, 'p' },
+  { "status-file",     required_argument,      NULL, 's' },
+  { "start",           no_argument,            &action, ACTION_START },
+  { "stop",            no_argument,            &action, ACTION_STOP },
+  { "force-stop",      no_argument,            &action, ACTION_FORCE_STOP },
+  { "check",           no_argument,            &action, ACTION_CHECK },
+  { "reload",          no_argument,            &action, ACTION_RELOAD },
+  { NULL,              no_argument,            NULL, 0 }
+};
+
+static void NONRET
+usage(void)
+{
+  fputs("\n\
+Usage: ucw-daemon-helper --start <options> -- <daemon> <args>\n\
+   or: ucw-daemon-helper --stop <options>\n\
+   or: ucw-daemon-helper --force-stop <options>\n\
+   or: ucw-daemon-helper --reload <options>\n\
+   or: ucw-daemon-helper --check <options>\n\
+\n\
+Options:\n\
+--pid-file <name>      Name of PID file for this daemon (mandatory)\n\
+--status-file <name>   Status file used by the daemon (deleted just before starting)\n\
+", stderr);
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, fd;
+  char *pidfile = NULL;
+  char *statfile = NULL;
+  struct flock fl;
+  char buf[64];
+
+  while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+    switch (c)
+      {
+      case 0:
+       break;
+      case 'p':
+       pidfile = optarg;
+       break;
+      case 's':
+       statfile = optarg;
+       break;
+      default:
+       usage();
+      }
+  if (!pidfile)
+    usage();
+
+  bzero(&fl, sizeof(fl));
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+
+  switch (action)
+    {
+    case ACTION_START:
+      if (optind >= argc)
+       usage();
+      fd = open(pidfile, O_RDWR | O_CREAT, 0666);
+      if (fd < 0)
+       die("Unable to create %s: %m", pidfile);
+      if ((c = fcntl(fd, F_SETLK, &fl)) < 0)
+       {
+         if (errno == EAGAIN || errno == EACCES)
+           return 101;
+         else
+           die("fcntl lock on %s failed: %m", pidfile);
+       }
+      c = sprintf(buf, "%d\n", getpid());
+      if (write(fd, buf, c) != c)
+       die("write on %s failed: %m", pidfile);
+      if (ftruncate(fd, c) < 0)
+       die("truncate on %s failed: %m", pidfile);
+      if (statfile && unlink(statfile) < 0 && errno != ENOENT)
+       die("unlink(%s) failed: %m", statfile);
+      setsid();
+      /* Disconnect from stdin and stdout, leave stderr to the daemon. */
+      close(0);
+      open("/dev/null", O_RDWR, 0);
+      dup2(0, 1);
+      argv += optind;
+      argc -= optind;
+      char **a = alloca(sizeof(char *) * (argc+1));
+      memcpy(a, argv, sizeof(char *) * argc);
+      a[argc] = NULL;
+      execv(a[0], a);
+      die("Cannot execute %s: %m", a[0]);
+    case ACTION_STOP:
+    case ACTION_FORCE_STOP:
+    case ACTION_CHECK:
+    case ACTION_RELOAD:
+      if (optind < argc)
+       usage();
+      fd = open(pidfile, O_RDWR);
+      if (fd < 0)
+       {
+         if (errno == ENOENT)
+           return 102;
+         else
+           die("Unable to open %s: %m", pidfile);
+       }
+      if ((c = fcntl(fd, F_SETLK, &fl)) >= 0)
+       {
+       nopid:
+         unlink(pidfile);
+         return 102;
+       }
+      if (errno != EAGAIN && errno != EACCES)
+       die("fcntl lock on %s failed: %m", pidfile);
+      if ((c = read(fd, buf, sizeof(buf))) < 0)
+       die("read on %s failed: %m", pidfile);
+      if (!c)
+       goto nopid;
+      if (c >= (int) sizeof(buf) || sscanf(buf, "%d", &c) != 1)
+       die("PID file syntax error");
+      int sig = 0;
+      if (action == ACTION_CHECK || action == ACTION_RELOAD)
+       {
+         if (action == ACTION_RELOAD)
+           sig = SIGHUP;
+         if (kill(c, sig) < 0 && errno == ESRCH)
+           goto nopid;
+         return 0;
+       }
+      sig = (action == ACTION_STOP) ? SIGTERM : SIGQUIT;
+      if (kill(c, sig) < 0)
+       {
+         if (errno == ESRCH)
+           goto nopid;
+         die("Cannot kill process %d: %m", c);
+       }
+      if ((c = fcntl(fd, F_SETLKW, &fl)) < 0)
+       die("Cannot lock %s: %m", pidfile);
+      if (statfile)
+       unlink(statfile);
+      if (unlink(pidfile) < 0)
+       die("Cannot unlink %s: %m", pidfile);
+      return 0;
+    default:
+      usage();
+    }
+}
diff --git a/ucw/utils/ucw-rotate-log.pl b/ucw/utils/ucw-rotate-log.pl
new file mode 100644 (file)
index 0000000..6d5ae0b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+
+#      Rotate Sherlock logs
+#      (c) 2001--2002 Martin Mares <mj@ucw.cz>
+
+use File::stat;
+
+@ARGV >= 3 or die "Usage: ucw-rotate-log <days-to-compress> <date-to-delete> <logs...>";
+
+$now = time;
+$cps = shift @ARGV;
+$del = shift @ARGV;
+
+$compress_thr = $now - 86400 * $cps;
+$delete_thr = $now - 86400 * $del;
+foreach $f (@ARGV) {
+       -f $f or next;
+       $st = stat $f or next;
+       if ($del > 0 && $st->mtime < $delete_thr) {
+               print "Deleting $f\n";
+               unlink $f || die "Delete FAILED: $!";
+       } elsif ($cps > 0 && $st->mtime < $compress_thr && $f !~ /\.(gz|bz2)$/) {
+               print "Compressing $f\n";
+               `gzip -f $f`;
+               $? && die "Compression FAILED: $!";
+       }
+}
diff --git a/ucw/utils/ucw-urltool.c b/ucw/utils/ucw-urltool.c
new file mode 100644 (file)
index 0000000..eff6598
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *     Sherlock Utilities -- URL Handling Tool
+ *
+ *     (c) 2004 Martin Mares <mj@ucw.cz>
+ */
+
+#include <ucw/lib.h>
+#include <ucw/getopt.h>
+#include <ucw/url.h>
+#include <ucw/fastbuf.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static byte *base_url;
+static struct url base;
+static uns opt_split = 0, opt_normalize = 0, opt_forgive = 0;
+static struct fastbuf *fout;
+static uns err_count;
+
+static void
+process_url(byte *url)
+{
+  byte buf1[MAX_URL_SIZE], buf2[MAX_URL_SIZE], buf3[MAX_URL_SIZE], buf4[MAX_URL_SIZE];
+  int e;
+  struct url ur;
+
+  if ((e = url_deescape(url, buf1)) || (e = url_split(buf1, &ur, buf2)))
+    goto error;
+  if ((base_url || opt_normalize) && (e = url_normalize(&ur, &base)))
+    goto error;
+  if (opt_normalize && (e = url_canonicalize(&ur)))
+    goto error;
+  if (opt_split)
+    {
+      if (ur.protocol)
+       bprintf(fout, "protocol=%s\n", ur.protocol);
+      if (ur.user)
+       bprintf(fout, "user=%s\n", ur.user);
+      if (ur.pass)
+       bprintf(fout, "pass=%s\n", ur.pass);
+      if (ur.host)
+       bprintf(fout, "host=%s\n", ur.host);
+      if (ur.port != ~0U)
+       bprintf(fout, "port=%d\n", ur.port);
+      if (ur.rest)
+       bprintf(fout, "rest=%s\n", ur.rest);
+      bputc(fout, '\n');
+    }
+  else
+    {
+      if ((e = url_pack(&ur, buf3)) || (e = url_enescape(buf3, buf4)))
+       goto error;
+      bprintf(fout, "%s\n", buf4);
+    }
+  return;
+
+ error:
+  msg(L_ERROR, "%s: %s", url, url_error(e));
+  err_count++;
+}
+
+static char *shortopts = CF_SHORT_OPTS "b:fns";
+static struct option longopts[] =
+{
+  CF_LONG_OPTS
+  { "base",            1, 0, 'b' },
+  { "forgive",         0, 0, 'f' },
+  { "normalize",       0, 0, 'n' },
+  { "split",           0, 0, 's' },
+  { NULL,              0, 0, 0 }
+};
+
+static char *help = "\
+Usage: ucw-urltool [<options>] <operations> [<URL's>]\n\
+\n\
+Options:\n"
+CF_USAGE "\
+-b, --base <URL>\tInput URL's are relative to this base\n\
+-f, --forgive\t\tReturn exit status 0 even if there were errors\n\
+\n\
+Operations:\n\
+-s, --split\t\tSplit a given URL to components\n\
+-n, --normalize\t\tNormalize given URL\n\
+";
+
+static void NONRET
+usage(byte *msg)
+{
+  if (msg)
+    {
+      fputs(msg, stderr);
+      fputc('\n', stderr);
+    }
+  fputs(help, stderr);
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  int opt, err;
+  byte *base_url = NULL;
+  byte basebuf1[MAX_URL_SIZE], basebuf2[MAX_URL_SIZE];
+
+  log_init(argv[0]);
+  while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
+    switch (opt)
+      {
+      case 'b':
+       base_url = optarg;
+       err = url_canon_split(base_url, basebuf1, basebuf2, &base);
+       if (err)
+         die("Invalid base URL: %s", url_error(err));
+       break;
+      case 's':
+       opt_split = 1;
+       break;
+      case 'n':
+       opt_normalize = 1;
+       break;
+      case 'f':
+       opt_forgive = 1;
+       break;
+      default:
+       usage("Invalid option");
+      }
+
+  fout = bfdopen_shared(1, 4096);
+  if (optind >= argc)
+    {
+      struct fastbuf *fin = bfdopen_shared(0, 4096);
+      byte url[MAX_URL_SIZE];
+      while (bgets(fin, url, sizeof(url)))
+       process_url(url);
+      bclose(fin);
+    }
+  else
+    while (optind < argc)
+      process_url(argv[optind++]);
+  bclose(fout);
+
+  return (err_count && !opt_forgive);
+}
diff --git a/ucw/utils/urltool.c b/ucw/utils/urltool.c
deleted file mode 100644 (file)
index a9ac197..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- *     Sherlock Utilities -- URL Handling Tool
- *
- *     (c) 2004 Martin Mares <mj@ucw.cz>
- */
-
-#include <ucw/lib.h>
-#include <ucw/getopt.h>
-#include <ucw/url.h>
-#include <ucw/fastbuf.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static byte *base_url;
-static struct url base;
-static uns opt_split = 0, opt_normalize = 0, opt_forgive = 0;
-static struct fastbuf *fout;
-static uns err_count;
-
-static void
-process_url(byte *url)
-{
-  byte buf1[MAX_URL_SIZE], buf2[MAX_URL_SIZE], buf3[MAX_URL_SIZE], buf4[MAX_URL_SIZE];
-  int e;
-  struct url ur;
-
-  if ((e = url_deescape(url, buf1)) || (e = url_split(buf1, &ur, buf2)))
-    goto error;
-  if ((base_url || opt_normalize) && (e = url_normalize(&ur, &base)))
-    goto error;
-  if (opt_normalize && (e = url_canonicalize(&ur)))
-    goto error;
-  if (opt_split)
-    {
-      if (ur.protocol)
-       bprintf(fout, "protocol=%s\n", ur.protocol);
-      if (ur.user)
-       bprintf(fout, "user=%s\n", ur.user);
-      if (ur.pass)
-       bprintf(fout, "pass=%s\n", ur.pass);
-      if (ur.host)
-       bprintf(fout, "host=%s\n", ur.host);
-      if (ur.port != ~0U)
-       bprintf(fout, "port=%d\n", ur.port);
-      if (ur.rest)
-       bprintf(fout, "rest=%s\n", ur.rest);
-      bputc(fout, '\n');
-    }
-  else
-    {
-      if ((e = url_pack(&ur, buf3)) || (e = url_enescape(buf3, buf4)))
-       goto error;
-      bprintf(fout, "%s\n", buf4);
-    }
-  return;
-
- error:
-  msg(L_ERROR, "%s: %s", url, url_error(e));
-  err_count++;
-}
-
-static char *shortopts = CF_SHORT_OPTS "b:fns";
-static struct option longopts[] =
-{
-  CF_LONG_OPTS
-  { "base",            1, 0, 'b' },
-  { "forgive",         0, 0, 'f' },
-  { "normalize",       0, 0, 'n' },
-  { "split",           0, 0, 's' },
-  { NULL,              0, 0, 0 }
-};
-
-static char *help = "\
-Usage: urltool [<options>] <operations> [<URL's>]\n\
-\n\
-Options:\n"
-CF_USAGE "\
--b, --base <URL>\tInput URL's are relative to this base\n\
--f, --forgive\t\tReturn exit status 0 even if there were errors\n\
-\n\
-Operations:\n\
--s, --split\t\tSplit a given URL to components\n\
--n, --normalize\t\tNormalize given URL\n\
-";
-
-static void NONRET
-usage(byte *msg)
-{
-  if (msg)
-    {
-      fputs(msg, stderr);
-      fputc('\n', stderr);
-    }
-  fputs(help, stderr);
-  exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
-  int opt, err;
-  byte *base_url = NULL;
-  byte basebuf1[MAX_URL_SIZE], basebuf2[MAX_URL_SIZE];
-
-  log_init(argv[0]);
-  while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
-    switch (opt)
-      {
-      case 'b':
-       base_url = optarg;
-       err = url_canon_split(base_url, basebuf1, basebuf2, &base);
-       if (err)
-         die("Invalid base URL: %s", url_error(err));
-       break;
-      case 's':
-       opt_split = 1;
-       break;
-      case 'n':
-       opt_normalize = 1;
-       break;
-      case 'f':
-       opt_forgive = 1;
-       break;
-      default:
-       usage("Invalid option");
-      }
-
-  fout = bfdopen_shared(1, 4096);
-  if (optind >= argc)
-    {
-      struct fastbuf *fin = bfdopen_shared(0, 4096);
-      byte url[MAX_URL_SIZE];
-      while (bgets(fin, url, sizeof(url)))
-       process_url(url);
-      bclose(fin);
-    }
-  else
-    while (optind < argc)
-      process_url(argv[optind++]);
-  bclose(fout);
-
-  return (err_count && !opt_forgive);
-}