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 (c5245316bf1ff46260e10caf09703f3dc7bc7db7) (5790 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 original file descriptor for it */
	if (close(filedes[0]))
		error_with_errno("Failed (in child) closing filedes[0]");
	/* 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. */
	if (system(cmd)) {}
	/* Close the standard input. */
	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 original file descriptor for it. */
	if (close(filedes[1]))
		error_with_errno("Failed closing filedes[1]");
	/* 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 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 44 5d425843f23db3bb6970a55c953f345e3a8c8fe1 .gitattributes
100644 blob 312 61108da49ae51ca3264e1760adad5687f92a5885 .gitignore
100644 blob 17989 b7b5f53df1412df1e117607f18385b39004cdaa2 COPYING
100644 blob 1358 1e92f61cafa421314e36fd80143cbcaed203182f Makefile
100644 blob 1181 1bb90af3a954062b79c41840a150e8580dfec37a README
100755 blob 2180 e24e582e864d1abcaddd07d9365d632ecc2abc13 chronic
100755 blob 3047 7f311d7aa58631795fcad87aa8fcc0f416a01796 combine
040000 tree - fe566c35db631ab98e799424e0922bf05576c22f debian
100644 blob 5102 d2f68a1ac365a0c8df88d4b64a400f63fffe4c69 errno.c
100644 blob 3877 8d9b4acf28e4e85244dc43dce7fbf35bb2171f80 errno.docbook
100644 blob 13670 99f30e9cebf9b90b8a283b02e2db5c47d11f2ca5 ifdata.c
100644 blob 7339 47f414301c47a69a81694c3b5affd71261207d49 ifdata.docbook
100644 blob 3027 ff648cc55865f5bf9af76b9622b52b08a1b489fb ifne.c
100644 blob 2465 e9c45692b7b95e77ea0184732f883d278c9415f6 ifne.docbook
040000 tree - 943446075009f6dbdb1ebc6ab3957c0b8be01b56 is_utf8
100644 blob 3996 f4631b2023616931670a8050227058291dda19a9 isutf8.docbook
100644 blob 5451 7bfb5e2c0376b6edaa607da00e45445b9d4ef197 lckdo.c
100644 blob 3637 3fbf797b177d6933ce106cce2e8368e5094702ab lckdo.docbook
100644 blob 5790 c5245316bf1ff46260e10caf09703f3dc7bc7db7 mispipe.c
100644 blob 2566 d65d1a45b1b47ba8d6fc7c87211cf4b26eb0feed mispipe.docbook
100644 blob 8666 8a379984714f9b8aec559ca5706e46329dd273fa parallel.c
100644 blob 3992 87e58787b21e94d007f4f62b038296599e995f2f parallel.docbook
100644 blob 2380 92df61c986e0399c3790a667a27ae2f01ff10324 pee.c
100644 blob 3680 403062997db883601e266d4c5d512d7a3b9015ca pee.docbook
100644 blob 7301 a53a2cf1906998c91533f5f5435ceeeeb1a7cd59 physmem.c
100644 blob 9200 09d3971fdb020de4da825625bd6dbbec8521d803 sponge.c
100644 blob 2865 31bc6dbc244e5e5313a2b34871877878fce24827 sponge.docbook
100755 blob 4574 4dad3d4c7b46699d100f4ea8e343be7e65f31bd4 ts
100755 blob 4878 656ce4feb1d4aff82adb122c4923c1d9d8f94e5e vidir
100755 blob 1403 2bf640dbd13f46dea540cbc49b8295d07d25a883 vipe
100755 blob 2518 98d1445a5f8106f04be690f85d802a7f6decfd13 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