Send commitlog mailing list submissions to
        commitlog@lists.openmoko.org

To subscribe or unsubscribe via the World Wide Web, visit
        http://lists.openmoko.org/mailman/listinfo/commitlog
or, via email, send a message with subject or body 'help' to
        commitlog-requ...@lists.openmoko.org

You can reach the person managing the list at
        commitlog-ow...@lists.openmoko.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of commitlog digest..."
Today's Topics:

   1. r4924 - in developers/werner: . stdlog (wer...@docs.openmoko.org)
--- Begin Message ---
Author: werner
Date: 2009-02-23 07:32:57 +0100 (Mon, 23 Feb 2009)
New Revision: 4924

Added:
   developers/werner/stdlog/
   developers/werner/stdlog/Makefile
   developers/werner/stdlog/stdlog.c
Log:
"Script" workalike but without requiring a tty.



Added: developers/werner/stdlog/Makefile
===================================================================
--- developers/werner/stdlog/Makefile                           (rev 0)
+++ developers/werner/stdlog/Makefile   2009-02-23 06:32:57 UTC (rev 4924)
@@ -0,0 +1,11 @@
+CFLAGS=-Wall -g
+
+.PHONY:                clean spotless
+
+stdlog:
+
+clean:
+               rm -f *.o
+
+spotless:      clean
+               rm -f stdlog

