]> err.no Git - moreutils/commitdiff
* Add mispipe, contributed by Nathanael Nerode. Pipes together two commands,
authorjoeyh <joeyh>
Fri, 8 Sep 2006 00:33:43 +0000 (00:33 +0000)
committerjoeyh <joeyh>
Fri, 8 Sep 2006 00:33:43 +0000 (00:33 +0000)
  returning the exit status of the first.

Makefile
README
debian/changelog
debian/control
debian/copyright
mispipe.c [new file with mode: 0644]
mispipe.docbook [new file with mode: 0644]

index e8d92ee7989fbb048bdad5785e91bee39209ee28..8f9db54f0831cdd86de5ee4134837277abcf8a71 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-BINS=isutf8 ifdata pee sponge
+BINS=isutf8 ifdata pee sponge mispipe
 PERLSCRIPTS=vidir vipe ts combine zrun
-MANS=sponge.1 vidir.1 vipe.1 isutf8.1 ts.1 combine.1 ifdata.1 pee.1 zrun.1
+MANS=sponge.1 vidir.1 vipe.1 isutf8.1 ts.1 combine.1 ifdata.1 pee.1 zrun.1 mispipe.1
 CFLAGS=-O2 -g -Wall
 
 all: $(BINS) $(MANS)
@@ -31,5 +31,8 @@ pee.1: pee.docbook
 sponge.1: sponge.docbook
        docbook2x-man $<
 
+mispipe.1: mispipe.docbook
+       docbook2x-man $<
+
 %.1: %
        pod2man --center=" " --release="moreutils" $< > $@;
diff --git a/README b/README
index 47a77be64908f0f8adb2ee830294bd4bce6e63b1..6ccbe7ff69a745af6ab82c2e69bf47258c38885b 100644 (file)
--- a/README
+++ b/README
@@ -19,6 +19,8 @@ pee
        tee standard input to pipes
 zrun
        automatically uncompress arguments to command
+mispipe
+       pipe two commands, returning the exit status of the first
 
 
 Its web page is here: http://kitenet.net/~joey/code/moreutils.html
index 99643c8e3d4a0ce55d9888134673a464036b513f..3ae051e83d5a4702da601d24011ebda728143e2b 100644 (file)
@@ -1,8 +1,10 @@
 moreutils (0.17) UNRELEASED; urgency=low
 
   * Add missing \n to sponge usage. Closes: #383944
+  * Add mispipe, contributed by Nathanael Nerode. Pipes together two commands,
+    returning the exit status of the first.
 
- -- Joey Hess <joeyh@debian.org>  Sun, 20 Aug 2006 18:36:04 -0400
+ -- Joey Hess <joeyh@debian.org>  Thu,  7 Sep 2006 20:20:26 -0400
 
 moreutils (0.16) unstable; urgency=low
 
index ced07eb9a88674af72c8ed8c34de8adadb24d1ce..3dd98df154a72a5bd0e2e252bc7f96646622009c 100644 (file)
@@ -23,3 +23,4 @@ Description: additional unix utilities
   - ifdata: get network interface info without parsing ifconfig output
   - pee: tee standard input to pipes
   - zrun: automatically uncompress arguments to command
+  - mispipe: pipe two commands, returning the exit status of the first
index b53bfaf006a85f8000e01346913ac776b05d2674..22e443e9335603a16ec945518cd82d206d32c8a5 100644 (file)
@@ -4,7 +4,7 @@ This package was put together and debianized by Joey Hess
 isutf8 is Copyright (C) 2005 by Lars Wirzenius, under the terms of
 the GPL.
 
-spong is Copyright (C) 2006 by Tollef Fog Heen, under the terms of
+sponge is Copyright (C) 2006 by Tollef Fog Heen, under the terms of
 the GPL version 2. Name and concept by Colin Watson.
 
 ifdata is Copyright (C) 2002 by Benjamin BAYART, under the terms of
@@ -16,6 +16,9 @@ pee is Copyright (c) Miek Gieben, 2006, under the terms of the GPL.
 zrun is Copyright (c) Chung-chieh Shan, under the terms of the GPL, version
 2 or later.
 
