Set("CONFIG_UCW_PERL" => 1);
Set("CONFIG_UCW_PERL_MODULES" => 1);
Set("CONFIG_UCW_SHELL_UTILS" => 1);
+Set("CONFIG_UCW_UTILS" => 1);
# Libsh settings
Set("CONFIG_BUCKET_SHIFT" => 6);
DIRS+=ucw
LIBUCW=$(o)/ucw/libucw.pc
-PROGS+=$(o)/ucw/basecode
+ifdef CONFIG_UCW_UTILS
+UCW_UTILS=basecode b224 rotate-log urltool daemon-helper hex
+
+PROGS+=$(addprefix $(o)/ucw/,$(UCW_UTILS))
+endif
LIBUCW_MODS= \
threads \
TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test stkstring.test \
slists.test kmp-test.test bbuf.test getopt.test ff-unicode.test eltpool.test \
fb-socket.test trie-test.test string.test sha1.test asort-test.test binheap-test.test \
- redblack-test.test basecode.test fb-file.test fb-grow.test fb-pool.test fb-atomic.test \
+ redblack-test.test fb-file.test fb-grow.test fb-pool.test fb-atomic.test \
fb-limfd.test fb-temp.test fb-mem.test fb-buffer.test fb-mmap.test url.test)
$(o)/ucw/regex.test: $(o)/ucw/regex-t
$(o)/ucw/asort-test.test: $(o)/ucw/asort-test
$(o)/ucw/binheap-test.test: $(o)/ucw/binheap-test
$(o)/ucw/redblack-test.test: $(o)/ucw/redblack-test
-$(o)/ucw/basecode.test: $(o)/ucw/basecode
$(addprefix $(o)/ucw/fb-,file.test grow.test pool.test socket.test atomic.test \
limfd.test temp.test mem.test buffer.test mmap.test): %.test: %-t
$(o)/ucw/fb-atomic-tt.o: CFLAGS += -DFB_ATOMIC_TRACE
ifdef CONFIG_UCW_SHELL_UTILS
include $(s)/ucw/shell/Makefile
endif
+
+ifdef CONFIG_UCW_UTILS
+$(o)/ucw/b224: $(o)/ucw/b224.o $(LIBUCW)
+$(o)/ucw/daemon-helper: $(o)/ucw/daemon-helper.o $(LIBUCW)
+$(o)/ucw/urltool: $(o)/ucw/urltool.o $(LIBUCW)
+$(o)/ucw/hex: $(o)/ucw/hex.o $(LIBUCW)
+
+TESTS+=$(o)/ucw/basecode.test
+$(o)/ucw/basecode.test: $(o)/ucw/basecode
+endif
--- /dev/null
+/*
+ * A Program For Manipulation With Base224 Encoded Files
+ *
+ * (c) 2002 Martin Mares <mj@ucw.cz>
+ */
+
+#include "ucw/lib.h"
+#include "ucw/fastbuf.h"
+#include "ucw/base224.h"
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ struct fastbuf *in = bfdopen_shared(0, 4096);
+ struct fastbuf *out = bfdopen_shared(1, 4096);
+ byte ib[BASE224_IN_CHUNK*10], ob[BASE224_OUT_CHUNK*10], *b;
+ uns il, ol;
+
+ if (argc != 2 || argv[1][0] != '-')
+ goto usage;
+
+ switch (argv[1][1])
+ {
+ case 'e': /* Plain encoding */
+ while (il = bread(in, ib, sizeof(ib)))
+ {
+ ol = base224_encode(ob, ib, il);
+ bwrite(out, ob, ol);
+ }
+ break;
+ case 'E': /* Line block encoding */
+ while (il = bread(in, ib, BASE224_IN_CHUNK*6))
+ {
+ ol = base224_encode(ob, ib, il);
+ bputc(out, 'N');
+ bwrite(out, ob, ol);
+ bputc(out, '\n');
+ }
+ break;
+ case 'd': /* Plain decoding */
+ while (ol = bread(in, ob, sizeof(ob)))
+ {
+ il = base224_decode(ib, ob, ol);
+ bwrite(out, ib, il);
+ }
+ break;
+ case 'D': /* Line block decoding */
+ while (b = bgets(in, ob, sizeof(ob)))
+ {
+ if (!ob[0])
+ die("Invalid line syntax");
+ il = base224_decode(ib, ob+1, b-ob-1);
+ bwrite(out, ib, il);
+ }
+ break;
+ default:
+ usage:
+ fputs("Usage: b224 (-e|-E|-d|-D)\n", stderr);
+ return 1;
+ }
+
+ bclose(in);
+ bclose(out);
+ return 0;
+}
--- /dev/null
+/*
+ * 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
+ */
+
+#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();
+ }
+}
# Include support utilities for shell scripts
Set("CONFIG_UCW_SHELL_UTILS" => 1);
+# Include utilities
+Set("CONFIG_UCW_UTILS" => 1);
+
# Default configuration file
UnSet("DEFAULT_CONFIG");
--- /dev/null
+/*
+ * Hexadecimal dumper (CP/M style format)
+ *
+ * Original version (c) Eric S. Raymond <esr@snark.thyrsus.com>
+ * Heavily modified by Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "ucw/lib.h"
+#include "ucw/lfs.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define DEFWIDTH 16 /* Default # chars to show per line */
+#define MAXWIDTH 32 /* Maximum # of bytes per line */
+
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+static long linesize = DEFWIDTH; /* # of bytes to print per line */
+static bool cflag = FALSE; /* show printables as ASCII if true */
+static bool gflag = FALSE; /* suppress mid-page gutter if true */
+static ucw_off_t start = 0; /* file offset to start dumping at */
+static ucw_off_t length = 0; /* if nz, how many chars to dump */
+
+static void dumpfile(FILE *f)
+ /* dump a single, specified file -- stdin if filename is NULL */
+{
+ int ch = '\0'; /* current character */
+ char ascii[MAXWIDTH+3]; /* printable ascii data */
+ int i = 0; /* counter: # bytes processed */
+ int ai = 0; /* index into ascii[] */
+ ucw_off_t offset = start; /* byte offset of line in file */
+ int hpos = 0; /* horizontal position counter */
+ ucw_off_t fstart = start;
+ ucw_off_t flength = length;
+ char *specials = "\b\f\n\r\t";
+ char *escapes = "bfnrt";
+ char *cp;
+
+ if (fstart && ucw_seek(fileno(f), fstart, SEEK_SET) >= 0)
+ fstart = 0;
+
+ do {
+ ch = getc(f);
+
+ if (ch != EOF)
+ {
+ if (length && flength-- <= 0)
+ ch = EOF;
+ }
+
+ if (ch != EOF)
+ {
+ if (i++ % linesize == 0)
+ {
+ (void) printf("%04Lx ", (long long) offset);
+ offset += linesize;
+ hpos = 5;
+ }
+
+ /* output one space for the mid-page gutter */
+ if (!gflag)
+ if ((i - 1) % (linesize / 2) == 0)
+ {
+ (void) putchar(' ');
+ hpos++;
+ ascii[ai++] = ' ';
+ }
+
+ /* dump the indicated representation of a character */
+ ascii[ai] = (isprint (ch) || ch == ' ') ? ch : '.';
+
+ if (cflag && (isprint(ch) || ch == ' '))
+ (void) printf("%c ", ch);
+ else if (cflag && ch && (cp = strchr(specials, ch)))
+ (void) printf("\\%c ", escapes[cp - specials]);
+ else
+ (void) printf("%02x ", ch);
+
+ /* update counters and things */
+ ai++;
+ hpos += 3;
+ }
+
+ /* At end-of-line or EOF, show ASCII version of data. */
+ if (i && (ch == EOF || (i % linesize == 0)))
+ {
+ if (!cflag)
+ {
+ while (hpos < linesize * 3 + 7)
+ {
+ hpos++;
+ (void) putchar(' ');
+ }
+
+ ascii[ai] = '\0';
+ (void) printf("%s", ascii);
+ }
+
+ if (ch != EOF || (i % linesize != 0))
+ (void) putchar('\n');
+ ai = 0; /* reset counters */
+ }
+ } while
+ (ch != EOF);
+}
+
+static ucw_off_t getoffs(char *cp)
+ /* fetch decimal or hex integer to be used as file start or offset */
+{
+ ucw_off_t value = 0;
+ char *hexdigits = "0123456789abcdefABCDEF";
+
+#if 0
+ bool foundzero = FALSE;
+ int base = 0;
+
+ for (; *cp; cp++)
+ if (*cp == '0')
+ foundzero = TRUE;
+ else if (isdigit(*cp))
+ {
+ base = 10;
+ break;
+ }
+ else if (*cp = 'x' || *cp == 'X' || *cp == 'h' || *cp == 'H')
+ {
+ base = 16;
+ cp++;
+ break;
+ }
+ else
+ return(-1L);
+
+ if (base == 0)
+ if (foundzero)
+ base = 10;
+ else
+ return(-1L);
+
+ if (base == 10)
+ {
+ for (; *cp; cp++)
+ if (isdigit(*cp))
+ value = value * 10 + (*cp - '0');
+ else
+ return(-1L);
+ }
+ else
+#endif
+ {
+ for (; *cp; cp++)
+ if (strchr(hexdigits, *cp))
+ value = value*16 + (strchr(hexdigits, tolower(*cp))-hexdigits);
+ else
+ return -1;
+ }
+
+ return(value);
+}
+
+int main(int argc, char **argv)
+{
+ FILE *infile; /* file pointer input file */
+ int dumpcount = 0; /* count of files dumped so far */
+ char *cp;
+ int fd;
+
+ for (argv++, argc--; argc > 0; argv++, argc--)
+ {
+ char s = **argv;
+
+ if (s == '-' || s == '+')
+ {
+ int c = *++*argv;
+
+ switch (c)
+ {
+ case 'c': cflag = (s == '-'); continue;
+ case 'g': gflag = (s == '-'); continue;
+
+ case 's':
+ if ((*argv)[1])
+ (*argv)++;
+ else
+ argc--, argv++;
+ if (s == '-' && argc >= 0)
+ {
+ if (cp = strchr(*argv, ','))
+ *cp++ = '\0';
+ if ((start = getoffs(*argv)) < 0)
+ {
+ (void) fputs("hex: start offset no good\n", stderr);
+ exit(1);
+ }
+
+ if (cp)
+ if ((length = getoffs(cp)) < 0)
+ {
+ (void) fputs("hex: length no good\n", stderr);
+ exit(1);
+ }
+ }
+ else
+ start = length = 0L;
+ continue;
+
+ case '\0':
+ infile = stdin;
+ break;
+
+ case 'w':
+ if ((*argv)[1])
+ (*argv)++;
+ else
+ argc--, argv++;
+ if ((linesize = getoffs(*argv)) == -1L || linesize > MAXWIDTH)
+ {
+ (void) fputs("hex: line width no good\n", stderr);
+ exit(1);
+ }
+ if (linesize % 2)
+ gflag = TRUE;
+ continue;
+
+ default:
+ (void) fprintf(stderr, "hex: no such option as %s\n", *argv);
+ exit(1);
+ }
+ }
+ else
+ {
+ fd = ucw_open(*argv, O_RDONLY, 0);
+ if (fd < 0 || !(infile = fdopen(fd, "r")))
+ {
+ (void) fprintf(stderr, "hex: cannot open %s: %m\n", *argv);
+ exit(1);
+ }
+ }
+
+ if (dumpcount > 0 || argc > 1)
+ if (infile == stdin)
+ (void) printf("---- <Standard input> ----\n");
+ else
+ (void) printf("---- %s ----\n", *argv);
+ dumpfile(infile);
+ dumpcount++;
+ if (infile != stdin)
+ (void) fclose(infile);
+ }
+
+ if (dumpcount == 0)
+ dumpfile(stdin);
+ return(0);
+}
--- /dev/null
+#!/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: $!";
+ }
+}
--- /dev/null
+/*
+ * 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);
+}