Added: developers/werner/stdlog/stdlog.c
===================================================================
--- developers/werner/stdlog/stdlog.c                           (rev 0)
+++ developers/werner/stdlog/stdlog.c   2009-02-23 06:32:57 UTC (rev 4924)
@@ -0,0 +1,329 @@
+/*
+ * stdlog.c - Log stdin/stdout to a file (similar to "script", but without tty)
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by Werner Almesberger <wer...@openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
+#include <wait.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/select.h>
+
+
+#define COPY_BUFFER 4096
+
+
+static int fds[3][2];
+static pid_t pid;
+static int file;
+static time_t t0, last;
+static int timestamps = 0;
+
+
+static void child(char *const *argv)
+{
+    int i;
+
+    for (i = 0; i != 3; i++) {
+       if (close(fds[i][!i]) < 0) {
+           perror("close");
+           exit(1);
+       }
+       if (dup2(fds[i][!!i], i) < 0) {
+           perror("dup2");
+           exit(1);
+       }
+    }
+    execvp(*argv, argv);
+    perror(*argv);
+    exit(1);
+}
+
+
+static void write_all(int fd, void *data, size_t size)
+{
+    size_t done;
+    size_t wrote;
+
+    for (done = 0; done != size; done += wrote) {
+       wrote = write(fd, data+done, size-done);
+       if (wrote < 0) {
+           perror("write");
+           exit(1);
+       }
+       if (!wrote)
+           return;
+    }
+}
+
+
+static void write_file(void *data, size_t size)
+{
+    static char buffer[COPY_BUFFER];
+    static size_t buf_len;
+    const char *p, *nl = NULL;
+
+    if (buf_len)
+       write_all(file, buffer, buf_len);
+    buf_len = 0;
+    for (p = data; p != data+size; p++)
+       if (*p == '\n')
+           nl = p;
+    if (!nl)
+       write_all(file, data, size);
+    else {
+       write_all(file, data, nl-(char *) data+1);
+       buf_len = size-(nl-(char *) data+1);
+       memcpy(buffer, nl+1, buf_len);
+    }
+}
+
+
+static void copy(int from, int *to)
+{
+    char buf[COPY_BUFFER];
+    ssize_t got;
+
+    assert(*to != -1);
+    got = read(from, buf, sizeof(buf));
+    if (got < 0) {
+       perror("read");
+       exit(1);
+    }
+    if (!got) {
+       if (close(*to) < 0) {
+           perror("close");
+           exit(1);
+       }
+       *to = -1;
+       return;
+    }
+    write_all(*to, buf, got);
+    if (from)
+       write_file(buf, got);
+}
+
+
+static void set_signal(int sig, void (*handler)(int sig))
+{
+    if (signal(sig, handler) == SIG_ERR) {
+       perror("signal");
+       exit(1);
+    }
+}
+
+
+static void forward(int sig)
+{
+    if (kill(pid, sig) < 0)
+       perror("kill");
+}
+
+
+static void many_signals(void (*handler)(int sig))
+{
+    static int signals[] = {
+       SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGUSR2, SIGTERM, 0
+    };
+    int *sig;
+
+    for (sig = signals; *sig; sig++)
+       set_signal(*sig, handler);
+}
+
+
+static void sigchld(int sig)
+{
+    /* do nothing - all we need is the EINTR */
+}
+
+
+static void block(int how)
+{
+    sigset_t set;
+
+    if (sigemptyset(&set) < 0) {
+       perror("sigemptyset");
+       exit(1);
+    }
+    if (sigaddset(&set, SIGCHLD) < 0) {
+       perror("sigaddset");
+       exit(1);
+    }
+    if (sigprocmask(how, &set, NULL) < 0) {
+       perror("sigprocmask");
+       exit(1);
+    }
+}
+
+
+static void do_timestamp(void)
+{
+    char buf[20];
+    time_t t;
+    int len;
+
+    if (time(&t) < 0) {
+       perror("time");
+       exit(1);
+    }
+    if (t-last < timestamps)
+       return;
+    last += timestamps;
+    len = sprintf(buf, "--- %ld ---\n", (long) (t-t0));
+    write_file(buf, len);
+}
+
+
+static void parent(void)
+{
+    struct timeval to;
+    int i, max_fd;
+    pid_t pid;
+    int status;
+    int out = 1, err = 2;
+
+    for (i = 0; i != 3; i++)
+       if (close(fds[i][!!i]) < 0) {
+           perror("close");
+           exit(1);
+       }
+    block(SIG_BLOCK);
+    set_signal(SIGCHLD, sigchld);
+    many_signals(forward);
+    max_fd = fds[1][0] > fds[2][0] ? fds[1][0] : fds[2][0];
+    do {
+       fd_set set;
+       int n;
+
+       FD_ZERO(&set);
+       if (fds[0][1] != -1)
+           FD_SET(0, &set);
+       if (out != -1)
+           FD_SET(fds[1][0], &set);
+       if (err != -1)
+           FD_SET(fds[2][0], &set);
+       to.tv_sec = 1;
+       to.tv_usec = 0;
+       /*
+        * This can still race. However, if it does, we'll still catch the
+        * process through the timeout. "pselect" would be better.
+        */
+       block(SIG_UNBLOCK);
+       n = select(max_fd+1, &set, NULL, NULL, &to);
+       block(SIG_BLOCK);
+       if (n < 0 && errno != EINTR) {
+           perror("select");
+           exit(1);
+       }
+       if (FD_ISSET(0, &set))
+           copy(0, &fds[0][1]);
+       if (FD_ISSET(fds[1][0], &set))
+           copy(fds[1][0], &out);
+       if (FD_ISSET(fds[2][0], &set))
+           copy(fds[2][0], &err);
+       if (timestamps)
+           do_timestamp();
+       pid = waitpid(-1, &status, WNOHANG);
+    }
+    while (!pid);
+    if (pid < 0) {
+       perror("wait");
+       exit(1);
+    }
+    if (WIFEXITED(status))
+       _exit(WEXITSTATUS(status));
+    if (WIFSIGNALED(status)) {
+       many_signals(SIG_DFL);
+       raise(WTERMSIG(status));
+    }
+    fprintf(stderr, "status %d\n", status);
+    _exit(1);
+}
+
+
+static void usage(const char *name)
+{
+    fprintf(stderr,
+"usage: %s [-a] [-t] file command ...\n"
+"  -a       append to existing log file\n"
+"  -t secs  periodically write a timestamp\n"
+  , name);
+    exit(1);
+}
+
+
+int main(int argc, char *const *argv)
+{
+    int append = 0;
+    int c, i;
+
+    while ((c = getopt(argc, argv, "+at:")) != EOF)
+       switch (c) {
+           char *end;
+
+           case 'a':
+               append = 1;
+               break;
+           case 't':
+               timestamps = strtoul(optarg, &end, 0);
+               if (*end) {
+                   usage(*argv);
+                   exit(1);
+               }
+               break;
+           default:
+               usage(*argv);
+       }
+    if (argc-optind < 2)
+       usage(*argv);
+    file = open(argv[optind],
+      O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+    if (file < 0) {
+       perror(argv[optind]);
+       exit(1);
+    }
+    for (i = 0; i != 3; i++)
+       if (pipe(fds[i]) < 0) {
+           perror("pipe");
+           exit(1);
+       }
+    if (timestamps) {
+       if (time(&t0) < 0) {
+           perror("time");
+           exit(1);
+       }
+       last = t0;
+    }
+    pid = fork();
+    if (!pid)
+       child(argv+optind+1);
+    else
+       parent();
+    return 1;
+}




--- End Message ---
_______________________________________________
commitlog mailing list
commitlog@lists.openmoko.org
http://lists.openmoko.org/mailman/listinfo/commitlog

Reply via email to