+mispipe is Copyright (c) Nathanael Nerode, under the terms of the GPL,
+version 2 or later. (It's also dual-licensed under the MIT/Expat licence.)
+
 Everything else is copyright 2006 by Joey Hess, under the terms of GPL.
 The full text of the GNU GPL can be found in /usr/share/common-licenses/GPL
 on Debian systems.
diff --git a/mispipe.c b/mispipe.c
new file mode 100644 (file)
index 0000000..43ba76a
--- /dev/null
+++ b/mispipe.c
@@ -0,0 +1,179 @@
+/*
+ * mispipe: written by Nathanael Nerode.
+ *
+ * Copyright 2004 Nathanael Nerode.
+ *
+ * Licensed under the GPL version 2 or above, and dual-licensed under the
+ * following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+ * THE SOFTWARE.
+ */
+
+/*
+ * Usage: mispipe <command1> <command2>
+ * Run <command1> | <command2>, but return with the exit status of <command1>.
+ *
+ * This is designed for a very specific purpose: logging.
+ * "foo | logger -t foo"
+ * will return with the exit status of logger, not that of foo.
+ * "mispipe foo 'logger -t foo'"
+ * will return with the exit status of foo.
+ */
+
+/*
+ * To do:
+ * Make this into a fancy, internationalized, option-handling hellbeast.
+ * (But why bother?  It does its job quite well.)
+ */
+
+#include <errno.h> /* errno */
+#include <sys/types.h>
+#include <unistd.h> /* pipe(), fork(),... */
+#include <stdlib.h> /* system() */
+#include <sys/wait.h> /* waitpid(), etc. */
+#include <stdio.h>
+#include <stdarg.h> /* va_list, for error() */
+
+static const char* progname; /* Stores argv[0] */
+static int filedes[2]; /* Stores pipe file descriptors */
+
+/* Subroutine for 'warning' and 'error' which prefixes progname */
+static void warning_prefix(void) {
+       fputs(progname, stderr);
+       fputs(": ", stderr);
+}
+
+/* Issue a warning, then die */
+__attribute__(( noreturn, format (printf, 1, 2) ))
+static void error(const char* formatstr, ...) {
+       va_list ap;
+       va_start(ap, formatstr);
+       warning_prefix();
+       vfprintf(stderr, formatstr, ap);
+       va_end(ap);
+       exit(1);
+}
+
+/* Issue a warning, then die, with errno */
+__attribute__(( noreturn ))
+static void error_with_errno(const char* message) {
+       int saved_errno;
+       saved_errno=errno;
+       warning_prefix();
+       fputs(message, stderr);
+       fputs(": error number ", stderr);
+       fprintf(stderr, "%i\n", saved_errno);
+       exit(1);
+}
+
+/* Convert 'wait'/'system'-style exit status to 'exit'-style exit status */
+__attribute__(( const ))
+static int shorten_status(int status_big) {
+       if (WIFEXITED(status_big))
+               return WEXITSTATUS(status_big);
+       if (WIFSIGNALED(status_big))
+               return 128+WTERMSIG(status_big);
+       if (WIFSTOPPED(status_big))
+               return 128+WSTOPSIG(status_big);
+#ifdef WCOREDUMP
+       if (WCOREDUMP(status_big))
+                error("Ow, somebody dumped core!");
+#endif
+       error("shorten_status got an invalid status (?!)");
+}
+
+/* All the work for command 2. */
+__attribute__(( noreturn ))
+static void subprocess2(const char* cmd) {
+       /* Close the old standard input. */
+       if (close(0))
+               error_with_errno("Failed (in child) closing standard input");
+       /* Make the reading end of the pipe the new standard input. */
+       if (dup2(filedes[0], 0) == -1)
+               error_with_errno("Failed (in child) redefining standard input");
+       /* Close the other end of the pipe. */
+       if (close(filedes[1]))
+               error_with_errno("Failed (in child) closing filedes[1]");
+       /* Do the second command, and throw away the exit status. */
+       system(cmd);
+       /* Close all the file descriptors. */
+       if (close(filedes[0]))
+               error_with_errno("Failed (in child) closing filedes[0]"
+                       " (while cleaning up)");
+       if (close(0))
+               error_with_errno("Failed (in child) closing standard output "
+                       " (while cleaning up)");
+       exit(0);
+}
+
+int main (int argc, const char ** argv) {
+       int status_big; /* Exit status, 'wait' and 'system' style */
+       pid_t child2_pid;
+       pid_t dead_pid;
+
+       /* Set progname */
+       progname = argv[0];
+
+       /* Verify arguments */
+       if (argc != 3) 
+               error("Wrong number of args, aborting\n");
+       /* Open a new pipe */
+       if (pipe(filedes))
+               error_with_errno("pipe() failed");
+
+       /* Fork to run second command */
+       child2_pid = fork();
+       if (child2_pid == 0)
+               subprocess2(argv[2]);
+       if (child2_pid == -1)
+               error_with_errno("fork() failed");
+
+       /* Run first command inline (seriously!) */
+       /* Close standard output. */
+       if (close(1))
+               error_with_errno("Failed closing standard output");
+       /* Make the writing end of the pipe the new standard output. */
+       if (dup2(filedes[1], 1) == -1)
+               error_with_errno("Failed redefining standard output");
+       /* Close the other end of the pipe. */
+       if (close(filedes[0]))
+               error_with_errno("Failed closing filedes[0]");
+       /* Do the first command, and (crucially) get the status. */
+       status_big = system(argv[1]);
+
+       /* Close the pipe "standard output". */
+       if (close(filedes[1]))
+               error_with_errno("Failed closing filedes[1] (while cleaning up)");
+       /* Close standard output. */
+       if (close(1))
+               error_with_errno("Failed closing standard output (while cleaning up)");
+
+       /* Wait for the other process to exit. */
+       /* We don't care about the status. */
+       dead_pid = waitpid(child2_pid, NULL, WUNTRACED);
+       if (dead_pid == -1) {
+               error_with_errno("waitpid() failed");
+       }
+       else if (dead_pid != child2_pid) {
+               error("waitpid(): Who died? %i\n", dead_pid);
+       }
+
+       /* Return the desired exit status. */
+       return shorten_status(status_big);
+}
diff --git a/mispipe.docbook b/mispipe.docbook
new file mode 100644 (file)
index 0000000..ce25e86
--- /dev/null
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+Copyright 2006 Joey Hess <joey@kitenet.net>
+
+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.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+-->
+
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
+"file:///usr/share/xml/docbook/schema/dtd/4.4/docbookx.dtd"
+[]>
+
+<refentry>
+       <refentryinfo>
+               <address>
+                       <email>neroden@fastmail.fm</email>
+               </address>
+               <author>
+                       <firstname>Nathanael</firstname>
+                       <surname>Nerode</surname>
+               </author>
+               <date>2006-09-07</date>
+       </refentryinfo>
+
+       <refmeta>
+               <refentrytitle>mispipe</refentrytitle>
+               <manvolnum>1</manvolnum>
+       </refmeta>
+
+       <refnamediv>
+               <refname>mispipe</refname> 
+               <refpurpose>pipe two commands, returning the exit status of
+               the first</refpurpose>
+       </refnamediv>
+
+       <refsynopsisdiv>
+               <cmdsynopsis>
+                       <command>mispope</command>
+                       <arg><replaceable>"command1"</replaceable></arg>
+                       <arg><replaceable>"command2"</replaceable></arg>
+               </cmdsynopsis>
+       </refsynopsisdiv>
+       
+       <refsect1>
+               <title>DESCRIPTION</title>
+               
+               <para><command>mispipe</command> pipes two commands
+               together like the shell does, but unlike piping in the
+               shell, the exit status of the first command is returned.
+               </para>
+
+               <para>
+               Note that some shells, notably <command>bash</command>,
+               do offer a pipefail option, however, that option does not
+               behave the same since it makes a failure of any command in
+               the pipeline be returned, not just the exit status of the
+               first.
+               </para>
+
+       </refsect1>
+       
+       <refsect1>
+               <title>EXIT STATUS</title>
+               
+               <para>The exit status of the first command. If the process
+               terminated abnormally (due to a signal), 128 will be added
+               to its exit status.</para>
+               
+       </refsect1>
+</refentry>