2008-12-17 11:30:03 +00:00
|
|
|
/* stdbuf -- setup the standard streams for a command
|
2023-01-01 14:50:15 +00:00
|
|
|
Copyright (C) 2009-2023 Free Software Foundation, Inc.
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
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 3 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
|
2017-09-19 01:13:23 -07:00
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
/* Written by Pádraig Brady. */
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <getopt.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#include "system.h"
|
2016-10-15 23:10:35 +01:00
|
|
|
#include "die.h"
|
2008-12-17 11:30:03 +00:00
|
|
|
#include "error.h"
|
2009-09-24 17:18:47 -06:00
|
|
|
#include "filenamecat.h"
|
2008-12-17 11:30:03 +00:00
|
|
|
#include "quote.h"
|
2009-09-24 17:18:47 -06:00
|
|
|
#include "xreadlink.h"
|
2008-12-17 11:30:03 +00:00
|
|
|
#include "xstrtol.h"
|
|
|
|
|
#include "c-ctype.h"
|
|
|
|
|
|
2012-01-08 15:08:30 +01:00
|
|
|
/* The official name of this program (e.g., no 'g' prefix). */
|
2008-12-17 11:30:03 +00:00
|
|
|
#define PROGRAM_NAME "stdbuf"
|
|
|
|
|
#define LIB_NAME "libstdbuf.so" /* FIXME: don't hardcode */
|
|
|
|
|
|
2016-11-13 14:08:48 +00:00
|
|
|
#define AUTHORS proper_name ("Padraig Brady")
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
static char *program_path;
|
|
|
|
|
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
size_t size;
|
|
|
|
|
int optc;
|
|
|
|
|
char *optarg;
|
|
|
|
|
} stdbuf[3];
|
|
|
|
|
|
|
|
|
|
static struct option const longopts[] =
|
|
|
|
|
{
|
|
|
|
|
{"input", required_argument, NULL, 'i'},
|
|
|
|
|
{"output", required_argument, NULL, 'o'},
|
|
|
|
|
{"error", required_argument, NULL, 'e'},
|
|
|
|
|
{GETOPT_HELP_OPTION_DECL},
|
|
|
|
|
{GETOPT_VERSION_OPTION_DECL},
|
|
|
|
|
{NULL, 0, NULL, 0}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Set size to the value of STR, interpreted as a decimal integer,
|
|
|
|
|
optionally multiplied by various values.
|
|
|
|
|
Return -1 on error, 0 on success.
|
|
|
|
|
|
|
|
|
|
This supports dd BLOCK size suffixes.
|
|
|
|
|
Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats. */
|
|
|
|
|
static int
|
|
|
|
|
parse_size (char const *str, size_t *size)
|
|
|
|
|
{
|
|
|
|
|
uintmax_t tmp_size;
|
2023-01-06 13:13:54 +00:00
|
|
|
enum strtol_error e = xstrtoumax (str, NULL, 10, &tmp_size, "EGkKMPQRTYZ0");
|
2014-12-16 12:36:39 +00:00
|
|
|
if (e == LONGINT_OK && SIZE_MAX < tmp_size)
|
2008-12-17 11:30:03 +00:00
|
|
|
e = LONGINT_OVERFLOW;
|
|
|
|
|
|
|
|
|
|
if (e == LONGINT_OK)
|
|
|
|
|
{
|
|
|
|
|
errno = 0;
|
|
|
|
|
*size = tmp_size;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-16 12:36:39 +00:00
|
|
|
errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : errno);
|
2008-12-17 11:30:03 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
usage (int status)
|
|
|
|
|
{
|
|
|
|
|
if (status != EXIT_SUCCESS)
|
2012-01-07 16:54:26 +01:00
|
|
|
emit_try_help ();
|
2008-12-17 11:30:03 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf (_("Usage: %s OPTION... COMMAND\n"), program_name);
|
|
|
|
|
fputs (_("\
|
|
|
|
|
Run COMMAND, with modified buffering operations for its standard streams.\n\
|
|
|
|
|
"), stdout);
|
maint: define usage note about mandatory args centrally
Each program with at least one long option which is marked as
'required_argument' and which has also a short option for that
option, should print a note about mandatory arguments.
Define that well-known note centrally and use it rather than
literal printf/fputs, and add it where it was missing.
* src/system.h (emit_mandatory_arg_note): Add new function.
* src/cp.c (usage): Use it rather than literal printf/fputs.
* src/csplit.c, src/cut.c, src/date.c, src/df.c, src/du.c:
* src/expand.c, src/fmt.c, src/fold.c, src/head.c, src/install.c:
* src/kill.c, src/ln.c, src/ls.c, src/mkdir.c, src/mkfifo.c:
* src/mknod.c, src/mv.c, src/nl.c, src/od.c, src/paste.c:
* src/pr.c, src/ptx.c, src/shred.c, src/shuf.c, src/sort.c:
* src/split.c, src/stdbuf.c, src/tac.c, src/tail.c, src/timeout.c:
* src/touch.c, src/truncate.c, src/unexpand.c, src/uniq.c:
Likewise.
* src/base64.c (usage): Add call of the above new function
because at least one long option has a required argument.
* src/basename.c, src/chcon.c, src/date.c, src/env.c:
* src/nice.c, src/runcon.c, src/seq.c, src/stat.c, src/stty.c:
Likewise.
2013-01-23 01:03:38 +01:00
|
|
|
|
|
|
|
|
emit_mandatory_arg_note ();
|
|
|
|
|
|
2008-12-17 11:30:03 +00:00
|
|
|
fputs (_("\
|
2010-02-12 15:19:15 +00:00
|
|
|
-i, --input=MODE adjust standard input stream buffering\n\
|
|
|
|
|
-o, --output=MODE adjust standard output stream buffering\n\
|
|
|
|
|
-e, --error=MODE adjust standard error stream buffering\n\
|
2008-12-17 11:30:03 +00:00
|
|
|
"), stdout);
|
|
|
|
|
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
|
|
|
|
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
|
|
|
|
fputs (_("\n\
|
2012-01-08 14:08:03 +01:00
|
|
|
If MODE is 'L' the corresponding stream will be line buffered.\n\
|
2008-12-17 11:30:03 +00:00
|
|
|
This option is invalid with standard input.\n"), stdout);
|
|
|
|
|
fputs (_("\n\
|
2012-01-08 14:08:03 +01:00
|
|
|
If MODE is '0' the corresponding stream will be unbuffered.\n\
|
2008-12-17 11:30:03 +00:00
|
|
|
"), stdout);
|
|
|
|
|
fputs (_("\n\
|
|
|
|
|
Otherwise MODE is a number which may be followed by one of the following:\n\
|
numfmt: add support for new SI prefixes
* src/dd, src/head.c, src/od.c, src/sort.c, src/stdbuf.c, src/tail.c:
(usage):
* src/system.h (emit_size_note):
Mention new SI prefixes.
* src/du.c (main):
* src/head.c (head_file):
* src/numfmt.c (suffix_power, suffix_power_char, prepare_padded_number):
* src/shred.c (main):
* src/sort.c (unit_order):
* src/tail.c (parse_options):
Support new SI prefixes.
* src/numfmt.c (MAX_ACCEPTABLE_DIGITS): Increase to 33.
(zero_and_valid_suffixes, valid_suffixes): New constants,
with new SI prefixes.
(valid_suffix, unit_to_umax): Use them.
(prepare_padded_number): Diagnose "999Q" instead of "999Y".
* tests/misc/numfmt.pl, tests/misc/sort.pl:
Adjust tests to match new max.
2023-01-05 11:42:51 -08:00
|
|
|
KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G,T,P,E,Z,Y,R,Q.\n\
|
2018-07-22 08:16:23 -07:00
|
|
|
Binary prefixes can be used, too: KiB=K, MiB=M, and so on.\n\
|
2008-12-17 11:30:03 +00:00
|
|
|
In this case the corresponding stream will be fully buffered with the buffer\n\
|
|
|
|
|
size set to MODE bytes.\n\
|
|
|
|
|
"), stdout);
|
|
|
|
|
fputs (_("\n\
|
2012-01-08 14:08:03 +01:00
|
|
|
NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does\n\
|
2014-09-23 03:50:14 +02:00
|
|
|
for example) then that will override corresponding changes by 'stdbuf'.\n\
|
2012-01-08 14:08:03 +01:00
|
|
|
Also some filters (like 'dd' and 'cat' etc.) don't use streams for I/O,\n\
|
|
|
|
|
and are thus unaffected by 'stdbuf' settings.\n\
|
2008-12-17 11:30:03 +00:00
|
|
|
"), stdout);
|
2022-09-27 21:59:01 +01:00
|
|
|
emit_exec_status (PROGRAM_NAME);
|
2014-09-18 14:50:47 +01:00
|
|
|
emit_ancillary_info (PROGRAM_NAME);
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
exit (status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* argv[0] can be anything really, but generally it contains
|
|
|
|
|
the path to the executable or just a name if it was executed
|
|
|
|
|
using $PATH. In the latter case to get the path we can:
|
2021-07-26 15:42:29 +01:00
|
|
|
search getenv("PATH"), readlink("/prof/self/exe"), getenv("_"),
|
2008-12-17 11:30:03 +00:00
|
|
|
dladdr(), pstat_getpathname(), etc. */
|
|
|
|
|
|
|
|
|
|
static void
|
2021-04-11 18:23:21 +01:00
|
|
|
set_program_path (char const *arg)
|
2008-12-17 11:30:03 +00:00
|
|
|
{
|
|
|
|
|
if (strchr (arg, '/')) /* Use absolute or relative paths directly. */
|
|
|
|
|
{
|
|
|
|
|
program_path = dir_name (arg);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-09-24 17:18:47 -06:00
|
|
|
char *path = xreadlink ("/proc/self/exe");
|
|
|
|
|
if (path)
|
|
|
|
|
program_path = dir_name (path);
|
2008-12-17 11:30:03 +00:00
|
|
|
else if ((path = getenv ("PATH")))
|
|
|
|
|
{
|
|
|
|
|
char *dir;
|
2009-08-31 09:44:30 +02:00
|
|
|
path = xstrdup (path);
|
2008-12-17 11:30:03 +00:00
|
|
|
for (dir = strtok (path, ":"); dir != NULL; dir = strtok (NULL, ":"))
|
|
|
|
|
{
|
2009-09-24 17:18:47 -06:00
|
|
|
char *candidate = file_name_concat (dir, arg, NULL);
|
|
|
|
|
if (access (candidate, X_OK) == 0)
|
2008-12-17 11:30:03 +00:00
|
|
|
{
|
2009-09-24 17:18:47 -06:00
|
|
|
program_path = dir_name (candidate);
|
|
|
|
|
free (candidate);
|
2008-12-17 11:30:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2009-09-24 17:18:47 -06:00
|
|
|
free (candidate);
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-09-24 17:18:47 -06:00
|
|
|
free (path);
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
optc_to_fileno (int c)
|
|
|
|
|
{
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case 'e':
|
|
|
|
|
ret = STDERR_FILENO;
|
|
|
|
|
break;
|
|
|
|
|
case 'i':
|
|
|
|
|
ret = STDIN_FILENO;
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
ret = STDOUT_FILENO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_LD_PRELOAD (void)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
2014-05-26 09:19:16 +01:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
char const *preload_env = "DYLD_INSERT_LIBRARIES";
|
|
|
|
|
#else
|
|
|
|
|
char const *preload_env = "LD_PRELOAD";
|
|
|
|
|
#endif
|
|
|
|
|
char *old_libs = getenv (preload_env);
|
2008-12-17 11:30:03 +00:00
|
|
|
char *LD_PRELOAD;
|
|
|
|
|
|
|
|
|
|
/* Note this would auto add the appropriate search path for "libstdbuf.so":
|
2011-06-19 11:41:24 +02:00
|
|
|
gcc stdbuf.c -Wl,-rpath,'$ORIGIN' -Wl,-rpath,$PKGLIBEXECDIR
|
2008-12-17 11:30:03 +00:00
|
|
|
However we want the lookup done for the exec'd command not stdbuf.
|
|
|
|
|
|
2011-06-19 11:41:24 +02:00
|
|
|
Since we don't link against libstdbuf.so add it to PKGLIBEXECDIR
|
2014-05-10 04:53:29 +01:00
|
|
|
rather than to LIBDIR.
|
|
|
|
|
|
|
|
|
|
Note we could add "" as the penultimate item in the following list
|
|
|
|
|
to enable searching for libstdbuf.so in the default system lib paths.
|
|
|
|
|
However that would not indicate an error if libstdbuf.so was not found.
|
|
|
|
|
Also while this could support auto selecting the right arch in a multilib
|
|
|
|
|
environment, what we really want is to auto select based on the arch of the
|
|
|
|
|
command being run, rather than that of stdbuf itself. This is currently
|
|
|
|
|
not supported due to the unusual need for controlling the stdio buffering
|
|
|
|
|
of programs that are a different architecture to the default on the
|
|
|
|
|
system (and that of stdbuf itself). */
|
2008-12-17 11:30:03 +00:00
|
|
|
char const *const search_path[] = {
|
|
|
|
|
program_path,
|
2011-06-19 11:41:24 +02:00
|
|
|
PKGLIBEXECDIR,
|
2008-12-17 11:30:03 +00:00
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
char const *const *path = search_path;
|
|
|
|
|
char *libstdbuf;
|
|
|
|
|
|
2011-02-18 23:29:14 +01:00
|
|
|
while (true)
|
2008-12-17 11:30:03 +00:00
|
|
|
{
|
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
|
|
if (!**path) /* system default */
|
|
|
|
|
{
|
|
|
|
|
libstdbuf = xstrdup (LIB_NAME);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ret = asprintf (&libstdbuf, "%s/%s", *path, LIB_NAME);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
xalloc_die ();
|
|
|
|
|
if (stat (libstdbuf, &sb) == 0) /* file_exists */
|
|
|
|
|
break;
|
|
|
|
|
free (libstdbuf);
|
2011-02-18 23:29:14 +01:00
|
|
|
|
|
|
|
|
++path;
|
|
|
|
|
if ( ! *path)
|
2016-10-15 23:10:35 +01:00
|
|
|
die (EXIT_CANCELED, 0, _("failed to find %s"), quote (LIB_NAME));
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: Do we need to support libstdbuf.dll, c:, '\' separators etc? */
|
|
|
|
|
|
|
|
|
|
if (old_libs)
|
2014-05-26 09:19:16 +01:00
|
|
|
ret = asprintf (&LD_PRELOAD, "%s=%s:%s", preload_env, old_libs, libstdbuf);
|
2008-12-17 11:30:03 +00:00
|
|
|
else
|
2014-05-26 09:19:16 +01:00
|
|
|
ret = asprintf (&LD_PRELOAD, "%s=%s", preload_env, libstdbuf);
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
xalloc_die ();
|
|
|
|
|
|
|
|
|
|
free (libstdbuf);
|
|
|
|
|
|
|
|
|
|
ret = putenv (LD_PRELOAD);
|
2014-05-26 09:19:16 +01:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
if (ret == 0)
|
2015-06-28 10:35:04 -07:00
|
|
|
ret = setenv ("DYLD_FORCE_FLAT_NAMESPACE", "y", 1);
|
2014-05-26 09:19:16 +01:00
|
|
|
#endif
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
{
|
2016-10-15 23:10:35 +01:00
|
|
|
die (EXIT_CANCELED, errno,
|
|
|
|
|
_("failed to update the environment with %s"),
|
|
|
|
|
quote (LD_PRELOAD));
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-22 03:37:51 +01:00
|
|
|
/* Populate environ with _STDBUF_I=$MODE _STDBUF_O=$MODE _STDBUF_E=$MODE.
|
|
|
|
|
Return TRUE if any environment variables set. */
|
2008-12-17 11:30:03 +00:00
|
|
|
|
2013-06-22 03:37:51 +01:00
|
|
|
static bool
|
2008-12-17 11:30:03 +00:00
|
|
|
set_libstdbuf_options (void)
|
|
|
|
|
{
|
2013-06-22 03:37:51 +01:00
|
|
|
bool env_set = false;
|
2008-12-17 11:30:03 +00:00
|
|
|
|
2017-06-17 14:54:23 -07:00
|
|
|
for (size_t i = 0; i < ARRAY_CARDINALITY (stdbuf); i++)
|
2008-12-17 11:30:03 +00:00
|
|
|
{
|
|
|
|
|
if (stdbuf[i].optarg)
|
|
|
|
|
{
|
|
|
|
|
char *var;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (*stdbuf[i].optarg == 'L')
|
|
|
|
|
ret = asprintf (&var, "%s%c=L", "_STDBUF_",
|
|
|
|
|
toupper (stdbuf[i].optc));
|
|
|
|
|
else
|
|
|
|
|
ret = asprintf (&var, "%s%c=%" PRIuMAX, "_STDBUF_",
|
|
|
|
|
toupper (stdbuf[i].optc),
|
|
|
|
|
(uintmax_t) stdbuf[i].size);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
xalloc_die ();
|
|
|
|
|
|
|
|
|
|
if (putenv (var) != 0)
|
|
|
|
|
{
|
2016-10-15 23:10:35 +01:00
|
|
|
die (EXIT_CANCELED, errno,
|
|
|
|
|
_("failed to update the environment with %s"),
|
|
|
|
|
quote (var));
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
2013-06-22 03:37:51 +01:00
|
|
|
|
|
|
|
|
env_set = true;
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-06-22 03:37:51 +01:00
|
|
|
|
|
|
|
|
return env_set;
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
initialize_main (&argc, &argv);
|
|
|
|
|
set_program_name (argv[0]);
|
|
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
|
bindtextdomain (PACKAGE, LOCALEDIR);
|
|
|
|
|
textdomain (PACKAGE);
|
|
|
|
|
|
|
|
|
|
initialize_exit_failure (EXIT_CANCELED);
|
|
|
|
|
atexit (close_stdout);
|
|
|
|
|
|
|
|
|
|
while ((c = getopt_long (argc, argv, "+i:o:e:", longopts, NULL)) != -1)
|
|
|
|
|
{
|
|
|
|
|
int opt_fileno;
|
|
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
/* Old McDonald had a farm ei... */
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'o':
|
|
|
|
|
opt_fileno = optc_to_fileno (c);
|
2009-06-27 01:48:49 +01:00
|
|
|
assert (0 <= opt_fileno && opt_fileno < ARRAY_CARDINALITY (stdbuf));
|
2008-12-17 11:30:03 +00:00
|
|
|
stdbuf[opt_fileno].optc = c;
|
|
|
|
|
while (c_isspace (*optarg))
|
|
|
|
|
optarg++;
|
|
|
|
|
stdbuf[opt_fileno].optarg = optarg;
|
|
|
|
|
if (c == 'i' && *optarg == 'L')
|
|
|
|
|
{
|
|
|
|
|
/* -oL will be by far the most common use of this utility,
|
|
|
|
|
but one could easily think -iL might have the same affect,
|
|
|
|
|
so disallow it as it could be confusing. */
|
|
|
|
|
error (0, 0, _("line buffering stdin is meaningless"));
|
|
|
|
|
usage (EXIT_CANCELED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!STREQ (optarg, "L")
|
|
|
|
|
&& parse_size (optarg, &stdbuf[opt_fileno].size) == -1)
|
2016-10-15 23:10:35 +01:00
|
|
|
die (EXIT_CANCELED, errno, _("invalid mode %s"), quote (optarg));
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case_GETOPT_HELP_CHAR;
|
|
|
|
|
|
|
|
|
|
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
usage (EXIT_CANCELED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv += optind;
|
|
|
|
|
argc -= optind;
|
|
|
|
|
|
|
|
|
|
/* must specify at least 1 command. */
|
|
|
|
|
if (argc < 1)
|
|
|
|
|
{
|
|
|
|
|
error (0, 0, _("missing operand"));
|
|
|
|
|
usage (EXIT_CANCELED);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-22 03:37:51 +01:00
|
|
|
if (! set_libstdbuf_options ())
|
|
|
|
|
{
|
|
|
|
|
error (0, 0, _("you must specify a buffering mode option"));
|
|
|
|
|
usage (EXIT_CANCELED);
|
|
|
|
|
}
|
2008-12-17 11:30:03 +00:00
|
|
|
|
|
|
|
|
/* Try to preload libstdbuf first from the same path as
|
|
|
|
|
stdbuf is running from. */
|
2011-09-01 15:23:17 +01:00
|
|
|
set_program_path (program_name);
|
2008-12-17 11:30:03 +00:00
|
|
|
if (!program_path)
|
2015-10-15 15:15:56 +01:00
|
|
|
program_path = xstrdup (PKGLIBDIR); /* Need to init to non-NULL. */
|
2008-12-17 11:30:03 +00:00
|
|
|
set_LD_PRELOAD ();
|
|
|
|
|
free (program_path);
|
|
|
|
|
|
|
|
|
|
execvp (*argv, argv);
|
|
|
|
|
|
maint: prefer 'return status;' to 'exit (status);' in 'main'
* build-aux/gen-single-binary.sh: Don't use ATTRIBUTE_NORETURN
for main functions.
* src/base64.c, src/basename.c, src/cat.c, src/chcon.c, src/chgrp.c:
* src/chmod.c, src/chown.c, src/chroot.c, src/cksum.c, src/comm.c:
* src/cp.c, src/csplit.c, src/cut.c, src/date.c, src/dd.c, src/df.c:
* src/dircolors.c, src/dirname.c, src/du.c, src/echo.c, src/env.c:
* src/expand.c, src/expr.c, src/factor.c, src/fmt.c, src/fold.c:
* src/getlimits.c, src/groups.c, src/head.c, src/hostid.c:
* src/hostname.c, src/id.c, src/install.c, src/join.c, src/kill.c:
* src/link.c, src/ln.c, src/logname.c, src/ls.c, src/make-prime-list.c:
* src/md5sum.c, src/mkdir.c, src/mkfifo.c, src/mknod.c, src/mktemp.c:
* src/mv.c, src/nice.c, src/nl.c, src/nohup.c, src/nproc.c:
* src/numfmt.c, src/od.c, src/paste.c, src/pathchk.c, src/pinky.c:
* src/pr.c, src/printenv.c, src/printf.c, src/ptx.c, src/pwd.c:
* src/readlink.c, src/realpath.c, src/rm.c, src/rmdir.c, src/runcon.c:
* src/seq.c, src/shred.c, src/shuf.c, src/sleep.c, src/sort.c:
* src/split.c, src/stat.c, src/stdbuf.c, src/stty.c, src/sum.c:
* src/sync.c, src/tac.c, src/tail.c, src/tee.c, src/timeout.c:
* src/touch.c, src/tr.c, src/true.c, src/truncate.c, src/tsort.c:
* src/tty.c, src/uname.c, src/unexpand.c, src/uniq.c, src/unlink.c:
* src/uptime.c, src/users.c, src/wc.c, src/who.c, src/whoami.c:
In 'main' functions, Prefer 'return status;' to 'exit (status);'.
* src/coreutils-arch.c (_single_binary_main_uname)
(_single_binary_main_arch):
* src/coreutils-dir.c, src/coreutils-vdir.c (_single_binary_main_ls)
(_single_binary_main_dir, _single_binary_main_vdir):
Omit ATTRIBUTE_NORETURN. Return a value.
* src/coreutils.c (SINGLE_BINARY_PROGRAM): Omit ATTRIBUTE_NORETURN.
(launch_program): Now static.
* src/dd.c (finish_up): New function.
(quit, main): Use it.
* src/getlimits.c (main): Return a proper exit status.
* src/test.c (test_main_return): New macro.
(main): Use it.
* src/logname.c, src/nohup.c, src/whoami.c:
Use 'error' to simplify exit status in 'main' function.
* src/yes.c (main): Use 'return' rather than 'error' to exit,
so that GCC doesn't suggest ATTRIBUTE_NORETURN.
2014-09-08 16:31:14 -07:00
|
|
|
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
|
|
|
|
|
error (0, errno, _("failed to run command %s"), quote (argv[0]));
|
|
|
|
|
return exit_status;
|
2008-12-17 11:30:03 +00:00
|
|
|
}
|