nicolas / debian.moreutils (public) (License: GPL-2, GPL-2+, Expat, BSD-2-Clause, Public Domain) (since 2018-09-25) (hash sha1)
Debian packaging of joeyh's moreutils

/mispipe.c (43ba76aa6f3d24cfe8bb90b3776b044f27df9d37) (5777 bytes) (mode 100644) (type blob)

/*
 * 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);
}


Mode Type Size Ref File
100644 blob 17989 b7b5f53df1412df1e117607f18385b39004cdaa2 COPYING
100644 blob 968 16d88b4e9bddf62974c43189d12f3ade5b18b35d Makefile
100644 blob 1048 ccc257cd3e6190cafffba1b73125677a16beea33 README
100755 blob 806 83a4eed00f82e3bcc81856149b47cffc4091f9aa check-isutf8
100755 blob 2607 a695935b24a5f2789c71a8affc4486859a41f737 combine
040000 tree - 9e78b23327f4b76a02848cf2087603303e1e5c1e debian
100644 blob 12768 ba68edced696c617214a22b0a677e165d9c1dd8d ifdata.c
100644 blob 7039 5f2837f71cb7ea8e1aa8481d854d975174e19ab9 ifdata.docbook
100644 blob 3006 d8ecea9b8bc416154533572e1ce85a0385b7af10 ifne.c
100644 blob 2360 41fa9abe7a23b63f5afd110dcd0b3f78b0e4c531 ifne.docbook
100644 blob 7581 c5f5eeb667c425c3ef02516712c08acb72f3f557 isutf8.c
100644 blob 2894 f9c9eb59e9e15197e686a25a93d8785e4522696a isutf8.docbook
100644 blob 5471 4925409bd548b058f07defe913724868801040df lckdo.c
100644 blob 3261 8a0a4a863aba57a7a4d7b06b69414c25c21dfa17 lckdo.docbook
100644 blob 5777 43ba76aa6f3d24cfe8bb90b3776b044f27df9d37 mispipe.c
100644 blob 2292 b645b2c756f9b79cdde96a4a82c63bd9fd60fbff mispipe.docbook
100644 blob 2979 09588d6a37b68a04006fe07ce382f50262f72760 parallel.c
100644 blob 1040 6ba38f78da10b61c8670b1c450fa769248ef84c4 pee.c
100644 blob 2082 18c753f289f920c9fddc06b191a2c7a031bbe391 pee.docbook
100644 blob 7301 a53a2cf1906998c91533f5f5435ceeeeb1a7cd59 physmem.c
100644 blob 8551 80733a22387f8290b77434f04a6a5dae099cc6b9 sponge.c
100644 blob 1757 f9395a72eb845f0c8007dd2777501a305243f579 sponge.docbook
100755 blob 2515 ca150b4a36105ee55ca72920d6adce1aafd9a05a ts
100755 blob 4495 a77739f27d8cab6843471de92857fe5064f9ace4 vidir
100755 blob 1264 4874fe3a2c897482ca6e778e18b56a888fb8fdb9 vipe
100755 blob 2473 50026eb2735406f35fefda0ba6b12a0ca05c559c zrun
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/nicolas/debian.moreutils

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/nicolas/debian.moreutils

Clone this repository using git:
git clone git://git.rocketgit.com/user/nicolas/debian.moreutils

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main