diff options
author | joeyh <joeyh> | 2006-09-08 00:33:43 +0000 |
---|---|---|
committer | joeyh <joeyh> | 2006-09-08 00:33:43 +0000 |
commit | 7b6c6008e0e3f2a88c974cf8bea0545037626d2c (patch) | |
tree | f51ed58d764704a56c9da05c73508d0e90378c05 | |
parent | 79881487962d274e73b475458b6a1847789ca562 (diff) | |
download | moreutils-7b6c6008e0e3f2a88c974cf8bea0545037626d2c.tar.gz |
* Add mispipe, contributed by Nathanael Nerode. Pipes together two commands,
returning the exit status of the first.
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | debian/changelog | 4 | ||||
-rw-r--r-- | debian/control | 1 | ||||
-rw-r--r-- | debian/copyright | 5 | ||||
-rw-r--r-- | mispipe.c | 179 | ||||
-rw-r--r-- | mispipe.docbook | 84 |
7 files changed, 278 insertions, 4 deletions
@@ -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" $< > $@; @@ -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 diff --git a/debian/changelog b/debian/changelog index 99643c8..3ae051e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 diff --git a/debian/control b/debian/control index ced07eb..3dd98df 100644 --- a/debian/control +++ b/debian/control @@ -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 diff --git a/debian/copyright b/debian/copyright index b53bfaf..22e443e 100644 --- a/debian/copyright +++ b/debian/copyright @@ -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 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 index 0000000..ce25e86 --- /dev/null +++ b/mispipe.docbook @@ -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> |