splitconf z buf create inplace
SBINSCRIPTS = shadowfix
SCRIPTS = $(BINSCRIPTS) $(SBINSCRIPTS)
-BINPROGS = not cdb-probe cdb-check-domain gorp locking if-mtu pause
+BINPROGS = not cdb-probe cdb-check-domain gorp locking if-mtu pause stamp
SBINPROGS = qmail-checkspam
PROGS = $(BINPROGS) $(SBINPROGS)
PERLLIBS = MdwOpt.pm
DISTMAN1 = \
not.1 z.1 cdb-assign.1 cdb-map.1 cdb-list.1 cdb-probe.1 \
cdb-check-domain.1 \
- gorp.1 unfwd.1 splitconf.1 locking.1 if-mtu.1 pause.1 \
+ gorp.1 unfwd.1 splitconf.1 locking.1 if-mtu.1 pause.1 stamp.1 \
buf.1 create.1 inplace.1
MAN1 = $(DISTMAN1)
DISTMAN8 = qmail-checkspam.8
if-mtu: if-mtu.o
$(LINK)
+stamp: stamp.o
+ $(LINK) -lmLib
+
shadowfix.8: shadowfix
pod2man --section 8 shadowfix >shadowfix.8.new
mv shadowfix.8.new shadowfix.8
Architecture: all
Section: utils
Depends: mdwopt-perl, nsict-cdb, locking, qmail-checkspam, nsict-mail,
- if-mtu, shadowfix, zz, gorp, splitconf, xtitle, pause, buf, create, inplace
+ if-mtu, shadowfix, zz, gorp, splitconf, xtitle, pause, buf, create, inplace,
+ stamp
Description: Dummy package for convenience.
Package: mdwopt-perl
Architecture: all
Section: utils
Description: Update files in place safely.
+
+Package: stamp
+Architecture: any
+Section: utils
+Description: Like cat, but prefixing each line with a datestamp.
--- /dev/null
+.\" -*-nroff-*-
+.TH stamp 1 "11 August 2006" "Straylight/Edgeware"
+.SH NAME
+stamp \- copy files, prefixing each line with a datestamp
+.SH SYNOPSIS
+.B stamp
+.RB [ \-z ]
+.RB [ \-f
+.IR format ]
+.RI [ file ...]
+.SH DESCRIPTION
+Copies files, like
+.BR cat (1),
+except that it prefixes each line with a datestamp indicating when the
+line was recieved. The datestamp is formatted using
+.BR strftime (3),
+and can use any formatting codes permitted by that function.
+.PP
+Options available:
+.TP
+.B \-h, \-\-help
+Show a help message for
+.BR stamp .
+.TP
+.B \-v, \-\-version
+Show version number for
+.BR stamp .
+.TP
+.B \-u, \-\-usage
+Show usage message for
+.BR stamp .
+.TP
+.BI "\-f, \-\-format=" format
+Use
+.I format
+as the
+.BR strftime (3)
+format string for the datestamps. Note that if the datestamp is meant
+to be separated from the rest of the line by anything, then that
+separator should be part of the format string.
+.TP
+.B \-z, \-\-utc, \-\-zulu
+Use UTC (Zulu time) instead of local time for datestamps.
+.SH BUGS
+While
+.B stamp
+ensures that its input is line-buffered only, it's possible that
+whatever is providing that input delays it arbitrarily due to its own
+buffering. There's not much to be done about this.
+.SH AUTHOR
+Mark Wooding, <mdw@distorted.org.uk>
+.SH SEE ALSO
+.BR cat (1),
+.BR strftime (3).
--- /dev/null
+/* -*-
+ *
+ * Like cat, with datestamps
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <unistd.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+static const char *fmt = "%Y-%m-%d %H:%M:%S %Z: ";
+static struct tm *(*cvt)(const time_t *) = localtime;
+
+static void version(void) { pquis(stdout, "$ " VERSION); }
+static void usage(FILE *fp)
+ { pquis(fp, "Usage: $ [-z] [-f FORMAT] [FILE...]"); }
+
+static void help(void)
+{
+ version(); putchar('\n');
+ usage(stdout);
+ fputs("\n\
+Copy the FILEs (or standard input) to standard output, prefixing each line\n\
+with a datestamp.\n\
+\n\
+-h, --help Show this help text.\n\
+-v, --version Show the program's version number.\n\
+-u, --usage Show a brief usage message.\n\
+\n\
+-f, --format=FORMAT Write datestamps using the strftime(3) FORMAT.\n\
+-z, --utc, --zulu Use UTC rather than local time for datestamps.\n\
+", stdout);
+}
+
+static void cat(FILE *in)
+{
+ unsigned ln = 1;
+ time_t t;
+ struct tm *tm;
+ char buf[256];
+ int ch;
+
+ for (;;) {
+ if ((ch = getc(in)) == EOF)
+ break;
+ if (ln) {
+ t = time(0);
+ tm = cvt(&t);
+ strftime(buf, sizeof(buf), fmt, tm);
+ fwrite(buf, 1, strlen(buf), stdout);
+ }
+ putchar(ch);
+ ln = (ch == '\n');
+ }
+ if (!ln)
+ putchar('\n');
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ FILE *fp;
+ unsigned f = 0;
+#define F_BOGUS 1u
+
+ ego(argv[0]);
+ setvbuf(stdin, 0, _IOLBF, 0);
+
+ for (;;) {
+ static const struct option opt[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "usage", 0, 0, 'u' },
+ { "format", OPTF_ARGREQ, 0, 'f' },
+ { "utc", 0, 0, 'z' },
+ { "zulu", 0, 0, 'z' },
+ { 0, 0, 0, 0 }
+ };
+
+ if ((i = mdwopt(argc, argv, "hvuf:z", opt, 0, 0, 0)) < 0)
+ break;
+ switch (i) {
+ case 'h':
+ help();
+ exit(0);
+ case 'v':
+ version();
+ exit(0);
+ case 'u':
+ usage(stdout);
+ exit(0);
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'z':
+ cvt = gmtime;
+ break;
+ default:
+ f |= F_BOGUS;
+ break;
+ }
+ }
+
+ if (f & F_BOGUS) {
+ usage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (optind == argc) {
+ if (isatty(STDIN_FILENO))
+ die(EXIT_FAILURE, "no arguments, and stdin is a terminal");
+ cat(stdin);
+ } else for (i = optind; i < argc; i++) {
+ if (strcmp(argv[i], "-") == 0)
+ cat(stdin);
+ else if ((fp = fopen(argv[i], "r")) == 0) {
+ moan("failed to open `%s': %s", argv[i], strerror(errno));
+ f |= F_BOGUS;
+ } else {
+ cat(fp);
+ fclose(fp);
+ }
+ }
+
+ if (ferror(stdout) || fflush(stdout) || fclose(stdout)) {
+ moan("error writing output: %s", strerror(errno));
+ f |= F_BOGUS;
+ }
+
+ return ((f & F_BOGUS) ? EXIT_FAILURE : 0);
+}