Check in the source for coreutils

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6837 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Phipps
2004-03-01 02:43:35 +00:00
parent f0446088b3
commit 9e959120f4
118 changed files with 83978 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
SubDir OBOS_TOP src apps bin coreutils-5.0 src ;
SubDirCcFlags -DHAVE_CONFIG_H -DLOCALEDIR=\'\"/share/locale\"\' ;
StdBinCommands
basename.c
cat.c
chmod.c
cksum.c
comm.c
csplit.c
cut.c
date.c
dd.c
dircolors.c
dirname.c
du.c
echo.c
env.c
expand.c
expr.c
factor.c
false.c
fmt.c
fold.c
head.c
hostname.c
id.c
join.c
kill.c
link.c
ln.c
logname.c
mkdir.c
mkfifo.c
mknod.c
nl.c
od.c
paste.c
pathchk.c
pr.c
printenv.c
printf.c
ptx.c
pwd.c
readlink.c
rmdir.c
seq.c
shred.c
sleep.c
sort.c
split.c
stty.c
su.c
sum.c
sync.c
tac.c
tail.c
tee.c
test.c
touch.c
tr.c
true.c
tsort.c
tty.c
uname.c
unexpand.c
uniq.c
unlink.c
wc.c
whoami.c
yes.c
: root libfetish.a ;
# stat.c
# chroot.c
# df.c
# hostid.c
# nice.c
# pinky.c
# uptime.c
# users.c
# who.c
BinCommand ls :
ls.c ls-dir.c : root libfetish.a ;
BinCommand rm :
rm.c remove.c : root libfetish.a ;
BinCommand chgroup :
chgrp.c chown-core.c : root libfetish.a ;
BinCommand chmod :
chmod.c chown-core.c : root libfetish.a ;
BinCommand cp :
cp.c copy.c cp-hash.c : root libfetish.a ;
BinCommand md5sum :
md5sum.c md5.c : root libfetish.a ;
BinCommand mv :
mv.c copy.c cp-hash.c remove.c : root libfetish.a ;
BinCommand sha1sum :
md5sum.c sha1sum.c : root libfetish.a ;
BinCommand vdir :
ls.c ls-vdir.c : root libfetish.a ;
File diff suppressed because it is too large Load Diff
+242
View File
@@ -0,0 +1,242 @@
## Process this file with automake to produce Makefile.in -*-Makefile-*-
EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who
EXTRA_SCRIPTS = nohup
bin_SCRIPTS = groups @OPTIONAL_BIN_ZCRIPTS@
bin_PROGRAMS = chgrp chown chmod cp dd dircolors du \
ginstall link ln dir vdir ls mkdir \
mkfifo mknod mv readlink rm rmdir shred stat sync touch unlink \
cat cksum comm csplit cut expand fmt fold head join md5sum \
nl od paste pr ptx sha1sum sort split sum tac tail tr tsort unexpand uniq wc \
basename date dirname echo env expr factor false \
hostname id kill logname pathchk printenv printf pwd seq sleep tee \
test true tty whoami yes \
@OPTIONAL_BIN_PROGS@ @DF_PROG@
localedir = $(datadir)/locale
noinst_HEADERS = \
system.h sys2.h checksum.h copy.h cp-hash.h ls.h dircolors.h remove.h \
chown-core.h fs.h \
wheel.h wheel-size.h
EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \
groups.sh nohup.sh wheel-gen.pl
CLEANFILES = $(SCRIPTS) su
INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir)/lib -I../lib
DEFS = -DLOCALEDIR=\"$(localedir)\" -DSHAREDIR=\"$(datadir)\" @DEFS@
# Sometimes, the expansion of @LIBINTL@ includes -lc which may
# include modules defining variables like `optind', so libfetish.a
# must precede @LIBINTL@ in order to ensure we use GNU getopt.
# But libfetish.a must also follow @LIBINTL@, since libintl uses
# replacement functions defined in libfetish.a.
LDADD = ../lib/libfetish.a @LIBINTL@ ../lib/libfetish.a
dir_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@
ls_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@
shred_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@
vdir_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@
## If necessary, add -lm to resolve use of pow in lib/strtod.c.
sort_LDADD = $(LDADD) @POW_LIB@
# for clock_gettime
date_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@
# For sqrt
factor_LDADD = $(LDADD) @SQRT_LIBM@
# If necessary, add -lm to resolve use of pow in lib/strtod.c.
# If necessary, add -liconv to resolve use of iconv in lib/unicodeio.c.
printf_LDADD = $(LDADD) @POW_LIB@ @LIBICONV@
# If necessary, add -lm to resolve use of floor, rint, modf.
seq_LDADD = $(LDADD) @SEQ_LIBM@
# If necessary, add -lm to resolve the `pow' reference in lib/strtod.c
# or for the fesetround reference in programs using nanosec.c.
nanosec_libs = \
$(LDADD) @FESETROUND_LIBM@ @POW_LIB@ @LIB_CLOCK_GETTIME@ @LIB_NANOSLEEP@
sleep_LDADD = $(nanosec_libs)
tail_LDADD = $(nanosec_libs)
uptime_LDADD = $(LDADD) @GETLOADAVG_LIBS@
su_LDADD = $(LDADD) @LIB_CRYPT@
$(PROGRAMS): ../lib/libfetish.a
$(SCRIPTS): Makefile
SUFFIXES = .sh
.sh:
rm -f $@ $@-t
sed \
-e 's!@''bindir''@!$(bindir)!' \
-e 's/@''GNU_PACKAGE''@/@GNU_PACKAGE@/' \
-e 's/@''PACKAGE_BUGREPORT''@/@PACKAGE_BUGREPORT@/' \
-e 's/@''VERSION''@/@VERSION@/' $< > $@-t
chmod +x $@-t
mv $@-t $@
all-local: su$(EXEEXT)
installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'`
setuid_root_mode = a=rx,u+s
INSTALL_SU = \
p=su; \
echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \
$(INSTALL_PROGRAM) $$p $(installed_su); \
echo " chown root $(installed_su)"; \
chown root $(installed_su); \
echo " chmod $(setuid_root_mode) $(installed_su)"; \
chmod $(setuid_root_mode) $(installed_su)
install-root: su$(EXEEXT)
@$(INSTALL_SU)
install-exec-local: su$(EXEEXT)
@TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \
rm -f $$TMPFILE; \
echo > $$TMPFILE; \
## See if we can create a setuid root executable in $(bindir).
## If not, then don't even try to install su.
can_create_suid_root_executable=no; \
chown root $$TMPFILE > /dev/null 2>&1 \
&& chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \
&& can_create_suid_root_executable=yes; \
rm -f $$TMPFILE; \
if test $$can_create_suid_root_executable = yes; then \
$(INSTALL_SU); \
else \
echo "WARNING: insufficient access; not installing su"; \
echo "NOTE: to install su, run 'make install-root' as root"; \
fi
uninstall-local:
# Remove su only if it's one we installed.
@if grep '@GNU_PACKAGE@' $(installed_su) > /dev/null 2>&1; then \
echo " rm -f $(installed_su)"; \
rm -f $(installed_su); \
else :; fi
# Use `ginstall' in the definition of PROGRAMS and in dependencies to avoid
# confusion with the `install' target. The install rule transforms `ginstall'
# to install before applying any user-specified name transformations.
transform = s/ginstall/install/; @program_transform_name@
ginstall_SOURCES = install.c copy.c cp-hash.c
cp_SOURCES = cp.c copy.c cp-hash.c
dir_SOURCES = ls.c ls-dir.c
vdir_SOURCES = ls.c ls-vdir.c
ls_SOURCES = ls.c ls-ls.c
chown_SOURCES = chown.c chown-core.c
chgrp_SOURCES = chgrp.c chown-core.c
mv_SOURCES = mv.c copy.c cp-hash.c remove.c
rm_SOURCES = rm.c remove.c
md5sum_SOURCES = md5sum.c md5.c
sha1sum_SOURCES = md5sum.c sha1sum.c
PERL = @PERL@
editpl = sed -e 's,@''PERL''@,$(PERL),g'
MAINTAINERCLEANFILES = dircolors.h \
wheel.h wheel-size.h
dircolors.h: dcgen dircolors.hin
$(PERL) -w -- $(srcdir)/dcgen $(srcdir)/dircolors.hin > $@-t
mv $@-t $@
wheel_size = 5
wheel-size.h: Makefile.am
echo '#define WHEEL_SIZE $(wheel_size)' > $@-t
mv $@-t $@
wheel.h: wheel-gen.pl Makefile.am
$(srcdir)/wheel-gen.pl $(wheel_size) \
> $@-t
mv $@-t $@
BUILT_SOURCES = dircolors.h false.c wheel.h wheel-size.h
# false exits nonzero even with --help or --version.
# Tell automake to exempt it from that installcheck test.
AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = false
false.c: true.c
rm -f $@
sed \
-e s/true/false/g \
-e s/success/failure/g \
-e 's/(EXIT_SUCCESS)/(EXIT_FAILURE)/g' \
$(srcdir)/true.c > $@-t
chmod a-w $@-t
mv $@-t $@
all_programs = \
$(bin_PROGRAMS) \
$(bin_SCRIPTS) \
$(EXTRA_PROGRAMS) \
$(EXTRA_SCRIPTS)
pm = progs-makefile
pr = progs-readme
# Ensure that the list of programs in README matches the list
# of programs we can build.
check: check-README check-misc
.PHONY: check-README
check-README:
rm -rf $(pr) $(pm)
echo $(all_programs) \
| tr -s ' ' '\n' | sort -u > $(pm)
sed -n '/^The programs .* are:/,/^[a-zA-Z]/p' $(top_srcdir)/README \
| sed -n '/^ */s///p' | tr -s ' ' '\n' > $(pr)
diff $(pm) $(pr) && rm -rf $(pr) $(pm)
# Make sure we don't define any S_IS* macros in src/*.c files.
# Not a big deal, but they're already defined via system.h.
#
# Also make sure we don't use st_blocks. Use ST_NBLOCKS instead.
# This is a bit of a kludge, since it prevents use of the string
# even in comments, but for now it does the job with no false positives.
.PHONY: check-misc
check-misc:
cd $(srcdir); grep '^# *define *S_IS' $(SOURCES) && exit 1 || :
cd $(srcdir); grep st_blocks $(SOURCES) && exit 1 || :
cd $(srcdir); grep '^# *define .*defined' $(SOURCES) && exit 1 || :
# Extract the list of authors from each file.
sed_filter = s/^ *//;s/N_ (//;s/^"//;s/")*$$//
# Sometimes the string is on the same line as the #define...
s1 = '/^\#define AUTHORS \([^\\]\)/{;s//\1/;$(sed_filter);p;q;}'
# Sometimes the string is on the backslash-continued line after the #define.
s2 = '/^\#define AUTHORS \\\\/{;n;$(sed_filter);p;q;}'
# FIXME: handle *.sh; and use $(all_programs), not $(SOURCES)
../AUTHORS: $(SOURCES)
rm -f $@-t
( \
set -e; \
echo "Here are the names of the programs in this package,"; \
echo "each followed by the name(s) of its author(s)."; \
echo; \
for i in $(SOURCES); do \
a=`sed -n $(s1) $$i`; \
test "$$a" && : \
|| a=`sed -n $(s2) $$i`; \
if test "$$a"; then \
prog=`echo $$i|sed 's/\.c$$//'`; \
echo "$$prog: $$a"; \
fi; \
done | sort -u ) > $@-t
chmod a-w $@-t
mv $@-t $@
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
/* basename -- strip directory and suffix from filenames
Copyright (C) 1990-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Usage: basename name [suffix]
NAME is a pathname; SUFFIX is a suffix to strip from it.
basename /usr/foo/lossage/functions.l
=> functions.l
basename /usr/foo/lossage/functions.l .l
=> functions
basename functions.lisp p
=> functions.lis */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "long-options.h"
#include "dirname.h"
#include "error.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "basename"
#define AUTHORS "FIXME unknown"
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s NAME [SUFFIX]\n\
or: %s OPTION\n\
"),
program_name, program_name);
fputs (_("\
Print NAME with any leading directory components removed.\n\
If specified, also remove a trailing SUFFIX.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Remove SUFFIX from the end of NAME if it is there, unless NAME
consists entirely of SUFFIX. */
static void
remove_suffix (char *name, const char *suffix)
{
char *np;
const char *sp;
np = name + strlen (name);
sp = suffix + strlen (suffix);
while (np > name && sp > suffix)
if (*--np != *--sp)
return;
if (np > name)
*np = '\0';
}
int
main (int argc, char **argv)
{
char *name;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
/* The above handles --help and --version.
Since there is no other invocation of getopt, handle `--' here. */
if (argc > 1 && STREQ (argv[1], "--"))
{
--argc;
++argv;
}
if (argc == 1 || argc > 3)
{
error (0, 0, (argc == 1 ? _("too few arguments")
: _("too many arguments")));
usage (EXIT_FAILURE);
}
name = base_name (argv[1]);
name[base_len (name)] = '\0';
if (argc == 3)
remove_suffix (name, argv[2]);
puts (name);
exit (EXIT_SUCCESS);
}
+864
View File
@@ -0,0 +1,864 @@
/* cat -- concatenate files and print on the standard output.
Copyright (C) 88, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Differences from the Unix cat:
* Always unbuffered, -u is ignored.
* Usually much faster than other versions of cat, the difference
is especially apparent when using the -v option.
By [email protected], Torbjorn Granlund, advised by rms, Richard Stallman. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#ifndef _POSIX_SOURCE
# include <sys/ioctl.h>
#endif
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "full-write.h"
#include "safe-read.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "cat"
#define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman")
/* Undefine, to avoid warning about redefinition on some systems. */
#undef max
#define max(h,i) ((h) > (i) ? (h) : (i))
/* Name under which this program was invoked. */
char *program_name;
/* Name of input file. May be "-". */
static char *infile;
/* Descriptor on which input file is open. */
static int input_desc;
/* Buffer for line numbers.
An 11 digit counter may overflow within an hour on a P2/466,
an 18 digit counter needs about 1000y */
#define LINE_COUNTER_BUF_LEN 20
static char line_buf[LINE_COUNTER_BUF_LEN] =
{
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0',
'\t', '\0'
};
/* Position in `line_buf' where printing starts. This will not change
unless the number of lines is larger than 999999. */
static char *line_num_print = line_buf + LINE_COUNTER_BUF_LEN - 8;
/* Position of the first digit in `line_buf'. */
static char *line_num_start = line_buf + LINE_COUNTER_BUF_LEN - 3;
/* Position of the last digit in `line_buf'. */
static char *line_num_end = line_buf + LINE_COUNTER_BUF_LEN - 3;
/* Preserves the `cat' function's local `newlines' between invocations. */
static int newlines2 = 0;
/* Count of non-fatal error conditions. */
static int exit_status = 0;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION] [FILE]...\n\
"),
program_name);
fputs (_("\
Concatenate FILE(s), or standard input, to standard output.\n\
\n\
-A, --show-all equivalent to -vET\n\
-b, --number-nonblank number nonblank output lines\n\
-e equivalent to -vE\n\
-E, --show-ends display $ at end of each line\n\
-n, --number number all output lines\n\
-s, --squeeze-blank never more than one single blank line\n\
"), stdout);
fputs (_("\
-t equivalent to -vT\n\
-T, --show-tabs display TAB characters as ^I\n\
-u (ignored)\n\
-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
With no FILE, or when FILE is -, read standard input.\n\
"), stdout);
#if O_BINARY
fputs (_("\
\n\
-B, --binary use binary writes to the console device.\n\n\
"), stdout);
#endif
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Compute the next line number. */
static void
next_line_num (void)
{
char *endp = line_num_end;
do
{
if ((*endp)++ < '9')
return;
*endp-- = '0';
}
while (endp >= line_num_start);
if (line_num_start > line_buf)
*--line_num_start = '1';
else
*line_buf = '>';
if (line_num_start < line_num_print)
line_num_print--;
}
/* Plain cat. Copies the file behind `input_desc' to STDOUT_FILENO. */
static void
simple_cat (
/* Pointer to the buffer, used by reads and writes. */
char *buf,
/* Number of characters preferably read or written by each read and write
call. */
int bufsize)
{
/* Actual number of characters read, and therefore written. */
size_t n_read;
/* Loop until the end of the file. */
for (;;)
{
/* Read a block of input. */
n_read = safe_read (input_desc, buf, bufsize);
if (n_read == SAFE_READ_ERROR)
{
error (0, errno, "%s", infile);
exit_status = 1;
return;
}
/* End of this file? */
if (n_read == 0)
break;
/* Write this block out. */
{
/* The following is ok, since we know that 0 < n_read. */
size_t n = n_read;
if (full_write (STDOUT_FILENO, buf, n) != n)
error (EXIT_FAILURE, errno, _("write error"));
}
}
}
/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC.
Called if any option more than -u was specified.
A newline character is always put at the end of the buffer, to make
an explicit test for buffer end unnecessary. */
static void
cat (
/* Pointer to the beginning of the input buffer. */
char *inbuf,
/* Number of characters read in each read call. */
size_t insize,
/* Pointer to the beginning of the output buffer. */
char *outbuf,
/* Number of characters written by each write call. */
size_t outsize,
/* Variables that have values according to the specified options. */
int quote,
int output_tabs,
int numbers,
int numbers_at_empty_lines,
int mark_line_ends,
int squeeze_empty_lines)
{
/* Last character read from the input buffer. */
unsigned char ch;
/* Pointer to the next character in the input buffer. */
char *bpin;
/* Pointer to the first non-valid byte in the input buffer, i.e. the
current end of the buffer. */
char *eob;
/* Pointer to the position where the next character shall be written. */
char *bpout;
/* Number of characters read by the last read call. */
size_t n_read;
/* Determines how many consecutive newlines there have been in the
input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1,
etc. Initially 0 to indicate that we are at the beginning of a
new line. The "state" of the procedure is determined by
NEWLINES. */
int newlines = newlines2;
#ifdef FIONREAD
/* If nonzero, use the FIONREAD ioctl, as an optimization.
(On Ultrix, it is not supported on NFS filesystems.) */
int use_fionread = 1;
#endif
/* The inbuf pointers are initialized so that BPIN > EOB, and thereby input
is read immediately. */
eob = inbuf;
bpin = eob + 1;
bpout = outbuf;
for (;;)
{
do
{
/* Write if there are at least OUTSIZE bytes in OUTBUF. */
if (outbuf + outsize <= bpout)
{
char *wp = outbuf;
size_t remaining_bytes;
do
{
if (full_write (STDOUT_FILENO, wp, outsize) != outsize)
error (EXIT_FAILURE, errno, _("write error"));
wp += outsize;
remaining_bytes = bpout - wp;
}
while (outsize <= remaining_bytes);
/* Move the remaining bytes to the beginning of the
buffer. */
memmove (outbuf, wp, remaining_bytes);
bpout = outbuf + remaining_bytes;
}
/* Is INBUF empty? */
if (bpin > eob)
{
#ifdef FIONREAD
int n_to_read = 0;
/* Is there any input to read immediately?
If not, we are about to wait,
so write all buffered output before waiting. */
if (use_fionread
&& ioctl (input_desc, FIONREAD, &n_to_read) < 0)
{
/* Ultrix returns EOPNOTSUPP on NFS;
HP-UX returns ENOTTY on pipes.
SunOS returns EINVAL and
More/BSD returns ENODEV on special files
like /dev/null.
Irix-5 returns ENOSYS on pipes. */
if (errno == EOPNOTSUPP || errno == ENOTTY
|| errno == EINVAL || errno == ENODEV
# ifdef ENOSYS
|| errno == ENOSYS
# endif
)
use_fionread = 0;
else
{
error (0, errno, _("cannot do ioctl on `%s'"), infile);
exit_status = 1;
newlines2 = newlines;
return;
}
}
if (n_to_read == 0)
#endif
{
size_t n_write = bpout - outbuf;
if (full_write (STDOUT_FILENO, outbuf, n_write) != n_write)
error (EXIT_FAILURE, errno, _("write error"));
bpout = outbuf;
}
/* Read more input into INBUF. */
n_read = safe_read (input_desc, inbuf, insize);
if (n_read == SAFE_READ_ERROR)
{
error (0, errno, "%s", infile);
exit_status = 1;
newlines2 = newlines;
return;
}
if (n_read == 0)
{
newlines2 = newlines;
return;
}
/* Update the pointers and insert a sentinel at the buffer
end. */
bpin = inbuf;
eob = bpin + n_read;
*eob = '\n';
}
else
{
/* It was a real (not a sentinel) newline. */
/* Was the last line empty?
(i.e. have two or more consecutive newlines been read?) */
if (++newlines > 0)
{
if (newlines >= 2)
{
/* Limit this to 2 here. Otherwise, with lots of
consecutive newlines, the counter could wrap
around at INT_MAX. */
newlines = 2;
/* Are multiple adjacent empty lines to be substituted
by single ditto (-s), and this was the second empty
line? */
if (squeeze_empty_lines)
{
ch = *bpin++;
continue;
}
}
/* Are line numbers to be written at empty lines (-n)? */
if (numbers && numbers_at_empty_lines)
{
next_line_num ();
bpout = stpcpy (bpout, line_num_print);
}
}
/* Output a currency symbol if requested (-e). */
if (mark_line_ends)
*bpout++ = '$';
/* Output the newline. */
*bpout++ = '\n';
}
ch = *bpin++;
}
while (ch == '\n');
/* Are we at the beginning of a line, and line numbers are requested? */
if (newlines >= 0 && numbers)
{
next_line_num ();
bpout = stpcpy (bpout, line_num_print);
}
/* Here CH cannot contain a newline character. */
/* The loops below continue until a newline character is found,
which means that the buffer is empty or that a proper newline
has been found. */
/* If quoting, i.e. at least one of -v, -e, or -t specified,
scan for chars that need conversion. */
if (quote)
{
for (;;)
{
if (ch >= 32)
{
if (ch < 127)
*bpout++ = ch;
else if (ch == 127)
{
*bpout++ = '^';
*bpout++ = '?';
}
else
{
*bpout++ = 'M';
*bpout++ = '-';
if (ch >= 128 + 32)
{
if (ch < 128 + 127)
*bpout++ = ch - 128;
else
{
*bpout++ = '^';
*bpout++ = '?';
}
}
else
{
*bpout++ = '^';
*bpout++ = ch - 128 + 64;
}
}
}
else if (ch == '\t' && output_tabs)
*bpout++ = '\t';
else if (ch == '\n')
{
newlines = -1;
break;
}
else
{
*bpout++ = '^';
*bpout++ = ch + 64;
}
ch = *bpin++;
}
}
else
{
/* Not quoting, neither of -v, -e, or -t specified. */
for (;;)
{
if (ch == '\t' && !output_tabs)
{
*bpout++ = '^';
*bpout++ = ch + 64;
}
else if (ch != '\n')
*bpout++ = ch;
else
{
newlines = -1;
break;
}
ch = *bpin++;
}
}
}
}
/* This is gross, but necessary, because of the way close_stdout
works and because this program closes STDOUT_FILENO directly. */
static void (*closeout_func) (void) = close_stdout;
static void
close_stdout_wrapper (void)
{
if (closeout_func)
(*closeout_func) ();
}
int
main (int argc, char **argv)
{
/* Optimal size of i/o operations of output. */
size_t outsize;
/* Optimal size of i/o operations of input. */
size_t insize;
/* Pointer to the input buffer. */
char *inbuf;
/* Pointer to the output buffer. */
char *outbuf;
int c;
/* Index in argv to processed argument. */
int argind;
/* Device number of the output (file or whatever). */
dev_t out_dev;
/* I-node number of the output. */
ino_t out_ino;
/* Nonzero if the output file should not be the same as any input file. */
int check_redirection = 1;
/* Nonzero if we have ever read standard input. */
int have_read_stdin = 0;
struct stat stat_buf;
/* Variables that are set according to the specified options. */
int numbers = 0;
int numbers_at_empty_lines = 1;
int squeeze_empty_lines = 0;
int mark_line_ends = 0;
int quote = 0;
int output_tabs = 1;
#if O_BINARY
int binary_files = 0;
int binary_output = 0;
#endif
int file_open_mode = O_RDONLY;
/* If nonzero, call cat, otherwise call simple_cat to do the actual work. */
int options = 0;
static struct option const long_options[] =
{
{"number-nonblank", no_argument, NULL, 'b'},
{"number", no_argument, NULL, 'n'},
{"squeeze-blank", no_argument, NULL, 's'},
{"show-nonprinting", no_argument, NULL, 'v'},
{"show-ends", no_argument, NULL, 'E'},
{"show-tabs", no_argument, NULL, 'T'},
{"show-all", no_argument, NULL, 'A'},
#if O_BINARY
{"binary", no_argument, NULL, 'B'},
#endif
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
/* Arrange to close stdout if we exit via the
case_GETOPT_HELP_CHAR or case_GETOPT_VERSION_CHAR code. */
atexit (close_stdout_wrapper);
/* Parse command line options. */
while ((c = getopt_long (argc, argv,
#if O_BINARY
"benstuvABET"
#else
"benstuvAET"
#endif
, long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
case 'b':
++options;
numbers = 1;
numbers_at_empty_lines = 0;
break;
case 'e':
++options;
mark_line_ends = 1;
quote = 1;
break;
case 'n':
++options;
numbers = 1;
break;
case 's':
++options;
squeeze_empty_lines = 1;
break;
case 't':
++options;
output_tabs = 0;
quote = 1;
break;
case 'u':
/* We provide the -u feature unconditionally. */
break;
case 'v':
++options;
quote = 1;
break;
case 'A':
++options;
quote = 1;
mark_line_ends = 1;
output_tabs = 0;
break;
#if O_BINARY
case 'B':
++options;
binary_files = 1;
break;
#endif
case 'E':
++options;
mark_line_ends = 1;
break;
case 'T':
++options;
output_tabs = 0;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
/* Don't close stdout on exit from here on. */
closeout_func = NULL;
/* Get device, i-node number, and optimal blocksize of output. */
if (fstat (STDOUT_FILENO, &stat_buf) < 0)
error (EXIT_FAILURE, errno, _("standard output"));
outsize = ST_BLKSIZE (stat_buf);
/* Input file can be output file for non-regular files.
fstat on pipes returns S_IFSOCK on some systems, S_IFIFO
on others, so the checking should not be done for those types,
and to allow things like cat < /dev/tty > /dev/tty, checking
is not done for device files either. */
if (S_ISREG (stat_buf.st_mode))
{
out_dev = stat_buf.st_dev;
out_ino = stat_buf.st_ino;
}
else
{
check_redirection = 0;
#ifdef lint /* Suppress `used before initialized' warning. */
out_dev = 0;
out_ino = 0;
#endif
}
#if O_BINARY
/* We always read and write in BINARY mode, since this is the
best way to copy the files verbatim. Exceptions are when
they request line numbering, squeezing of empty lines or
marking lines' ends: then we use text I/O, because otherwise
-b, -s and -E would surprise users on DOS/Windows where a line
with only CR-LF is an empty line. (Besides, if they ask for
one of these options, they don't care much about the original
file contents anyway). */
if ((!isatty (STDOUT_FILENO)
&& !(numbers || squeeze_empty_lines || mark_line_ends))
|| binary_files)
{
/* Switch stdout to BINARY mode. */
binary_output = 1;
SET_BINARY (STDOUT_FILENO);
/* When stdout is in binary mode, make sure all input files are
also read in binary mode. */
file_open_mode |= O_BINARY;
}
else if (quote)
{
/* If they want to see the non-printables, let's show them
those CR characters as well, so make the input binary.
But keep console output in text mode, so that LF causes
both CR and LF on output, and the output is readable. */
file_open_mode |= O_BINARY;
SET_BINARY (0);
/* Setting stdin to binary switches the console device to
raw I/O, which also affects stdout to console. Undo that. */
if (isatty (STDOUT_FILENO))
setmode (STDOUT_FILENO, O_TEXT);
}
#endif
/* Check if any of the input files are the same as the output file. */
/* Main loop. */
infile = "-";
argind = optind;
do
{
if (argind < argc)
infile = argv[argind];
if (infile[0] == '-' && infile[1] == 0)
{
have_read_stdin = 1;
input_desc = 0;
#if O_BINARY
/* Switch stdin to BINARY mode if needed. */
if (binary_output)
{
int tty_in = isatty (input_desc);
/* If stdin is a terminal device, and it is the ONLY
input file (i.e. we didn't write anything to the
output yet), switch the output back to TEXT mode.
This is so "cat > xyzzy" creates a DOS-style text
file, like people expect. */
if (tty_in && optind <= argc)
setmode (STDOUT_FILENO, O_TEXT);
else
{
SET_BINARY (input_desc);
# ifdef __DJGPP__
/* This is DJGPP-specific. By default, switching console
to binary mode disables SIGINT. But we want terminal
reads to be interruptible. */
if (tty_in)
__djgpp_set_ctrl_c (1);
# endif
}
}
#endif
}
else
{
input_desc = open (infile, file_open_mode);
if (input_desc < 0)
{
error (0, errno, "%s", infile);
exit_status = 1;
continue;
}
}
if (fstat (input_desc, &stat_buf) < 0)
{
error (0, errno, "%s", infile);
exit_status = 1;
goto contin;
}
insize = ST_BLKSIZE (stat_buf);
/* Compare the device and i-node numbers of this input file with
the corresponding values of the (output file associated with)
stdout, and skip this input file if they coincide. Input
files cannot be redirected to themselves. */
if (check_redirection
&& stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino
&& (input_desc != STDIN_FILENO))
{
error (0, 0, _("%s: input file is output file"), infile);
exit_status = 1;
goto contin;
}
/* Select which version of `cat' to use. If any options (more than -u,
--version, or --help) were specified, use `cat', otherwise use
`simple_cat'. */
if (options == 0)
{
insize = max (insize, outsize);
inbuf = xmalloc (insize);
simple_cat (inbuf, insize);
}
else
{
inbuf = xmalloc (insize + 1);
/* Why are (OUTSIZE - 1 + INSIZE * 4 + LINE_COUNTER_BUF_LEN)
bytes allocated for the output buffer?
A test whether output needs to be written is done when the input
buffer empties or when a newline appears in the input. After
output is written, at most (OUTSIZE - 1) bytes will remain in the
buffer. Now INSIZE bytes of input is read. Each input character
may grow by a factor of 4 (by the prepending of M-^). If all
characters do, and no newlines appear in this block of input, we
will have at most (OUTSIZE - 1 + INSIZE * 4) bytes in the buffer.
If the last character in the preceding block of input was a
newline, a line number may be written (according to the given
options) as the first thing in the output buffer. (Done after the
new input is read, but before processing of the input begins.)
A line number requires seldom more than LINE_COUNTER_BUF_LEN
positions. */
outbuf = xmalloc (outsize - 1 + insize * 4 + LINE_COUNTER_BUF_LEN);
cat (inbuf, insize, outbuf, outsize, quote,
output_tabs, numbers, numbers_at_empty_lines, mark_line_ends,
squeeze_empty_lines);
free (outbuf);
}
free (inbuf);
contin:
if (!STREQ (infile, "-") && close (input_desc) < 0)
{
error (0, errno, "%s", infile);
exit_status = 1;
}
}
while (++argind < argc);
if (have_read_stdin && close (STDIN_FILENO) < 0)
error (EXIT_FAILURE, errno, _("closing standard input"));
if (close (STDOUT_FILENO) < 0)
error (EXIT_FAILURE, errno, _("closing standard output"));
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+15
View File
@@ -0,0 +1,15 @@
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
ALG_UNSPECIFIED = 0,
ALG_MD5 = CHAR_MAX + 1,
ALG_SHA1
};
extern int algorithm;
+237
View File
@@ -0,0 +1,237 @@
/* chgrp -- change group ownership of files
Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie <[email protected]>. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <grp.h>
#include <getopt.h>
#include "system.h"
#include "error.h"
#include "lchown.h"
#include "group-member.h"
#include "quote.h"
#include "xstrtol.h"
#include "chown-core.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "chgrp"
#define AUTHORS "David MacKenzie"
/* MAXUID may come from limits.h *or* sys/params.h (via system.h) above. */
#ifndef MAXUID
# define MAXUID UID_T_MAX
#endif
#ifndef MAXGID
# define MAXGID GID_T_MAX
#endif
#ifndef _POSIX_VERSION
struct group *getgrnam ();
#endif
#if ! HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
/* The name the program was run with. */
char *program_name;
/* The argument to the --reference option. Use the group ID of this file.
This file must exist. */
static char *reference_file;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
REFERENCE_FILE_OPTION = CHAR_MAX + 1,
DEREFERENCE_OPTION
};
static struct option const long_options[] =
{
{"recursive", no_argument, 0, 'R'},
{"changes", no_argument, 0, 'c'},
{"dereference", no_argument, 0, DEREFERENCE_OPTION},
{"no-dereference", no_argument, 0, 'h'},
{"quiet", no_argument, 0, 'f'},
{"silent", no_argument, 0, 'f'},
{"reference", required_argument, 0, REFERENCE_FILE_OPTION},
{"verbose", no_argument, 0, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
/* Set *G according to NAME. */
static void
parse_group (const char *name, gid_t *g)
{
struct group *grp;
if (*name == '\0')
error (EXIT_FAILURE, 0, _("cannot change to null group"));
grp = getgrnam (name);
if (grp == NULL)
{
strtol_error s_err;
unsigned long int tmp_long;
if (!ISDIGIT (*name))
error (EXIT_FAILURE, 0, _("invalid group name %s"), quote (name));
s_err = xstrtoul (name, NULL, 0, &tmp_long, NULL);
if (s_err != LONGINT_OK)
STRTOL_FATAL_ERROR (name, _("group number"), s_err);
if (tmp_long > MAXGID)
error (EXIT_FAILURE, 0, _("invalid group number %s"), quote (name));
*g = tmp_long;
}
else
*g = grp->gr_gid;
endgrent (); /* Save a file descriptor. */
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... GROUP FILE...\n\
or: %s [OPTION]... --reference=RFILE FILE...\n\
"),
program_name, program_name);
fputs (_("\
Change the group membership of each FILE to GROUP.\n\
\n\
-c, --changes like verbose but report only when a change is made\n\
--dereference affect the referent of each symbolic link, rather\n\
than the symbolic link itself\n\
"), stdout);
fputs (_("\
-h, --no-dereference affect symbolic links instead of any referenced file\n\
(available only on systems that can change the\n\
ownership of a symlink)\n\
"), stdout);
fputs (_("\
-f, --silent, --quiet suppress most error messages\n\
--reference=RFILE use RFILE's group rather than the specified\n\
GROUP value\n\
-R, --recursive operate on files and directories recursively\n\
-v, --verbose output a diagnostic for every file processed\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
gid_t gid;
int errors = 0;
int optc;
struct Chown_option chopt;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
chopt_init (&chopt);
while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case REFERENCE_FILE_OPTION:
reference_file = optarg;
break;
case DEREFERENCE_OPTION:
chopt.dereference = DEREF_ALWAYS;
break;
case 'R':
chopt.recurse = 1;
break;
case 'c':
chopt.verbosity = V_changes_only;
break;
case 'f':
chopt.force_silent = 1;
break;
case 'h':
chopt.dereference = DEREF_NEVER;
break;
case 'v':
chopt.verbosity = V_high;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc - optind + (reference_file ? 1 : 0) <= 1)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
if (reference_file)
{
struct stat ref_stats;
if (stat (reference_file, &ref_stats))
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
quote (reference_file));
chopt.group_name = gid_to_name (ref_stats.st_gid);
gid = ref_stats.st_gid;
}
else
{
chopt.group_name = argv[optind++];
parse_group (chopt.group_name, &gid);
}
for (; optind < argc; ++optind)
errors |= change_file_owner (1, argv[optind], (uid_t) -1, gid,
(uid_t) -1, (gid_t) -1, &chopt);
chopt_free (&chopt);
exit (errors);
}
+372
View File
@@ -0,0 +1,372 @@
/* chmod -- change permission modes of files
Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "error.h"
#include "filemode.h"
#include "modechange.h"
#include "quote.h"
#include "savedir.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "chmod"
#define AUTHORS "David MacKenzie"
enum Change_status
{
CH_SUCCEEDED,
CH_FAILED,
CH_NO_CHANGE_REQUESTED
};
enum Verbosity
{
/* Print a message for each file that is processed. */
V_high,
/* Print a message for each file whose attributes we change. */
V_changes_only,
/* Do not be verbose. This is the default. */
V_off
};
static int change_dir_mode (const char *dir, const struct mode_change *changes);
/* The name the program was run with. */
char *program_name;
/* If nonzero, change the modes of directories recursively. */
static int recurse;
/* If nonzero, force silence (no error messages). */
static int force_silent;
/* Level of verbosity. */
static enum Verbosity verbosity = V_off;
/* The argument to the --reference option. Use the owner and group IDs
of this file. This file must exist. */
static char *reference_file;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
REFERENCE_FILE_OPTION = CHAR_MAX + 1
};
static struct option const long_options[] =
{
{"recursive", no_argument, 0, 'R'},
{"changes", no_argument, 0, 'c'},
{"silent", no_argument, 0, 'f'},
{"quiet", no_argument, 0, 'f'},
{"reference", required_argument, 0, REFERENCE_FILE_OPTION},
{"verbose", no_argument, 0, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
static int
mode_changed (const char *file, mode_t old_mode)
{
struct stat new_stats;
if (stat (file, &new_stats))
{
if (force_silent == 0)
error (0, errno, _("getting new attributes of %s"), quote (file));
return 0;
}
return old_mode != new_stats.st_mode;
}
/* Tell the user how/if the MODE of FILE has been changed.
CHANGED describes what (if anything) has happened. */
static void
describe_change (const char *file, mode_t mode,
enum Change_status changed)
{
char perms[11]; /* "-rwxrwxrwx" ls-style modes. */
const char *fmt;
mode_string (mode, perms);
perms[10] = '\0'; /* `mode_string' does not null terminate. */
switch (changed)
{
case CH_SUCCEEDED:
fmt = _("mode of %s changed to %04lo (%s)\n");
break;
case CH_FAILED:
fmt = _("failed to change mode of %s to %04lo (%s)\n");
break;
case CH_NO_CHANGE_REQUESTED:
fmt = _("mode of %s retained as %04lo (%s)\n");
break;
default:
abort ();
}
printf (fmt, quote (file),
(unsigned long) (mode & CHMOD_MODE_BITS), &perms[1]);
}
/* Change the mode of FILE according to the list of operations CHANGES.
If DEREF_SYMLINK is nonzero and FILE is a symbolic link, change the
mode of the referenced file. If DEREF_SYMLINK is zero, ignore symbolic
links. Return 0 if successful, 1 if errors occurred. */
static int
change_file_mode (const char *file, const struct mode_change *changes,
const int deref_symlink)
{
struct stat file_stats;
mode_t newmode;
int errors = 0;
int fail;
int saved_errno;
if (deref_symlink ? stat (file, &file_stats) : lstat (file, &file_stats))
{
if (force_silent == 0)
error (0, errno, _("failed to get attributes of %s"), quote (file));
return 1;
}
#ifdef S_ISLNK
if (S_ISLNK (file_stats.st_mode))
return 0;
#endif
newmode = mode_adjust (file_stats.st_mode, changes);
fail = chmod (file, newmode);
saved_errno = errno;
if (verbosity == V_high
|| (verbosity == V_changes_only
&& !fail && mode_changed (file, file_stats.st_mode)))
describe_change (file, newmode, (fail ? CH_FAILED : CH_SUCCEEDED));
if (fail)
{
if (force_silent == 0)
error (0, saved_errno, _("changing permissions of %s"),
quote (file));
errors = 1;
}
if (recurse && S_ISDIR (file_stats.st_mode))
errors |= change_dir_mode (file, changes);
return errors;
}
/* Recursively change the modes of the files in directory DIR
according to the list of operations CHANGES.
Return 0 if successful, 1 if errors occurred. */
static int
change_dir_mode (const char *dir, const struct mode_change *changes)
{
char *name_space, *namep;
char *path; /* Full path of each entry to process. */
unsigned dirlength; /* Length of DIR and '\0'. */
unsigned filelength; /* Length of each pathname to process. */
unsigned pathlength; /* Bytes allocated for `path'. */
int errors = 0;
name_space = savedir (dir);
if (name_space == NULL)
{
if (force_silent == 0)
error (0, errno, "%s", quote (dir));
return 1;
}
dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */
pathlength = dirlength + 1;
/* Give `path' a dummy value; it will be reallocated before first use. */
path = xmalloc (pathlength);
strcpy (path, dir);
path[dirlength - 1] = '/';
for (namep = name_space; *namep; namep += filelength - dirlength)
{
filelength = dirlength + strlen (namep) + 1;
if (filelength > pathlength)
{
pathlength = filelength * 2;
path = xrealloc (path, pathlength);
}
strcpy (path + dirlength, namep);
errors |= change_file_mode (path, changes, 0);
}
free (path);
free (name_space);
return errors;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... MODE[,MODE]... FILE...\n\
or: %s [OPTION]... OCTAL-MODE FILE...\n\
or: %s [OPTION]... --reference=RFILE FILE...\n\
"),
program_name, program_name, program_name);
fputs (_("\
Change the mode of each FILE to MODE.\n\
\n\
-c, --changes like verbose but report only when a change is made\n\
-f, --silent, --quiet suppress most error messages\n\
-v, --verbose output a diagnostic for every file processed\n\
--reference=RFILE use RFILE's mode instead of MODE values\n\
-R, --recursive change files and directories recursively\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Each MODE is one or more of the letters ugoa, one of the symbols +-= and\n\
one or more of the letters rwxXstugo.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Parse the ASCII mode given on the command line into a linked list
of `struct mode_change' and apply that to each file argument. */
int
main (int argc, char **argv)
{
struct mode_change *changes;
int errors = 0;
int modeind = 0; /* Index of the mode argument in `argv'. */
int thisind;
int c;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
recurse = force_silent = 0;
while (1)
{
thisind = optind ? optind : 1;
c = getopt_long (argc, argv, "RcfvrwxXstugoa,+-=", long_options, NULL);
if (c == -1)
break;
switch (c)
{
case 0:
break;
case 'r':
case 'w':
case 'x':
case 'X':
case 's':
case 't':
case 'u':
case 'g':
case 'o':
case 'a':
case ',':
case '+':
case '-':
case '=':
if (modeind != 0 && modeind != thisind)
{
static char char_string[2] = {0, 0};
char_string[0] = c;
error (EXIT_FAILURE, 0, _("invalid character %s in mode string %s"),
quote_n (0, char_string), quote_n (1, argv[thisind]));
}
modeind = thisind;
break;
case REFERENCE_FILE_OPTION:
reference_file = optarg;
break;
case 'R':
recurse = 1;
break;
case 'c':
verbosity = V_changes_only;
break;
case 'f':
force_silent = 1;
break;
case 'v':
verbosity = V_high;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (modeind == 0 && reference_file == NULL)
modeind = optind++;
if (optind >= argc)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
changes = (reference_file ? mode_create_from_ref (reference_file)
: mode_compile (argv[modeind], MODE_MASK_ALL));
if (changes == MODE_INVALID)
error (EXIT_FAILURE, 0,
_("invalid mode string: %s"), quote (argv[modeind]));
else if (changes == MODE_MEMORY_EXHAUSTED)
xalloc_die ();
else if (changes == MODE_BAD_REFERENCE)
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
quote (reference_file));
for (; optind < argc; ++optind)
errors |= change_file_mode (argv[optind], changes, 1);
exit (errors);
}
+362
View File
@@ -0,0 +1,362 @@
/* chown-core.c -- core functions for changing ownership.
Copyright (C) 2000, 2002 Free Software Foundation.
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, 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. */
/* Extracted from chown.c/chgrp.c and librarified by Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include "system.h"
#include "error.h"
#include "lchown.h"
#include "quote.h"
#include "savedir.h"
#include "chown-core.h"
/* The number of decimal digits required to represent the largest value of
type `unsigned int'. This is enough for an 8-byte unsigned int type. */
#define UINT_MAX_DECIMAL_DIGITS 20
#ifndef _POSIX_VERSION
struct group *getgrnam ();
struct group *getgrgid ();
#endif
int lstat ();
void
chopt_init (struct Chown_option *chopt)
{
chopt->verbosity = V_off;
chopt->dereference = DEREF_NEVER;
chopt->recurse = 0;
chopt->force_silent = 0;
chopt->user_name = 0;
chopt->group_name = 0;
}
void
chopt_free (struct Chown_option *chopt)
{
/* Deliberately do not free chopt->user_name or ->group_name.
They're not always allocated. */
}
/* Convert N to a string, and return a pointer to that string in memory
allocated from the heap. */
static char *
uint_to_string (unsigned int n)
{
char buf[UINT_MAX_DECIMAL_DIGITS + 1];
char *p = buf + sizeof buf;
*--p = '\0';
do
*--p = '0' + (n % 10);
while ((n /= 10) != 0);
return xstrdup (p);
}
/* Convert the numeric group-id, GID, to a string stored in xmalloc'd memory,
and return it. If there's no corresponding group name, use the decimal
representation of the ID. */
char *
gid_to_name (gid_t gid)
{
struct group *grp = getgrgid (gid);
return grp ? xstrdup (grp->gr_name) : uint_to_string (gid);
}
/* Convert the numeric user-id, UID, to a string stored in xmalloc'd memory,
and return it. If there's no corresponding user name, use the decimal
representation of the ID. */
char *
uid_to_name (uid_t uid)
{
struct passwd *pwd = getpwuid (uid);
return pwd ? xstrdup (pwd->pw_name) : uint_to_string (uid);
}
/* Tell the user how/if the user and group of FILE have been changed.
If USER is NULL, give the group-oriented messages.
CHANGED describes what (if anything) has happened. */
static void
describe_change (const char *file, enum Change_status changed,
char const *user, char const *group)
{
const char *fmt;
char *spec;
int spec_allocated = 0;
if (changed == CH_NOT_APPLIED)
{
printf (_("neither symbolic link %s nor referent has been changed\n"),
quote (file));
return;
}
if (user)
{
if (group)
{
spec = xmalloc (strlen (user) + 1 + strlen (group) + 1);
stpcpy (stpcpy (stpcpy (spec, user), ":"), group);
spec_allocated = 1;
}
else
{
spec = (char *) user;
}
}
else
{
spec = (char *) group;
}
switch (changed)
{
case CH_SUCCEEDED:
fmt = (user
? _("changed ownership of %s to %s\n")
: _("changed group of %s to %s\n"));
break;
case CH_FAILED:
fmt = (user
? _("failed to change ownership of %s to %s\n")
: _("failed to change group of %s to %s\n"));
break;
case CH_NO_CHANGE_REQUESTED:
fmt = (user
? _("ownership of %s retained as %s\n")
: _("group of %s retained as %s\n"));
break;
default:
abort ();
}
printf (fmt, quote (file), spec);
if (spec_allocated)
free (spec);
}
/* Recursively change the ownership of the files in directory DIR to user-id,
UID, and group-id, GID, according to the options specified by CHOPT.
Return 0 if successful, 1 if errors occurred. */
static int
change_dir_owner (const char *dir, uid_t uid, gid_t gid,
uid_t old_uid, gid_t old_gid,
struct Chown_option const *chopt)
{
char *name_space, *namep;
char *path; /* Full path of each entry to process. */
unsigned dirlength; /* Length of `dir' and '\0'. */
unsigned filelength; /* Length of each pathname to process. */
unsigned pathlength; /* Bytes allocated for `path'. */
int errors = 0;
name_space = savedir (dir);
if (name_space == NULL)
{
if (chopt->force_silent == 0)
error (0, errno, "%s", quote (dir));
return 1;
}
dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */
pathlength = dirlength + 1;
/* Give `path' a dummy value; it will be reallocated before first use. */
path = xmalloc (pathlength);
strcpy (path, dir);
path[dirlength - 1] = '/';
for (namep = name_space; *namep; namep += filelength - dirlength)
{
filelength = dirlength + strlen (namep) + 1;
if (filelength > pathlength)
{
pathlength = filelength * 2;
path = xrealloc (path, pathlength);
}
strcpy (path + dirlength, namep);
errors |= change_file_owner (0, path, uid, gid, old_uid, old_gid,
chopt);
}
free (path);
free (name_space);
return errors;
}
/* Change the ownership of FILE to user-id, UID, and group-id, GID,
provided it presently has owner OLD_UID and group OLD_GID.
Honor the options specified by CHOPT.
If FILE is a directory and -R is given, recurse.
Return 0 if successful, 1 if errors occurred. */
int
change_file_owner (int cmdline_arg, const char *file, uid_t uid, gid_t gid,
uid_t old_uid, gid_t old_gid,
struct Chown_option const *chopt)
{
struct stat file_stats;
uid_t new_uid;
gid_t new_gid;
int errors = 0;
int is_symlink;
int is_directory;
if (lstat (file, &file_stats))
{
if (chopt->force_silent == 0)
error (0, errno, _("failed to get attributes of %s"), quote (file));
return 1;
}
/* If it's a symlink and we're dereferencing, then use stat
to get the attributes of the referent. */
if (S_ISLNK (file_stats.st_mode))
{
if (chopt->dereference == DEREF_ALWAYS
&& stat (file, &file_stats))
{
if (chopt->force_silent == 0)
error (0, errno, _("failed to get attributes of %s"), quote (file));
return 1;
}
is_symlink = 1;
/* With -R, don't traverse through symlinks-to-directories.
But of course, this will all change with POSIX's new
-H, -L, -P options. */
is_directory = 0;
}
else
{
is_symlink = 0;
is_directory = S_ISDIR (file_stats.st_mode);
}
if ((old_uid == (uid_t) -1 || file_stats.st_uid == old_uid)
&& (old_gid == (gid_t) -1 || file_stats.st_gid == old_gid))
{
new_uid = (uid == (uid_t) -1 ? file_stats.st_uid : uid);
new_gid = (gid == (gid_t) -1 ? file_stats.st_gid : gid);
if (new_uid != file_stats.st_uid || new_gid != file_stats.st_gid)
{
int fail;
int symlink_changed = 1;
int saved_errno;
int called_lchown = 0;
if (is_symlink)
{
if (chopt->dereference == DEREF_NEVER)
{
called_lchown = 1;
fail = lchown (file, new_uid, new_gid);
/* Ignore the failure if it's due to lack of support (ENOSYS)
and this is not a command line argument. */
if (!cmdline_arg && fail && errno == ENOSYS)
{
fail = 0;
symlink_changed = 0;
}
}
else if (chopt->dereference == DEREF_ALWAYS)
{
/* Applying chown to a symlink and expecting it to affect
the referent is not portable. So instead, open the
file and use fchown on the resulting descriptor. */
int fd = open (file, O_RDONLY | O_NONBLOCK | O_NOCTTY);
fail = (fd == -1 ? 1 : fchown (fd, new_uid, new_gid));
}
else
{
/* FIXME */
abort ();
}
}
else
{
fail = chown (file, new_uid, new_gid);
}
saved_errno = errno;
if (chopt->verbosity == V_high
|| (chopt->verbosity == V_changes_only && !fail))
{
enum Change_status ch_status = (! symlink_changed
? CH_NOT_APPLIED
: (fail
? CH_FAILED : CH_SUCCEEDED));
describe_change (file, ch_status,
chopt->user_name, chopt->group_name);
}
if (fail)
{
if (chopt->force_silent == 0)
error (0, saved_errno, (uid != (uid_t) -1
? _("changing ownership of %s")
: _("changing group of %s")),
quote (file));
errors = 1;
}
else
{
/* The change succeeded. On some systems, the chown function
resets the `special' permission bits. When run by a
`privileged' user, this program must ensure that at least
the set-uid and set-group ones are still set. */
if (file_stats.st_mode & ~(S_IFMT | S_IRWXUGO)
/* If we called lchown above (which means this is a symlink),
then skip it. */
&& ! called_lchown)
{
if (chmod (file, file_stats.st_mode))
{
error (0, saved_errno,
_("unable to restore permissions of %s"),
quote (file));
fail = 1;
}
}
}
}
else if (chopt->verbosity == V_high)
{
describe_change (file, CH_NO_CHANGE_REQUESTED,
chopt->user_name, chopt->group_name);
}
}
if (chopt->recurse && is_directory)
errors |= change_dir_owner (file, uid, gid, old_uid, old_gid, chopt);
return errors;
}
@@ -0,0 +1,89 @@
/* chown-core.h -- types and prototypes shared by chown and chgrp.
Copyright (C) 2000, 2003 Free Software Foundation.
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, 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. */
#ifndef CHOWN_CORE_H
# define CHOWN_CORE_H
enum Change_status
{
CH_NOT_APPLIED = 1,
CH_SUCCEEDED,
CH_FAILED,
CH_NO_CHANGE_REQUESTED
};
enum Verbosity
{
/* Print a message for each file that is processed. */
V_high,
/* Print a message for each file whose attributes we change. */
V_changes_only,
/* Do not be verbose. This is the default. */
V_off
};
enum Dereference_symlink
{
DEREF_UNDEFINED = 1,
DEREF_NEVER, /* -P */
DEREF_COMMAND_LINE_ARGUMENTS, /* -H */
DEREF_ALWAYS /* -L */
};
struct Chown_option
{
/* Level of verbosity. */
enum Verbosity verbosity;
/* If nonzero, change the ownership of directories recursively. */
int recurse;
/* This is useful only on systems with support for changing the
ownership of symbolic links. */
enum Dereference_symlink dereference;
/* If nonzero, force silence (no error messages). */
int force_silent;
/* The name of the user to which ownership of the files is being given. */
char *user_name;
/* The name of the group to which ownership of the files is being given. */
char *group_name;
};
void
chopt_init (struct Chown_option *);
void
chopt_free (struct Chown_option *);
char *
gid_to_name (gid_t);
char *
uid_to_name (uid_t);
int
change_file_owner (int, const char *,
uid_t, gid_t,
uid_t, gid_t,
struct Chown_option const *);
#endif /* CHOWN_CORE_H */
+249
View File
@@ -0,0 +1,249 @@
/* chown -- change user and group ownership of files
Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/*
| user
| unchanged explicit
-------------|-------------------------+-------------------------|
g unchanged | --- | chown u |
r |-------------------------+-------------------------|
o explicit | chgrp g or chown .g | chown u.g |
u |-------------------------+-------------------------|
p from passwd| --- | chown u. |
|-------------------------+-------------------------|
Written by David MacKenzie <[email protected]>. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "error.h"
#include "lchown.h"
#include "quote.h"
#include "chown-core.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "chown"
#define AUTHORS "David MacKenzie"
#ifndef _POSIX_VERSION
struct passwd *getpwnam ();
struct group *getgrnam ();
struct group *getgrgid ();
#endif
#if ! HAVE_ENDPWENT
# define endpwent() ((void) 0)
#endif
char *parse_user_spec ();
/* The name the program was run with. */
char *program_name;
/* The argument to the --reference option. Use the owner and group IDs
of this file. This file must exist. */
static char *reference_file;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
REFERENCE_FILE_OPTION = CHAR_MAX + 1,
DEREFERENCE_OPTION,
FROM_OPTION
};
static struct option const long_options[] =
{
{"recursive", no_argument, 0, 'R'},
{"changes", no_argument, 0, 'c'},
{"dereference", no_argument, 0, DEREFERENCE_OPTION},
{"from", required_argument, 0, FROM_OPTION},
{"no-dereference", no_argument, 0, 'h'},
{"quiet", no_argument, 0, 'f'},
{"silent", no_argument, 0, 'f'},
{"reference", required_argument, 0, REFERENCE_FILE_OPTION},
{"verbose", no_argument, 0, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... OWNER[:[GROUP]] FILE...\n\
or: %s [OPTION]... :GROUP FILE...\n\
or: %s [OPTION]... --reference=RFILE FILE...\n\
"),
program_name, program_name, program_name);
fputs (_("\
Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
\n\
-c, --changes like verbose but report only when a change is made\n\
--dereference affect the referent of each symbolic link, rather\n\
than the symbolic link itself\n\
"), stdout);
fputs (_("\
-h, --no-dereference affect symbolic links instead of any referenced file\n\
(available only on systems that can change the\n\
ownership of a symlink)\n\
"), stdout);
fputs (_("\
--from=CURRENT_OWNER:CURRENT_GROUP\n\
change the owner and/or group of each file only if\n\
its current owner and/or group match those specified\n\
here. Either may be omitted, in which case a match\n\
is not required for the omitted attribute.\n\
"), stdout);
fputs (_("\
-f, --silent, --quiet suppress most error messages\n\
--reference=RFILE use RFILE's owner and group rather than\n\
the specified OWNER:GROUP values\n\
-R, --recursive operate on files and directories recursively\n\
-v, --verbose output a diagnostic for every file processed\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Owner is unchanged if missing. Group is unchanged if missing, but changed\n\
to login group if implied by a `:'. OWNER and GROUP may be numeric as well\n\
as symbolic.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
uid_t uid = (uid_t) -1; /* New uid; -1 if not to be changed. */
gid_t gid = (uid_t) -1; /* New gid; -1 if not to be changed. */
uid_t old_uid = (uid_t) -1; /* Old uid; -1 if unrestricted. */
gid_t old_gid = (uid_t) -1; /* Old gid; -1 if unrestricted. */
struct Chown_option chopt;
int errors = 0;
int optc;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
chopt_init (&chopt);
while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case REFERENCE_FILE_OPTION:
reference_file = optarg;
break;
case DEREFERENCE_OPTION:
chopt.dereference = DEREF_ALWAYS;
break;
case FROM_OPTION:
{
char *u_dummy, *g_dummy;
const char *e = parse_user_spec (optarg,
&old_uid, &old_gid,
&u_dummy, &g_dummy);
if (e)
error (EXIT_FAILURE, 0, "%s: %s", quote (optarg), e);
break;
}
case 'R':
chopt.recurse = 1;
break;
case 'c':
chopt.verbosity = V_changes_only;
break;
case 'f':
chopt.force_silent = 1;
break;
case 'h':
chopt.dereference = DEREF_NEVER;
break;
case 'v':
chopt.verbosity = V_high;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc - optind + (reference_file ? 1 : 0) <= 1)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
if (reference_file)
{
struct stat ref_stats;
if (stat (reference_file, &ref_stats))
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
quote (reference_file));
uid = ref_stats.st_uid;
gid = ref_stats.st_gid;
chopt.user_name = uid_to_name (ref_stats.st_uid);
chopt.group_name = gid_to_name (ref_stats.st_gid);
}
else
{
const char *e = parse_user_spec (argv[optind], &uid, &gid,
&chopt.user_name, &chopt.group_name);
if (e)
error (EXIT_FAILURE, 0, "%s: %s", quote (argv[optind]), e);
/* FIXME: set it to the empty string? */
if (chopt.user_name == NULL)
chopt.user_name = "";
optind++;
}
for (; optind < argc; ++optind)
errors |= change_file_owner (1, argv[optind], uid, gid,
old_uid, old_gid, &chopt);
chopt_free (&chopt);
exit (errors);
}
+112
View File
@@ -0,0 +1,112 @@
/* chroot -- run command or shell with special root directory
Copyright (C) 95, 96, 1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Roland McGrath. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "long-options.h"
#include "error.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "chroot"
#define AUTHORS "Roland McGrath"
/* The name this program was run with, for error messages. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s NEWROOT [COMMAND...]\n\
or: %s OPTION\n\
"), program_name, program_name);
fputs (_("\
Run COMMAND with root directory set to NEWROOT.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
If no command is given, run ``${SHELL} -i'' (default: /bin/sh).\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
if (argc == 1)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
if (chroot (argv[1]))
error (EXIT_FAILURE, errno,
_("cannot change root directory to %s"), argv[1]);
if (chdir ("/"))
error (EXIT_FAILURE, errno, _("cannot chdir to root directory"));
if (argc == 2)
{
/* No command. Run an interactive shell. */
char *shell = getenv ("SHELL");
if (shell == NULL)
shell = "/bin/sh";
argv[0] = shell;
argv[1] = "-i";
}
else
{
/* The following arguments give the command. */
argv += 2;
}
/* Execute the given command. */
execvp (argv[0], argv);
{
int exit_status = (errno == ENOENT ? 127 : 126);
error (0, errno, "%s", argv[0]);
exit (exit_status);
}
}
+341
View File
@@ -0,0 +1,341 @@
/* cksum -- calculate and print POSIX checksums and sizes of files
Copyright (C) 92, 1995-2003 Free Software Foundation, Inc.
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, 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. */
/* Written by Q. Frank Xia, [email protected].
Cosmetic changes and reorganization by David MacKenzie, [email protected].
Usage: cksum [file...]
The code segment between "#ifdef CRCTAB" and "#else" is the code
which calculates the "crctab". It is included for those who want
verify the correctness of the "crctab". To recreate the "crctab",
do following:
cc -DCRCTAB -o crctab cksum.c
crctab > crctab.h
As Bruce Evans pointed out to me, the crctab in the sample C code
in 4.9.10 Rationale of P1003.2/D11.2 is represented in reversed order.
Namely, 0x01 is represented as 0x80, 0x02 is represented as 0x40, etc.
The generating polynomial is crctab[0x80]=0xedb88320 instead of
crctab[1]=0x04C11DB7. But the code works only for a non-reverse order
crctab. Therefore, the sample implementation is wrong.
This software is compatible with neither the System V nor the BSD
`sum' program. It is supposed to conform to P1003.2/D11.2,
except foreign language interface (4.9.5.3 of P1003.2/D11.2) support.
Any inconsistency with the standard except 4.9.5.3 is a bug. */
#include <config.h>
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "cksum"
#define AUTHORS "Q. Frank Xia"
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#if !defined UINT_FAST32_MAX && !defined uint_fast32_t
# define uint_fast32_t unsigned int
#endif
#ifdef CRCTAB
# define BIT(x) ((uint_fast32_t) 1 << (x))
# define SBIT BIT (31)
/* The generating polynomial is
32 26 23 22 16 12 11 10 8 7 5 4 2 1
G(X)=X + X + X + X + X + X + X + X + X + X + X + X + X + X + 1
The i bit in GEN is set if X^i is a summand of G(X) except X^32. */
# define GEN (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \
| BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \
| BIT (4) | BIT (2) | BIT (1) | BIT (0))
static uint_fast32_t r[8];
static void
fill_r (void)
{
int i;
r[0] = GEN;
for (i = 1; i < 8; i++)
r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0);
}
static uint_fast32_t
remainder (int m)
{
uint_fast32_t rem = 0;
int i;
for (i = 0; i < 8; i++)
if (BIT (i) & m)
rem ^= r[i];
return rem & 0xFFFFFFFF; /* Make it run on 64-bit machine. */
}
int
main (void)
{
int i;
fill_r ();
printf ("static uint_fast32_t crctab[256] =\n{\n 0x0");
for (i = 0; i < 51; i++)
{
printf (",\n 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X",
remainder (i * 5 + 1), remainder (i * 5 + 2),
remainder (i * 5 + 3), remainder (i * 5 + 4),
remainder (i * 5 + 5));
}
printf ("\n};\n");
exit (EXIT_SUCCESS);
}
#else /* !CRCTAB */
# include <getopt.h>
# include "closeout.h"
# include "long-options.h"
# include "error.h"
# include "inttostr.h"
/* Number of bytes to read at once. */
# define BUFLEN (1 << 16)
/* The name this program was run with. */
char *program_name;
static struct option const long_options[] =
{
{0, 0, 0, 0}
};
static uint_fast32_t crctab[256] =
{
0x0,
0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
};
/* Nonzero if any of the files read were the standard input. */
static int have_read_stdin;
/* Calculate and print the checksum and length in bytes
of file FILE, or of the standard input if FILE is "-".
If PRINT_NAME is nonzero, print FILE next to the checksum and size.
Return 0 if successful, -1 if an error occurs. */
static int
cksum (const char *file, int print_name)
{
unsigned char buf[BUFLEN];
uint_fast32_t crc = 0;
uintmax_t length = 0;
size_t bytes_read;
register FILE *fp;
char length_buf[INT_BUFSIZE_BOUND (uintmax_t)];
char const *hp;
if (STREQ (file, "-"))
{
fp = stdin;
have_read_stdin = 1;
}
else
{
fp = fopen (file, "r");
if (fp == NULL)
{
error (0, errno, "%s", file);
return -1;
}
}
/* Read input in BINARY mode, unless it is a console device. */
SET_BINARY (fileno (fp));
while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0)
{
unsigned char *cp = buf;
if (length + bytes_read < length)
error (EXIT_FAILURE, 0, _("%s: file too long"), file);
length += bytes_read;
while (bytes_read--)
crc = (crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
if (feof (fp))
break;
}
if (ferror (fp))
{
error (0, errno, "%s", file);
if (!STREQ (file, "-"))
fclose (fp);
return -1;
}
if (!STREQ (file, "-") && fclose (fp) == EOF)
{
error (0, errno, "%s", file);
return -1;
}
hp = umaxtostr (length, length_buf);
for (; length; length >>= 8)
crc = (crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
crc = ~crc & 0xFFFFFFFF;
if (print_name)
printf ("%u %s %s\n", (unsigned) crc, hp, file);
else
printf ("%u %s\n", (unsigned) crc, hp);
if (ferror (stdout))
error (EXIT_FAILURE, errno, "-: %s", _("write error"));
return 0;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [FILE]...\n\
or: %s [OPTION]\n\
"),
program_name, program_name);
fputs (_("\
Print CRC checksum and byte counts of each FILE.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
int
main (int argc, char **argv)
{
int i, c;
int errors = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION,
AUTHORS, usage);
have_read_stdin = 0;
while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
errors |= cksum ("-", 0);
else
{
for (i = optind; i < argc; i++)
errors |= cksum (argv[i], 1);
}
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, "-");
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
#endif /* !CRCTAB */
+268
View File
@@ -0,0 +1,268 @@
/* comm -- compare two sorted files line by line.
Copyright (C) 86, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Richard Stallman and David MacKenzie. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "linebuffer.h"
#include "error.h"
#include "hard-locale.h"
#include "xmemcoll.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "comm"
#define AUTHORS N_ ("Richard Stallman and David MacKenzie")
/* Undefine, to avoid warning about redefinition on some systems. */
#undef min
#define min(x, y) ((x) < (y) ? (x) : (y))
/* The name this program was run with. */
char *program_name;
/* Nonzero if the LC_COLLATE locale is hard. */
static int hard_LC_COLLATE;
/* If nonzero, print lines that are found only in file 1. */
static int only_file_1;
/* If nonzero, print lines that are found only in file 2. */
static int only_file_2;
/* If nonzero, print lines that are found in both files. */
static int both;
static struct option const long_options[] =
{
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... LEFT_FILE RIGHT_FILE\n\
"),
program_name);
fputs (_("\
Compare sorted files LEFT_FILE and RIGHT_FILE line by line.\n\
\n\
-1 suppress lines unique to left file\n\
-2 suppress lines unique to right file\n\
-3 suppress lines that appear in both files\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Output the line in linebuffer LINE to stream STREAM
provided the switches say it should be output.
CLASS is 1 for a line found only in file 1,
2 for a line only in file 2, 3 for a line in both. */
static void
writeline (const struct linebuffer *line, FILE *stream, int class)
{
switch (class)
{
case 1:
if (!only_file_1)
return;
break;
case 2:
if (!only_file_2)
return;
/* Print a TAB if we are printing lines from file 1. */
if (only_file_1)
putc ('\t', stream);
break;
case 3:
if (!both)
return;
/* Print a TAB if we are printing lines from file 1. */
if (only_file_1)
putc ('\t', stream);
/* Print a TAB if we are printing lines from file 2. */
if (only_file_2)
putc ('\t', stream);
break;
}
fwrite (line->buffer, sizeof (char), line->length, stream);
}
/* Compare INFILES[0] and INFILES[1].
If either is "-", use the standard input for that file.
Assume that each input file is sorted;
merge them and output the result.
Return 0 if successful, 1 if any errors occur. */
static int
compare_files (char **infiles)
{
/* For each file, we have one linebuffer in lb1. */
struct linebuffer lb1[2];
/* thisline[i] points to the linebuffer holding the next available line
in file i, or is NULL if there are no lines left in that file. */
struct linebuffer *thisline[2];
/* streams[i] holds the input stream for file i. */
FILE *streams[2];
int i, ret = 0;
/* Initialize the storage. */
for (i = 0; i < 2; i++)
{
initbuffer (&lb1[i]);
thisline[i] = &lb1[i];
streams[i] = (STREQ (infiles[i], "-") ? stdin : fopen (infiles[i], "r"));
if (!streams[i])
{
error (0, errno, "%s", infiles[i]);
return 1;
}
thisline[i] = readline (thisline[i], streams[i]);
}
while (thisline[0] || thisline[1])
{
int order;
/* Compare the next available lines of the two files. */
if (!thisline[0])
order = 1;
else if (!thisline[1])
order = -1;
else
{
if (HAVE_SETLOCALE && hard_LC_COLLATE)
order = xmemcoll (thisline[0]->buffer, thisline[0]->length - 1,
thisline[1]->buffer, thisline[1]->length - 1);
else
{
size_t len = min (thisline[0]->length, thisline[1]->length) - 1;
order = memcmp (thisline[0]->buffer, thisline[1]->buffer, len);
if (order == 0)
order = (thisline[0]->length < thisline[1]->length
? -1
: thisline[0]->length != thisline[1]->length);
}
}
/* Output the line that is lesser. */
if (order == 0)
writeline (thisline[1], stdout, 3);
else if (order > 0)
writeline (thisline[1], stdout, 2);
else
writeline (thisline[0], stdout, 1);
/* Step the file the line came from.
If the files match, step both files. */
if (order >= 0)
thisline[1] = readline (thisline[1], streams[1]);
if (order <= 0)
thisline[0] = readline (thisline[0], streams[0]);
}
/* Free all storage and close all input streams. */
for (i = 0; i < 2; i++)
{
free (lb1[i].buffer);
if (ferror (streams[i]) || fclose (streams[i]) == EOF)
{
error (0, errno, "%s", infiles[i]);
ret = 1;
}
}
return ret;
}
int
main (int argc, char **argv)
{
int c;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
hard_LC_COLLATE = hard_locale (LC_COLLATE);
atexit (close_stdout);
only_file_1 = 1;
only_file_2 = 1;
both = 1;
while ((c = getopt_long (argc, argv, "123", long_options, NULL)) != -1)
switch (c)
{
case 0:
break;
case '1':
only_file_1 = 0;
break;
case '2':
only_file_2 = 0;
break;
case '3':
both = 0;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
if (optind + 2 != argc)
usage (EXIT_FAILURE);
exit (compare_files (argv + optind) == 0
? EXIT_SUCCESS : EXIT_FAILURE);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+211
View File
@@ -0,0 +1,211 @@
#ifndef COPY_H
# define COPY_H
# include "hash.h"
/* Control creation of sparse files (files with holes). */
enum Sparse_type
{
SPARSE_UNUSED,
/* Never create holes in DEST. */
SPARSE_NEVER,
/* This is the default. Use a crude (and sometimes inaccurate)
heuristic to determine if SOURCE has holes. If so, try to create
holes in DEST. */
SPARSE_AUTO,
/* For every sufficiently long sequence of bytes in SOURCE, try to
create a corresponding hole in DEST. There is a performance penalty
here because CP has to search for holes in SRC. But if the holes are
big enough, that penalty can be offset by the decrease in the amount
of data written to disk. */
SPARSE_ALWAYS
};
/* This type is used to help mv (via copy.c) distinguish these cases. */
enum Interactive
{
I_ALWAYS_YES = 1,
I_ALWAYS_NO,
I_ASK_USER,
I_UNSPECIFIED
};
/* How to handle symbolic links. */
enum Dereference_symlink
{
DEREF_UNDEFINED = 1,
/* Copy the symbolic link itself. -P */
DEREF_NEVER,
/* If the symbolic is a command line argument, then copy
its referent. Otherwise, copy the symbolic link itself. -H */
DEREF_COMMAND_LINE_ARGUMENTS,
/* Copy the referent of the symbolic link. -L */
DEREF_ALWAYS
};
# define VALID_SPARSE_MODE(Mode) \
((Mode) == SPARSE_NEVER \
|| (Mode) == SPARSE_AUTO \
|| (Mode) == SPARSE_ALWAYS)
/* These options control how files are copied by at least the
following programs: mv (when rename doesn't work), cp, install.
So, if you add a new member, be sure to initialize it in
mv.c, cp.c, and install.c. */
struct cp_options
{
enum backup_type backup_type;
/* If nonzero, copy all files except (directories and, if not dereferencing
them, symbolic links,) as if they were regular files. */
int copy_as_regular;
/* How to handle symlinks. */
enum Dereference_symlink dereference;
/* If nonzero, remove each existing destination nondirectory before
trying to open it. */
int unlink_dest_before_opening;
/* If nonzero, first try to open each existing destination nondirectory,
then, if the open fails, unlink and try again.
This option must be set for `cp -f', in case the destination file
exists when the open is attempted. It is irrelevant to `mv' since
any destination is sure to be removed before the open. */
int unlink_dest_after_failed_open;
/* If nonzero, create hard links instead of copying files.
Create destination directories as usual. */
int hard_link;
/* This value is used to determine whether to prompt before removing
each existing destination file. It works differently depending on
whether move_mode is set. See code/comments in copy.c. */
enum Interactive interactive;
/* If nonzero, rather than copying, first attempt to use rename.
If that fails, then resort to copying. */
int move_mode;
/* This process's effective user ID. */
uid_t myeuid;
/* If nonzero, when copying recursively, skip any subdirectories that are
on different filesystems from the one we started on. */
int one_file_system;
/* If nonzero, attempt to give the copies the original files' permissions,
owner, group, and timestamps. */
int preserve_ownership;
int preserve_mode;
int preserve_timestamps;
/* Enabled for mv, and for cp by the --preserve=links option.
If nonzero, attempt to preserve in the destination files any
logical hard links between the source files. If used with cp's
--no-dereference option, and copying two hard-linked files,
the two corresponding destination files will also be hard linked.
If used with cp's --dereference (-L) option, then, as that option implies,
hard links are *not* preserved. However, when copying a file F and
a symlink S to F, the resulting S and F in the destination directory
will be hard links to the same file (a copy of F). */
int preserve_links;
/* If nonzero and any of the above (for preserve) file attributes cannot
be applied to a destination file, treat it as a failure and return
nonzero immediately. E.g. cp -p requires this be nonzero, mv requires
it be zero. */
int require_preserve;
/* If nonzero, copy directories recursively and copy special files
as themselves rather than copying their contents. */
int recursive;
/* If nonzero, set file mode to value of MODE. Otherwise,
set it based on current umask modified by UMASK_KILL. */
int set_mode;
/* Set the mode of the destination file to exactly this value
if USE_MODE is nonzero. */
mode_t mode;
/* Control creation of sparse files. */
enum Sparse_type sparse_mode;
/* If nonzero, create symbolic links instead of copying files.
Create destination directories as usual. */
int symbolic_link;
/* The bits to preserve in created files' modes. */
mode_t umask_kill;
/* If nonzero, do not copy a nondirectory that has an existing destination
with the same or newer modification time. */
int update;
/* If nonzero, display the names of the files before copying them. */
int verbose;
/* A pointer to either lstat or stat, depending on
whether the copy should dereference symlinks. */
int (*xstat) ();
/* If nonzero, stdin is a tty. */
int stdin_tty;
/* This is a set of destination name/inode/dev triples. Each such triple
represents a file we have created corresponding to a source file name
that was specified on the command line. Use it to avoid clobbering
source files in commands like this:
rm -rf a b c; mkdir a b c; touch a/f b/f; mv a/f b/f c
For now, it protects only regular files when copying (i.e. not renaming).
When renaming, it protects all non-directories.
Use dest_info_init to initialize it, or set it to NULL to disable
this feature. */
Hash_table *dest_info;
/* FIXME */
Hash_table *src_info;
};
int stat ();
int lstat ();
/* Arrange to make lstat calls go through the wrapper function
on systems with an lstat function that does not dereference symlinks
that are specified with a trailing slash. */
# if ! LSTAT_FOLLOWS_SLASHED_SYMLINK
int rpl_lstat (const char *, struct stat *);
# undef lstat
# define lstat rpl_lstat
# endif
int rename ();
/* Arrange to make rename calls go through the wrapper function
on systems with a rename function that fails for a source path
specified with a trailing slash. */
# if RENAME_TRAILING_SLASH_BUG
int rpl_rename (const char *, const char *);
# undef rename
# define rename rpl_rename
# endif
int
copy (const char *src_path, const char *dst_path,
int nonexistent_dst, const struct cp_options *options,
int *copy_into_self, int *rename_succeeded);
void
dest_info_init (struct cp_options *);
void
src_info_init (struct cp_options *);
#endif
+173
View File
@@ -0,0 +1,173 @@
/* cp-hash.c -- file copying (hash search routines)
Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation.
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, 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.
Written by Torbjorn Granlund, Sweden ([email protected]).
Rewritten to use lib/hash.c by Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "same.h"
#include "quote.h"
#include "hash.h"
#include "error.h"
#include "cp-hash.h"
/* Use ST_DEV and ST_INO as the key, FILENAME as the value.
These are used e.g., in copy.c to associate the destination path with
the source device/inode pair so that if we encounter a matching dev/ino
pair in the source tree we can arrange to create a hard link between
the corresponding names in the destination tree. */
struct Src_to_dest
{
ino_t st_ino;
dev_t st_dev;
/* Destination path name (of non-directory or pre-existing directory)
corresponding to the dev/ino of a copied file, or the destination path
name corresponding to a dev/ino pair for a newly-created directory. */
char const* name;
};
/* This table maps source dev/ino to destination file name.
We use it to preserve hard links when copying. */
static Hash_table *src_to_dest;
/* Initial size of the above hash table. */
#define INITIAL_TABLE_SIZE 103
static unsigned int
src_to_dest_hash (void const *x, unsigned int table_size)
{
struct Src_to_dest const *p = x;
/* Ignoring the device number here should be fine. */
/* The cast to uintmax_t prevents negative remainders
if st_ino is negative. */
return (uintmax_t) p->st_ino % table_size;
}
/* Compare two Src_to_dest entries.
Return true if their keys are judged `equal'. */
static bool
src_to_dest_compare (void const *x, void const *y)
{
struct Src_to_dest const *a = x;
struct Src_to_dest const *b = y;
return SAME_INODE (*a, *b) ? true : false;
}
static void
src_to_dest_free (void *x)
{
struct Src_to_dest *a = x;
free ((char *) (a->name));
free (x);
}
/* Remove the entry matching INO/DEV from the table
that maps source ino/dev to destination file name. */
void
forget_created (ino_t ino, dev_t dev)
{
struct Src_to_dest probe;
struct Src_to_dest *ent;
probe.st_ino = ino;
probe.st_dev = dev;
probe.name = NULL;
ent = hash_delete (src_to_dest, &probe);
if (ent)
src_to_dest_free (ent);
}
/* Add PATH to the list of files that we have created.
Return 1 if we can't stat PATH, otherwise 0. */
int
remember_created (const char *path)
{
struct stat sb;
if (stat (path, &sb) < 0)
{
error (0, errno, "%s", quote (path));
return 1;
}
remember_copied (path, sb.st_ino, sb.st_dev);
return 0;
}
/* Add path NAME, copied from inode number INO and device number DEV,
to the list of files we have copied.
Return NULL if inserted, otherwise non-NULL. */
char *
remember_copied (const char *name, ino_t ino, dev_t dev)
{
struct Src_to_dest *ent;
struct Src_to_dest *ent_from_table;
ent = (struct Src_to_dest *) xmalloc (sizeof *ent);
ent->name = xstrdup (name);
ent->st_ino = ino;
ent->st_dev = dev;
ent_from_table = hash_insert (src_to_dest, ent);
if (ent_from_table == NULL)
{
/* Insertion failed due to lack of memory. */
xalloc_die ();
}
/* Determine whether there was already an entry in the table
with a matching key. If so, free ENT (it wasn't inserted) and
return the `name' from the table entry. */
if (ent_from_table != ent)
{
src_to_dest_free (ent);
return (char *) ent_from_table->name;
}
/* New key; insertion succeeded. */
return NULL;
}
/* Initialize the hash table. */
void
hash_init (void)
{
src_to_dest = hash_initialize (INITIAL_TABLE_SIZE, NULL,
src_to_dest_hash,
src_to_dest_compare,
src_to_dest_free);
if (src_to_dest == NULL)
xalloc_die ();
}
/* Reset the hash structure in the global variable `htab' to
contain no entries. */
void
forget_all (void)
{
hash_free (src_to_dest);
}
+5
View File
@@ -0,0 +1,5 @@
void hash_init (void);
void forget_all (void);
void forget_created (ino_t ino, dev_t dev);
char *remember_copied (const char *node, ino_t ino, dev_t dev);
int remember_created (const char *path);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+752
View File
@@ -0,0 +1,752 @@
/* cut - remove parts of lines of files
Copyright (C) 1984, 1997, 1998, 1999, 2000, 2001, 2002, 2003 by David M. Ihnat
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, 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. */
/* Written by David Ihnat. */
/* POSIX changes, bug fixes, long-named options, and cleanup
by David MacKenzie <[email protected]>.
Rewrite cut_fields and cut_bytes -- Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "getstr.h"
#include "closeout.h"
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "cut"
#define AUTHORS N_ ("David Ihnat, David MacKenzie, and Jim Meyering")
#define FATAL_ERROR(Message) \
do \
{ \
error (0, 0, (Message)); \
usage (2); \
} \
while (0)
/* Append LOW, HIGH to the list RP of range pairs, allocating additional
space if necessary. Update local variable N_RP. When allocating,
update global variable N_RP_ALLOCATED. */
#define ADD_RANGE_PAIR(rp, low, high) \
do \
{ \
if (n_rp >= n_rp_allocated) \
{ \
n_rp_allocated *= 2; \
(rp) = (struct range_pair *) xrealloc ((char *) (rp), \
n_rp_allocated * sizeof (*(rp))); \
} \
rp[n_rp].lo = (low); \
rp[n_rp].hi = (high); \
++n_rp; \
} \
while (0)
struct range_pair
{
unsigned int lo;
unsigned int hi;
};
/* This buffer is used to support the semantics of the -s option
(or lack of same) when the specified field list includes (does
not include) the first field. In both of those cases, the entire
first field must be read into this buffer to determine whether it
is followed by a delimiter or a newline before any of it may be
output. Otherwise, cut_fields can do the job without using this
buffer. */
static char *field_1_buffer;
/* The number of bytes allocated for FIELD_1_BUFFER. */
static size_t field_1_bufsize;
/* The largest field or byte index used as an endpoint of a closed
or degenerate range specification; this doesn't include the starting
index of right-open-ended ranges. For example, with either range spec
`2-5,9-', `2-3,5,9-' this variable would be set to 5. */
static unsigned int max_range_endpoint;
/* If nonzero, this is the index of the first field in a range that goes
to end of line. */
static unsigned int eol_range_start;
/* A nonzero, non-1 value with which to distinguish the index
corresponding to the lower bound of a range. */
#define RANGE_START_SENTINEL 2
/* In byte mode, which bytes to output.
In field mode, which DELIM-separated fields to output.
Both bytes and fields are numbered starting with 1,
so the zeroth element of this array is unused.
A field or byte K has been selected if
(K <= MAX_RANGE_ENDPOINT and PRINTABLE_FIELD[K])
|| (EOL_RANGE_START > 0 && K >= EOL_RANGE_START). */
static int *printable_field;
enum operating_mode
{
undefined_mode,
/* Output characters that are in the given bytes. */
byte_mode,
/* Output the given delimeter-separated fields. */
field_mode
};
/* The name this program was run with. */
char *program_name;
static enum operating_mode operating_mode;
/* If nonzero do not output lines containing no delimeter characters.
Otherwise, all such lines are printed. This option is valid only
with field mode. */
static int suppress_non_delimited;
/* The delimeter character for field mode. */
static int delim;
/* Nonzero if the --output-delimiter=STRING option was specified. */
static int output_delimiter_specified;
/* The length of output_delimiter_string. */
static size_t output_delimiter_length;
/* The output field separator string. Defaults to the 1-character
string consisting of the input delimiter. */
static char *output_delimiter_string;
/* Nonzero if we have ever read standard input. */
static int have_read_stdin;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1
};
static struct option const longopts[] =
{
{"bytes", required_argument, 0, 'b'},
{"characters", required_argument, 0, 'c'},
{"fields", required_argument, 0, 'f'},
{"delimiter", required_argument, 0, 'd'},
{"only-delimited", no_argument, 0, 's'},
{"output-delimiter", required_argument, 0, OUTPUT_DELIMITER_OPTION},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Print selected parts of lines from each FILE to standard output.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-b, --bytes=LIST output only these bytes\n\
-c, --characters=LIST output only these characters\n\
-d, --delimiter=DELIM use DELIM instead of TAB for field delimiter\n\
"), stdout);
fputs (_("\
-f, --fields=LIST output only these fields; also print any line\n\
that contains no delimiter character, unless\n\
the -s option is specified\n\
-n (ignored)\n\
"), stdout);
fputs (_("\
-s, --only-delimited do not print lines not containing delimiters\n\
--output-delimiter=STRING use STRING as the output delimiter\n\
the default is to use the input delimiter\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Use one, and only one of -b, -c or -f. Each LIST is made up of one\n\
range, or many ranges separated by commas. Each range is one of:\n\
\n\
N N'th byte, character or field, counted from 1\n\
N- from N'th byte, character or field, to end of line\n\
N-M from N'th to M'th (included) byte, character or field\n\
-M from first to M'th (included) byte, character or field\n\
\n\
With no FILE, or when FILE is -, read standard input.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Return nonzero if the K'th field or byte is printable.
When returning nonzero, if RANGE_START is non-NULL,
set *RANGE_START to nonzero if K is the beginning of a range, and
set *RANGE_START to zero if K is not the beginning of a range. */
static int
print_kth (unsigned int k, int *range_start)
{
if (0 < eol_range_start && eol_range_start <= k)
{
if (range_start)
*range_start = (k == eol_range_start);
return 1;
}
if (k <= max_range_endpoint && printable_field[k])
{
if (range_start)
*range_start = (printable_field[k] == RANGE_START_SENTINEL);
return 1;
}
return 0;
}
/* Given the list of field or byte range specifications FIELDSTR, set
MAX_RANGE_ENDPOINT and allocate and initialize the PRINTABLE_FIELD
array. If there is a right-open-ended range, set EOL_RANGE_START
to its starting index. FIELDSTR should be composed of one or more
numbers or ranges of numbers, separated by blanks or commas.
Incomplete ranges may be given: `-m' means `1-m'; `n-' means `n'
through end of line. Return nonzero if FIELDSTR contains at least
one field specification, zero otherwise. */
/* FIXME-someday: What if the user wants to cut out the 1,000,000-th field
of some huge input file? This function shouldn't have to allocate a table
of a million ints just so we can test every field < 10^6 with an array
dereference. Instead, consider using a dynamic hash table. It would be
simpler and nearly as good a solution to use a 32K x 4-byte table with
one bit per field index instead of a whole `int' per index. */
static int
set_fields (const char *fieldstr)
{
unsigned int initial = 1; /* Value of first number in a range. */
unsigned int value = 0; /* If nonzero, a number being accumulated. */
int dash_found = 0; /* Nonzero if a '-' is found in this field. */
int field_found = 0; /* Non-zero if at least one field spec
has been processed. */
struct range_pair *rp;
unsigned int n_rp;
unsigned int n_rp_allocated;
unsigned int i;
n_rp = 0;
n_rp_allocated = 16;
rp = (struct range_pair *) xmalloc (n_rp_allocated * sizeof (*rp));
/* Collect and store in RP the range end points.
It also sets EOL_RANGE_START if appropriate. */
for (;;)
{
if (*fieldstr == '-')
{
/* Starting a range. */
if (dash_found)
FATAL_ERROR (_("invalid byte or field list"));
dash_found++;
fieldstr++;
if (value)
{
initial = value;
value = 0;
}
else
initial = 1;
}
else if (*fieldstr == ',' || ISBLANK (*fieldstr) || *fieldstr == '\0')
{
/* Ending the string, or this field/byte sublist. */
if (dash_found)
{
dash_found = 0;
/* A range. Possibilites: -n, m-n, n-.
In any case, `initial' contains the start of the range. */
if (value == 0)
{
/* `n-'. From `initial' to end of line. */
eol_range_start = initial;
field_found = 1;
}
else
{
/* `m-n' or `-n' (1-n). */
if (value < initial)
FATAL_ERROR (_("invalid byte or field list"));
/* Is there already a range going to end of line? */
if (eol_range_start != 0)
{
/* Yes. Is the new sequence already contained
in the old one? If so, no processing is
necessary. */
if (initial < eol_range_start)
{
/* No, the new sequence starts before the
old. Does the old range going to end of line
extend into the new range? */
if (eol_range_start <= value)
{
/* Yes. Simply move the end of line marker. */
eol_range_start = initial;
}
else
{
/* No. A simple range, before and disjoint from
the range going to end of line. Fill it. */
ADD_RANGE_PAIR (rp, initial, value);
}
/* In any case, some fields were selected. */
field_found = 1;
}
}
else
{
/* There is no range going to end of line. */
ADD_RANGE_PAIR (rp, initial, value);
field_found = 1;
}
value = 0;
}
}
else if (value != 0)
{
/* A simple field number, not a range. */
ADD_RANGE_PAIR (rp, value, value);
value = 0;
field_found = 1;
}
if (*fieldstr == '\0')
{
break;
}
fieldstr++;
}
else if (ISDIGIT (*fieldstr))
{
/* FIXME: detect overflow? */
value = 10 * value + *fieldstr - '0';
fieldstr++;
}
else
FATAL_ERROR (_("invalid byte or field list"));
}
max_range_endpoint = 0;
for (i = 0; i < n_rp; i++)
{
if (rp[i].hi > max_range_endpoint)
max_range_endpoint = rp[i].hi;
}
/* Allocate an array large enough so that it may be indexed by
the field numbers corresponding to all finite ranges
(i.e. `2-6' or `-4', but not `5-') in FIELDSTR. */
printable_field = (int *) xmalloc ((max_range_endpoint + 1) * sizeof (int));
memset (printable_field, 0, (max_range_endpoint + 1) * sizeof (int));
/* Set the array entries corresponding to integers in the ranges of RP. */
for (i = 0; i < n_rp; i++)
{
unsigned int j = rp[i].lo;
/* Mark the first position of field or range with a sentinel,
but not if it's already part of another range. */
if (j <= rp[i].hi && ! printable_field[j])
printable_field[j] = RANGE_START_SENTINEL;
for (++j; j <= rp[i].hi; j++)
{
printable_field[j] = 1;
}
}
free (rp);
return field_found;
}
/* Read from stream STREAM, printing to standard output any selected bytes. */
static void
cut_bytes (FILE *stream)
{
unsigned int byte_idx; /* Number of bytes in the line so far. */
/* Whether to begin printing delimiters between ranges for the current line.
Set after we've begun printing data corresponding to the first range. */
int print_delimiter;
byte_idx = 0;
print_delimiter = 0;
while (1)
{
register int c; /* Each character from the file. */
c = getc (stream);
if (c == '\n')
{
putchar ('\n');
byte_idx = 0;
print_delimiter = 0;
}
else if (c == EOF)
{
if (byte_idx > 0)
putchar ('\n');
break;
}
else
{
int range_start;
if (print_kth (++byte_idx, &range_start))
{
if (range_start && print_delimiter && output_delimiter_specified)
{
fwrite (output_delimiter_string, sizeof (char),
output_delimiter_length, stdout);
}
print_delimiter = 1;
putchar (c);
}
}
}
}
/* Read from stream STREAM, printing to standard output any selected fields. */
static void
cut_fields (FILE *stream)
{
int c;
unsigned int field_idx;
int found_any_selected_field;
int buffer_first_field;
int empty_input;
found_any_selected_field = 0;
field_idx = 1;
c = getc (stream);
empty_input = (c == EOF);
if (c != EOF)
ungetc (c, stream);
/* To support the semantics of the -s flag, we may have to buffer
all of the first field to determine whether it is `delimited.'
But that is unnecessary if all non-delimited lines must be printed
and the first field has been selected, or if non-delimited lines
must be suppressed and the first field has *not* been selected.
That is because a non-delimited line has exactly one field. */
buffer_first_field = (suppress_non_delimited ^ !print_kth (1, NULL));
while (1)
{
if (field_idx == 1 && buffer_first_field)
{
int len;
size_t n_bytes;
len = getstr (&field_1_buffer, &field_1_bufsize, stream,
delim, '\n', 0);
if (len < 0)
{
if (ferror (stream) || feof (stream))
break;
xalloc_die ();
}
n_bytes = len;
assert (n_bytes != 0);
/* If the first field extends to the end of line (it is not
delimited) and we are printing all non-delimited lines,
print this one. */
if ((unsigned char) field_1_buffer[n_bytes - 1] != delim)
{
if (suppress_non_delimited)
{
/* Empty. */
}
else
{
fwrite (field_1_buffer, sizeof (char), n_bytes, stdout);
/* Make sure the output line is newline terminated. */
if (field_1_buffer[n_bytes - 1] != '\n')
putchar ('\n');
}
continue;
}
if (print_kth (1, NULL))
{
/* Print the field, but not the trailing delimiter. */
fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout);
found_any_selected_field = 1;
}
++field_idx;
}
if (c != EOF)
{
if (print_kth (field_idx, NULL))
{
if (found_any_selected_field)
{
fwrite (output_delimiter_string, sizeof (char),
output_delimiter_length, stdout);
}
found_any_selected_field = 1;
while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
{
putchar (c);
}
}
else
{
while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
{
/* Empty. */
}
}
}
if (c == '\n')
{
c = getc (stream);
if (c != EOF)
{
ungetc (c, stream);
c = '\n';
}
}
if (c == delim)
++field_idx;
else if (c == '\n' || c == EOF)
{
if (found_any_selected_field
|| (!empty_input && !(suppress_non_delimited && field_idx == 1)))
putchar ('\n');
if (c == EOF)
break;
field_idx = 1;
found_any_selected_field = 0;
}
}
}
static void
cut_stream (FILE *stream)
{
if (operating_mode == byte_mode)
cut_bytes (stream);
else
cut_fields (stream);
}
/* Process file FILE to standard output.
Return 0 if successful, 1 if not. */
static int
cut_file (char *file)
{
FILE *stream;
if (STREQ (file, "-"))
{
have_read_stdin = 1;
stream = stdin;
}
else
{
stream = fopen (file, "r");
if (stream == NULL)
{
error (0, errno, "%s", file);
return 1;
}
}
cut_stream (stream);
if (ferror (stream))
{
error (0, errno, "%s", file);
return 1;
}
if (STREQ (file, "-"))
clearerr (stream); /* Also clear EOF. */
else if (fclose (stream) == EOF)
{
error (0, errno, "%s", file);
return 1;
}
return 0;
}
int
main (int argc, char **argv)
{
int optc, exit_status = 0;
int delim_specified = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
operating_mode = undefined_mode;
/* By default, all non-delimited lines are printed. */
suppress_non_delimited = 0;
delim = '\0';
have_read_stdin = 0;
while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'b':
case 'c':
/* Build the byte list. */
if (operating_mode != undefined_mode)
FATAL_ERROR (_("only one type of list may be specified"));
operating_mode = byte_mode;
if (set_fields (optarg) == 0)
FATAL_ERROR (_("missing list of positions"));
break;
case 'f':
/* Build the field list. */
if (operating_mode != undefined_mode)
FATAL_ERROR (_("only one type of list may be specified"));
operating_mode = field_mode;
if (set_fields (optarg) == 0)
FATAL_ERROR (_("missing list of fields"));
break;
case 'd':
/* New delimiter. */
/* Interpret -d '' to mean `use the NUL byte as the delimiter.' */
if (optarg[0] != '\0' && optarg[1] != '\0')
FATAL_ERROR (_("the delimiter must be a single character"));
delim = (unsigned char) optarg[0];
delim_specified = 1;
break;
case OUTPUT_DELIMITER_OPTION:
output_delimiter_specified = 1;
/* Interpret --output-delimiter='' to mean
`use the NUL byte as the delimiter.' */
output_delimiter_length = (optarg[0] == '\0'
? 1 : strlen (optarg));
output_delimiter_string = xstrdup (optarg);
break;
case 'n':
break;
case 's':
suppress_non_delimited = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (2);
}
}
if (operating_mode == undefined_mode)
FATAL_ERROR (_("you must specify a list of bytes, characters, or fields"));
if (delim != '\0' && operating_mode != field_mode)
FATAL_ERROR (_("an input delimiter may be specified only\
when operating on fields"));
if (suppress_non_delimited && operating_mode != field_mode)
FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\
\tonly when operating on fields"));
if (!delim_specified)
delim = '\t';
if (output_delimiter_string == NULL)
{
static char dummy[2];
dummy[0] = delim;
dummy[1] = '\0';
output_delimiter_string = dummy;
output_delimiter_length = 1;
}
if (optind == argc)
exit_status |= cut_file ("-");
else
for (; optind < argc; optind++)
exit_status |= cut_file (argv[optind]);
if (have_read_stdin && fclose (stdin) == EOF)
{
error (0, errno, "-");
exit_status = 1;
}
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+552
View File
@@ -0,0 +1,552 @@
/* date - print or set the system date and time
Copyright (C) 1989-2002 Free Software Foundation, Inc.
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, 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.
David MacKenzie <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#if HAVE_LANGINFO_CODESET
# include <langinfo.h>
#endif
#include "system.h"
#include "argmatch.h"
#include "closeout.h"
#include "error.h"
#include "getdate.h"
#include "getline.h"
#include "posixtm.h"
#include "posixver.h"
#include "strftime.h"
#include "timespec.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "date"
#define AUTHORS "David MacKenzie"
int putenv ();
static void show_date (const char *format, struct timespec when);
enum Time_spec
{
/* display only the date: 1999-03-25 */
TIME_SPEC_DATE=1,
/* display date and hour: 1999-03-25T03-0500 */
TIME_SPEC_HOURS,
/* display date, hours, and minutes: 1999-03-25T03:23-0500 */
TIME_SPEC_MINUTES,
/* display date, hours, minutes, and seconds: 1999-03-25T03:23:14-0500 */
TIME_SPEC_SECONDS
};
static char const *const time_spec_string[] =
{
"date", "hours", "minutes", "seconds", 0
};
static enum Time_spec const time_spec[] =
{
TIME_SPEC_DATE, TIME_SPEC_HOURS, TIME_SPEC_MINUTES, TIME_SPEC_SECONDS
};
/* The name this program was run with, for error messages. */
char *program_name;
/* If nonzero, display an ISO 8601 format date/time string */
static int iso_8601_format = 0;
/* If non-zero, display time in RFC-(2)822 format for mail or news. */
static int rfc_format = 0;
#define COMMON_SHORT_OPTIONS "Rd:f:r:s:u"
static struct option const long_options[] =
{
{"date", required_argument, NULL, 'd'},
{"file", required_argument, NULL, 'f'},
{"iso-8601", optional_argument, NULL, 'I'},
{"reference", required_argument, NULL, 'r'},
{"rfc-822", no_argument, NULL, 'R'},
{"set", required_argument, NULL, 's'},
{"uct", no_argument, NULL, 'u'},
{"utc", no_argument, NULL, 'u'},
{"universal", no_argument, NULL, 'u'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
#if LOCALTIME_CACHE
# define TZSET tzset ()
#else
# define TZSET /* empty */
#endif
#ifdef _DATE_FMT
# define DATE_FMT_LANGINFO() nl_langinfo (_DATE_FMT)
#else
# define DATE_FMT_LANGINFO() ""
#endif
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [+FORMAT]\n\
or: %s [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]\n\
"),
program_name, program_name);
fputs (_("\
Display the current time in the given FORMAT, or set the system date.\n\
\n\
-d, --date=STRING display time described by STRING, not `now'\n\
-f, --file=DATEFILE like --date once for each line of DATEFILE\n\
-ITIMESPEC, --iso-8601[=TIMESPEC] output date/time in ISO 8601 format.\n\
TIMESPEC=`date' for date only,\n\
`hours', `minutes', or `seconds' for date and\n\
time to the indicated precision.\n\
--iso-8601 without TIMESPEC defaults to `date'.\n\
"), stdout);
fputs (_("\
-r, --reference=FILE display the last modification time of FILE\n\
-R, --rfc-822 output RFC-822 compliant date string\n\
-s, --set=STRING set time described by STRING\n\
-u, --utc, --universal print or set Coordinated Universal Time\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
FORMAT controls the output. The only valid option for the second form\n\
specifies Coordinated Universal Time. Interpreted sequences are:\n\
\n\
%% a literal %\n\
%a locale's abbreviated weekday name (Sun..Sat)\n\
"), stdout);
fputs (_("\
%A locale's full weekday name, variable length (Sunday..Saturday)\n\
%b locale's abbreviated month name (Jan..Dec)\n\
%B locale's full month name, variable length (January..December)\n\
%c locale's date and time (Sat Nov 04 12:02:33 EST 1989)\n\
"), stdout);
fputs (_("\
%C century (year divided by 100 and truncated to an integer) [00-99]\n\
%d day of month (01..31)\n\
%D date (mm/dd/yy)\n\
%e day of month, blank padded ( 1..31)\n\
"), stdout);
fputs (_("\
%F same as %Y-%m-%d\n\
%g the 2-digit year corresponding to the %V week number\n\
%G the 4-digit year corresponding to the %V week number\n\
"), stdout);
fputs (_("\
%h same as %b\n\
%H hour (00..23)\n\
%I hour (01..12)\n\
%j day of year (001..366)\n\
"), stdout);
fputs (_("\
%k hour ( 0..23)\n\
%l hour ( 1..12)\n\
%m month (01..12)\n\
%M minute (00..59)\n\
"), stdout);
fputs (_("\
%n a newline\n\
%N nanoseconds (000000000..999999999)\n\
%p locale's upper case AM or PM indicator (blank in many locales)\n\
%P locale's lower case am or pm indicator (blank in many locales)\n\
%r time, 12-hour (hh:mm:ss [AP]M)\n\
%R time, 24-hour (hh:mm)\n\
%s seconds since `00:00:00 1970-01-01 UTC' (a GNU extension)\n\
"), stdout);
fputs (_("\
%S second (00..60); the 60 is necessary to accommodate a leap second\n\
%t a horizontal tab\n\
%T time, 24-hour (hh:mm:ss)\n\
%u day of week (1..7); 1 represents Monday\n\
"), stdout);
fputs (_("\
%U week number of year with Sunday as first day of week (00..53)\n\
%V week number of year with Monday as first day of week (01..53)\n\
%w day of week (0..6); 0 represents Sunday\n\
%W week number of year with Monday as first day of week (00..53)\n\
"), stdout);
fputs (_("\
%x locale's date representation (mm/dd/yy)\n\
%X locale's time representation (%H:%M:%S)\n\
%y last two digits of year (00..99)\n\
%Y year (1970...)\n\
"), stdout);
fputs (_("\
%z RFC-822 style numeric timezone (-0500) (a nonstandard extension)\n\
%Z time zone (e.g., EDT), or nothing if no time zone is determinable\n\
\n\
By default, date pads numeric fields with zeroes. GNU date recognizes\n\
the following modifiers between `%' and a numeric directive.\n\
\n\
`-' (hyphen) do not pad the field\n\
`_' (underscore) pad the field with spaces\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Parse each line in INPUT_FILENAME as with --date and display each
resulting time and date. If the file cannot be opened, tell why
then exit. Issue a diagnostic for any lines that cannot be parsed.
If any line cannot be parsed, return nonzero; otherwise return zero. */
static int
batch_convert (const char *input_filename, const char *format)
{
int status;
FILE *in_stream;
char *line;
int line_length;
size_t buflen;
struct timespec when;
if (strcmp (input_filename, "-") == 0)
{
input_filename = _("standard input");
in_stream = stdin;
}
else
{
in_stream = fopen (input_filename, "r");
if (in_stream == NULL)
{
error (EXIT_FAILURE, errno, "`%s'", input_filename);
}
}
line = NULL;
buflen = 0;
status = 0;
while (1)
{
line_length = getline (&line, &buflen, in_stream);
if (line_length < 0)
{
/* FIXME: detect/handle error here. */
break;
}
when.tv_sec = get_date (line, NULL);
when.tv_nsec = 0; /* FIXME: get_date should set this. */
if (when.tv_sec == -1)
{
if (line[line_length - 1] == '\n')
line[line_length - 1] = '\0';
error (0, 0, _("invalid date `%s'"), line);
status = 1;
}
else
{
show_date (format, when);
}
}
if (fclose (in_stream) == EOF)
error (2, errno, "`%s'", input_filename);
if (line != NULL)
free (line);
return status;
}
int
main (int argc, char **argv)
{
int optc;
const char *datestr = NULL;
const char *set_datestr = NULL;
struct timespec when;
int set_date = 0;
char *format;
char *batch_file = NULL;
char *reference = NULL;
struct stat refstats;
int n_args;
int status;
int option_specified_date;
char const *short_options = (posix2_version () < 200112
? COMMON_SHORT_OPTIONS "I::"
: COMMON_SHORT_OPTIONS "I:");
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
close_stdout_set_status (2);
atexit (close_stdout);
while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
!= -1)
switch (optc)
{
case 0:
break;
case 'd':
datestr = optarg;
break;
case 'f':
batch_file = optarg;
break;
case 'I':
iso_8601_format = (optarg
? XARGMATCH ("--iso-8601", optarg,
time_spec_string, time_spec)
: TIME_SPEC_DATE);
break;
case 'r':
reference = optarg;
break;
case 'R':
rfc_format = 1;
break;
case 's':
set_datestr = optarg;
set_date = 1;
break;
case 'u':
/* POSIX says that `date -u' is equivalent to setting the TZ
environment variable, so this option should do nothing other
than setting TZ. */
if (putenv ("TZ=UTC0") != 0)
xalloc_die ();
TZSET;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
n_args = argc - optind;
option_specified_date = ((datestr ? 1 : 0)
+ (batch_file ? 1 : 0)
+ (reference ? 1 : 0));
if (option_specified_date > 1)
{
error (0, 0,
_("the options to specify dates for printing are mutually exclusive"));
usage (EXIT_FAILURE);
}
if (set_date && option_specified_date)
{
error (0, 0,
_("the options to print and set the time may not be used together"));
usage (EXIT_FAILURE);
}
if (n_args > 1)
{
error (0, 0, _("too many non-option arguments: %s%s"),
argv[optind + 1], n_args == 2 ? "" : " ...");
usage (EXIT_FAILURE);
}
if ((set_date || option_specified_date)
&& n_args == 1 && argv[optind][0] != '+')
{
error (0, 0, _("\
the argument `%s' lacks a leading `+';\n\
When using an option to specify date(s), any non-option\n\
argument must be a format string beginning with `+'."),
argv[optind]);
usage (EXIT_FAILURE);
}
/* Simply ignore --rfc-822 if specified when setting the date. */
if (rfc_format && !set_date && n_args > 0)
{
error (0, 0,
_("a format string may not be specified when using\
the --rfc-822 (-R) option"));
usage (EXIT_FAILURE);
}
if (set_date)
datestr = set_datestr;
if (batch_file != NULL)
{
status = batch_convert (batch_file,
(n_args == 1 ? argv[optind] + 1 : NULL));
}
else
{
bool valid_date = true;
status = 0;
if (!option_specified_date && !set_date)
{
if (n_args == 1 && argv[optind][0] != '+')
{
/* Prepare to set system clock to the specified date/time
given in the POSIX-format. */
set_date = 1;
datestr = argv[optind];
valid_date = posixtime (&when.tv_sec,
datestr,
(PDS_TRAILING_YEAR
| PDS_CENTURY | PDS_SECONDS));
when.tv_nsec = 0; /* FIXME: posixtime should set this. */
format = NULL;
}
else
{
/* Prepare to print the current date/time. */
datestr = _("undefined");
if (gettime (&when) != 0)
error (EXIT_FAILURE, errno, _("cannot get time of day"));
format = (n_args == 1 ? argv[optind] + 1 : NULL);
}
}
else
{
/* (option_specified_date || set_date) */
if (reference != NULL)
{
if (stat (reference, &refstats))
error (EXIT_FAILURE, errno, "%s", reference);
when.tv_sec = refstats.st_mtime;
when.tv_nsec = TIMESPEC_NS (refstats.st_mtim);
}
else
{
when.tv_sec = get_date (datestr, NULL);
when.tv_nsec = 0; /* FIXME: get_date should set this. */
valid_date = (when.tv_sec != (time_t) -1);
}
format = (n_args == 1 ? argv[optind] + 1 : NULL);
}
if (! valid_date)
error (EXIT_FAILURE, 0, _("invalid date `%s'"), datestr);
if (set_date)
{
/* Set the system clock to the specified date, then regardless of
the success of that operation, format and print that date. */
if (settime (&when) != 0)
{
error (0, errno, _("cannot set date"));
status = 1;
}
}
show_date (format, when);
}
exit (status);
}
/* Display the date and/or time in WHEN according to the format specified
in FORMAT, followed by a newline. If FORMAT is NULL, use the
standard output format (ctime style but with a timezone inserted). */
static void
show_date (const char *format, struct timespec when)
{
struct tm *tm;
char *out = NULL;
size_t out_length = 0;
/* ISO 8601 formats. See below regarding %z */
static char const * const iso_format_string[] =
{
"%Y-%m-%d",
"%Y-%m-%dT%H%z",
"%Y-%m-%dT%H:%M%z",
"%Y-%m-%dT%H:%M:%S%z"
};
tm = localtime (&when.tv_sec);
if (format == NULL)
{
if (rfc_format)
format = "%a, %d %b %Y %H:%M:%S %z";
else if (iso_8601_format)
format = iso_format_string[iso_8601_format - 1];
else
{
char *date_fmt = DATE_FMT_LANGINFO ();
/* Do not wrap the following literal format string with _(...).
For example, suppose LC_ALL is unset, LC_TIME="POSIX",
and LANG="ko_KR". In that case, POSIX says that LC_TIME
determines the format and contents of date and time strings
written by date, which means "date" must generate output
using the POSIX locale; but adding _() would cause "date"
to use a Korean translation of the format. */
format = *date_fmt ? date_fmt : "%a %b %e %H:%M:%S %Z %Y";
}
}
else if (*format == '\0')
{
printf ("\n");
return;
}
while (1)
{
int done;
out_length += 200;
out = (char *) xrealloc (out, out_length);
/* Mark the first byte of the buffer so we can detect the case
of nstrftime producing an empty string. Otherwise, this loop
would not terminate when date was invoked like this
`LANG=de date +%p' on a system with good language support. */
out[0] = '\1';
if (rfc_format)
setlocale (LC_ALL, "C");
done = (nstrftime (out, out_length, format, tm, 0, when.tv_nsec)
|| out[0] == '\0');
if (rfc_format)
setlocale (LC_ALL, "");
if (done)
break;
}
printf ("%s\n", out);
free (out);
}
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/perl -w
# -*- perl -*-
eval 'exec /p/bin/perl -S $0 ${1+"$@"}'
if 0;
# dcgen -- generate C declarations of arrays of lines and line lengths
# Copyright (C) 1996, 1998 Free Software Foundation, Inc.
# 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, 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.
# written by Jim Meyering
# If you uncomment the following lines, you should also do
# s/chop/chomp and s/local/my/.
#require 5.002;
#use strict;
# Convert an arbitrary file to dcl of two arrays.
# One of lines, the other of lengths.
local $prefix = 'G_';
local @line;
while (<>)
{
chop;
push (@line, $_);
}
local $n = @line;
print "#define ${prefix}N_LINES $n\n\n";
local $indent = ' ';
print "const size_t ${prefix}line_length[${prefix}N_LINES] =\n{\n$indent";
local $ind = $indent;
local $i;
for ($i = 0; $i < @line; $i++)
{
local $comma = ($i < @line - 1 ? ',' : '');
$ind = '' if $i == @line - 1;
local $sep = ($i && $i % 18 == 0 || $i == @line - 1 ? "\n$ind" : ' ');
print length ($line[$i]), $comma, $sep;
}
print "};\n\n";
print "const char *const ${prefix}line[${prefix}N_LINES] =\n{\n";
while (1)
{
$_ = shift (@line);
local $comma = (@line ? ',' : '');
print "$indent\"$_\"$comma\n";
last if !@line;
}
print "};\n";
exit (0);
File diff suppressed because it is too large Load Diff
+933
View File
@@ -0,0 +1,933 @@
/* df - summarize free disk space
Copyright (C) 91, 1995-2003 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie <[email protected]>.
--human-readable and --megabyte options added by [email protected].
--si and large file support added by [email protected]. */
#ifdef _AIX
#pragma alloca
#endif
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include <assert.h>
#include "system.h"
#include "canonicalize.h"
#include "dirname.h"
#include "error.h"
#include "fsusage.h"
#include "human.h"
#include "inttostr.h"
#include "mountlist.h"
#include "path-concat.h"
#include "quote.h"
#include "save-cwd.h"
#include "xgetcwd.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "df"
#define AUTHORS \
N_ ("Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert")
/* Name this program was run with. */
char *program_name;
/* If nonzero, show inode information. */
static int inode_format;
/* If nonzero, show even filesystems with zero size or
uninteresting types. */
static int show_all_fs;
/* If nonzero, show only local filesystems. */
static int show_local_fs;
/* If nonzero, output data for each filesystem corresponding to a
command line argument -- even if it's a dummy (automounter) entry. */
static int show_listed_fs;
/* Human-readable options for output. */
static int human_output_opts;
/* The units to use when printing sizes. */
static uintmax_t output_block_size;
/* If nonzero, use the POSIX output format. */
static int posix_format;
/* If nonzero, invoke the `sync' system call before getting any usage data.
Using this option can make df very slow, especially with many or very
busy disks. Note that this may make a difference on some systems --
SunOs4.1.3, for one. It is *not* necessary on Linux. */
static int require_sync = 0;
/* Nonzero if errors have occurred. */
static int exit_status;
/* A filesystem type to display. */
struct fs_type_list
{
char *fs_name;
struct fs_type_list *fs_next;
};
/* Linked list of filesystem types to display.
If `fs_select_list' is NULL, list all types.
This table is generated dynamically from command-line options,
rather than hardcoding into the program what it thinks are the
valid filesystem types; let the user specify any filesystem type
they want to, and if there are any filesystems of that type, they
will be shown.
Some filesystem types:
4.2 4.3 ufs nfs swap ignore io vm efs dbg */
static struct fs_type_list *fs_select_list;
/* Linked list of filesystem types to omit.
If the list is empty, don't exclude any types. */
static struct fs_type_list *fs_exclude_list;
/* Linked list of mounted filesystems. */
static struct mount_entry *mount_list;
/* If nonzero, print filesystem type as well. */
static int print_type;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
SYNC_OPTION = CHAR_MAX + 1,
NO_SYNC_OPTION
};
static struct option const long_options[] =
{
{"all", no_argument, NULL, 'a'},
{"block-size", required_argument, NULL, 'B'},
{"inodes", no_argument, NULL, 'i'},
{"human-readable", no_argument, NULL, 'h'},
{"si", no_argument, NULL, 'H'},
{"kilobytes", no_argument, NULL, 'k'}, /* long form is obsolescent */
{"local", no_argument, NULL, 'l'},
{"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
{"portability", no_argument, NULL, 'P'},
{"print-type", no_argument, NULL, 'T'},
{"sync", no_argument, NULL, SYNC_OPTION},
{"no-sync", no_argument, NULL, NO_SYNC_OPTION},
{"type", required_argument, NULL, 't'},
{"exclude-type", required_argument, NULL, 'x'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
static void
print_header (void)
{
char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))];
if (print_type)
fputs (_("Filesystem Type"), stdout);
else
fputs (_("Filesystem "), stdout);
if (inode_format)
printf (_(" Inodes IUsed IFree IUse%%"));
else if (human_output_opts & human_autoscale)
{
if (human_output_opts & human_base_1024)
printf (_(" Size Used Avail Use%%"));
else
printf (_(" Size Used Avail Use%%"));
}
else if (posix_format)
printf (_(" %4s-blocks Used Available Capacity"),
umaxtostr (output_block_size, buf));
else
{
int opts = (human_suppress_point_zero
| human_autoscale | human_SI
| (human_output_opts
& (human_group_digits | human_base_1024 | human_B)));
/* Prefer the base that makes the human-readable value more exact,
if there is a difference. */
uintmax_t q1000 = output_block_size;
uintmax_t q1024 = output_block_size;
bool divisible_by_1000;
bool divisible_by_1024;
do
{
divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
}
while (divisible_by_1000 & divisible_by_1024);
if (divisible_by_1000 < divisible_by_1024)
opts |= human_base_1024;
if (divisible_by_1024 < divisible_by_1000)
opts &= ~human_base_1024;
if (! (opts & human_base_1024))
opts |= human_B;
printf (_(" %4s-blocks Used Available Use%%"),
human_readable (output_block_size, buf, opts, 1, 1));
}
printf (_(" Mounted on\n"));
}
/* If FSTYPE is a type of filesystem that should be listed,
return nonzero, else zero. */
static int
selected_fstype (const char *fstype)
{
const struct fs_type_list *fsp;
if (fs_select_list == NULL || fstype == NULL)
return 1;
for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
if (STREQ (fstype, fsp->fs_name))
return 1;
return 0;
}
/* If FSTYPE is a type of filesystem that should be omitted,
return nonzero, else zero. */
static int
excluded_fstype (const char *fstype)
{
const struct fs_type_list *fsp;
if (fs_exclude_list == NULL || fstype == NULL)
return 0;
for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
if (STREQ (fstype, fsp->fs_name))
return 1;
return 0;
}
/* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
except:
- Return "-" if N is -1,
- If NEGATIVE is 1 then N represents a negative number,
expressed in two's complement. */
static char const *
df_readable (int negative, uintmax_t n, char *buf,
uintmax_t input_units, uintmax_t output_units)
{
if (n == -1)
return "-";
else
{
char *p = human_readable (negative ? -n : n, buf + negative,
human_output_opts, input_units, output_units);
if (negative)
*--p = '-';
return p;
}
}
/* Display a space listing for the disk device with absolute path DISK.
If MOUNT_POINT is non-NULL, it is the path of the root of the
filesystem on DISK.
If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
not be able to produce statistics in this case.
ME_DUMMY and ME_REMOTE are the mount entry flags. */
static void
show_dev (const char *disk, const char *mount_point, const char *fstype,
int me_dummy, int me_remote)
{
struct fs_usage fsu;
const char *stat_file;
char buf[3][LONGEST_HUMAN_READABLE + 2];
int width;
int use_width;
uintmax_t input_units;
uintmax_t output_units;
uintmax_t total;
uintmax_t available;
int negate_available;
uintmax_t available_to_root;
uintmax_t used;
int negate_used;
double pct = -1;
if (me_remote && show_local_fs)
return;
if (me_dummy && show_all_fs == 0 && !show_listed_fs)
return;
if (!selected_fstype (fstype) || excluded_fstype (fstype))
return;
/* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
program reports on the filesystem that the special file is on.
It would be better to report on the unmounted filesystem,
but statfs doesn't do that on most systems. */
stat_file = mount_point ? mount_point : disk;
if (get_fs_usage (stat_file, disk, &fsu))
{
error (0, errno, "%s", quote (stat_file));
exit_status = 1;
return;
}
if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
return;
if (! disk)
disk = "-"; /* unknown */
if (! fstype)
fstype = "-"; /* unknown */
/* df.c reserved 5 positions for fstype,
but that does not suffice for type iso9660 */
if (print_type)
{
int disk_name_len = (int) strlen (disk);
int fstype_len = (int) strlen (fstype);
if (disk_name_len + fstype_len + 2 < 20)
printf ("%s%*s ", disk, 18 - disk_name_len, fstype);
else if (!posix_format)
printf ("%s\n%18s ", disk, fstype);
else
printf ("%s %s", disk, fstype);
}
else
{
if ((int) strlen (disk) > 20 && !posix_format)
printf ("%s\n%20s", disk, "");
else
printf ("%-20s", disk);
}
if (inode_format)
{
width = 7;
use_width = 5;
input_units = output_units = 1;
total = fsu.fsu_files;
available = fsu.fsu_ffree;
negate_available = 0;
available_to_root = available;
}
else
{
width = (human_output_opts & human_autoscale
? 5 + ! (human_output_opts & human_base_1024)
: 9);
use_width = ((posix_format
&& ! (human_output_opts & human_autoscale))
? 8 : 4);
input_units = fsu.fsu_blocksize;
output_units = output_block_size;
total = fsu.fsu_blocks;
available = fsu.fsu_bavail;
negate_available = fsu.fsu_bavail_top_bit_set;
available_to_root = fsu.fsu_bfree;
}
used = -1;
negate_used = 0;
if (total != -1 && available_to_root != -1)
{
used = total - available_to_root;
if (total < available_to_root)
{
negate_used = 1;
used = - used;
}
}
printf (" %*s %*s %*s ",
width, df_readable (0, total,
buf[0], input_units, output_units),
width, df_readable (negate_used, used,
buf[1], input_units, output_units),
width, df_readable (negate_available, available,
buf[2], input_units, output_units));
if (used == -1 || available == -1)
;
else if (!negate_used
&& used <= TYPE_MAXIMUM (uintmax_t) / 100
&& used + available != 0
&& (used + available < used) == negate_available)
{
uintmax_t u100 = used * 100;
uintmax_t nonroot_total = used + available;
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
}
else
{
/* The calculation cannot be done easily with integer
arithmetic. Fall back on floating point. This can suffer
from minor rounding errors, but doing it exactly requires
multiple precision arithmetic, and it's not worth the
aggravation. */
double u = negate_used ? - (double) - used : used;
double a = negate_available ? - (double) - available : available;
double nonroot_total = u + a;
if (nonroot_total)
{
double ipct;
pct = u * 100 / nonroot_total;
ipct = (long) pct;
/* Like `pct = ceil (dpct);', but avoid ceil so that
the math library needn't be linked. */
if (ipct - 1 < pct && pct <= ipct + 1)
pct = ipct + (ipct < pct);
}
}
if (0 <= pct)
printf ("%*.0f%%", use_width - 1, pct);
else
printf ("%*s", use_width, "- ");
if (mount_point)
{
#ifdef HIDE_AUTOMOUNT_PREFIX
/* Don't print the first directory name in MOUNT_POINT if it's an
artifact of an automounter. This is a bit too aggressive to be
the default. */
if (strncmp ("/auto/", mount_point, 6) == 0)
mount_point += 5;
else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
mount_point += 8;
#endif
printf (" %s", mount_point);
}
putchar ('\n');
}
/* Return the root mountpoint of the filesystem on which FILE exists, in
malloced storage. FILE_STAT should be the result of stating FILE. */
static char *
find_mount_point (const char *file, const struct stat *file_stat)
{
struct saved_cwd cwd;
struct stat last_stat;
char *mp = 0; /* The malloced mount point path. */
if (save_cwd (&cwd))
return NULL;
if (S_ISDIR (file_stat->st_mode))
/* FILE is a directory, so just chdir there directly. */
{
last_stat = *file_stat;
if (chdir (file) < 0)
return NULL;
}
else
/* FILE is some other kind of file, we need to use its directory. */
{
char *dir = dir_name (file);
int rv = chdir (dir);
free (dir);
if (rv < 0)
return NULL;
if (stat (".", &last_stat) < 0)
goto done;
}
/* Now walk up FILE's parents until we find another filesystem or /,
chdiring as we go. LAST_STAT holds stat information for the last place
we visited. */
for (;;)
{
struct stat st;
if (stat ("..", &st) < 0)
goto done;
if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino)
/* cwd is the mount point. */
break;
if (chdir ("..") < 0)
goto done;
last_stat = st;
}
/* Finally reached a mount point, see what it's called. */
mp = xgetcwd ();
done:
/* Restore the original cwd. */
{
int save_errno = errno;
if (restore_cwd (&cwd))
error (EXIT_FAILURE, errno,
_("failed to return to initial working directory"));
free_cwd (&cwd);
errno = save_errno;
}
return mp;
}
/* If DISK corresponds to a mount point, show its usage
and return nonzero. Otherwise, return zero.
STATP must be the result of `stat (DISK, STATP)'. */
static int
show_disk (const char *disk, const struct stat *statp)
{
struct mount_entry *me;
for (me = mount_list; me; me = me->me_next)
if (STREQ (disk, me->me_devname))
{
show_dev (me->me_devname, me->me_mountdir, me->me_type,
me->me_dummy, me->me_remote);
return 1;
}
return 0;
}
/* Figure out which device file or directory POINT is mounted on
and show its disk usage.
STATP must be the result of `stat (POINT, STATP)'. */
static void
show_point (const char *point, const struct stat *statp)
{
struct stat disk_stats;
struct mount_entry *me;
struct mount_entry *matching_dummy = NULL;
/* If POINT is an absolute path name, see if we can find the
mount point without performing any extra stat calls at all. */
if (*point == '/')
{
for (me = mount_list; me; me = me->me_next)
{
if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs"))
{
/* Prefer non-dummy entries. */
if (! me->me_dummy)
goto show_me;
matching_dummy = me;
}
}
if (matching_dummy)
goto show_matching_dummy;
}
/* Calculate the real absolute path for POINT, and use that to find
the mount point. This avoids statting unavailable mount points,
which can hang df. */
{
char *resolved = canonicalize_file_name (point);
ssize_t resolved_len = resolved ? strlen (resolved) : -1;
struct mount_entry *best_match = NULL;
if (1 <= resolved_len && resolved[0] == '/')
{
size_t best_match_len = 0;
for (me = mount_list; me; me = me->me_next)
if (! me->me_dummy)
{
size_t len = strlen (me->me_mountdir);
if (best_match_len < len && len <= resolved_len
&& (len == 1 /* root file system */
|| ((len == resolved_len || resolved[len] == '/')
&& strncmp (me->me_mountdir, resolved, len) == 0)))
{
best_match = me;
best_match_len = len;
}
}
}
if (resolved)
free (resolved);
if (best_match && !STREQ (best_match->me_type, "lofs")
&& stat (best_match->me_mountdir, &disk_stats) == 0
&& disk_stats.st_dev == statp->st_dev)
{
me = best_match;
goto show_me;
}
}
for (me = mount_list; me; me = me->me_next)
{
if (me->me_dev == (dev_t) -1)
{
if (stat (me->me_mountdir, &disk_stats) == 0)
me->me_dev = disk_stats.st_dev;
else
{
error (0, errno, "%s", quote (me->me_mountdir));
exit_status = 1;
/* So we won't try and fail repeatedly. */
me->me_dev = (dev_t) -2;
}
}
if (statp->st_dev == me->me_dev)
{
/* Skip bogus mtab entries. */
if (stat (me->me_mountdir, &disk_stats) != 0
|| disk_stats.st_dev != me->me_dev)
{
me->me_dev = (dev_t) -2;
continue;
}
/* Prefer non-dummy entries. */
if (! me->me_dummy)
goto show_me;
matching_dummy = me;
}
}
if (matching_dummy)
goto show_matching_dummy;
/* We couldn't find the mount entry corresponding to POINT. Go ahead and
print as much info as we can; methods that require the device to be
present will fail at a later point. */
{
/* Find the actual mount point. */
char *mp = find_mount_point (point, statp);
if (mp)
{
show_dev (0, mp, 0, 0, 0);
free (mp);
}
else
error (0, errno, "%s", quote (point));
}
return;
show_matching_dummy:
me = matching_dummy;
show_me:
show_dev (me->me_devname, me->me_mountdir, me->me_type, me->me_dummy,
me->me_remote);
}
/* Determine what kind of node PATH is and show the disk usage
for it. STATP is the results of `stat' on PATH. */
static void
show_entry (const char *path, const struct stat *statp)
{
if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
&& show_disk (path, statp))
return;
show_point (path, statp);
}
/* Show all mounted filesystems, except perhaps those that are of
an unselected type or are empty. */
static void
show_all_entries (void)
{
struct mount_entry *me;
for (me = mount_list; me; me = me->me_next)
show_dev (me->me_devname, me->me_mountdir, me->me_type,
me->me_dummy, me->me_remote);
}
/* Add FSTYPE to the list of filesystem types to display. */
static void
add_fs_type (const char *fstype)
{
struct fs_type_list *fsp;
fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
fsp->fs_name = (char *) fstype;
fsp->fs_next = fs_select_list;
fs_select_list = fsp;
}
/* Add FSTYPE to the list of filesystem types to be omitted. */
static void
add_excluded_fs_type (const char *fstype)
{
struct fs_type_list *fsp;
fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
fsp->fs_name = (char *) fstype;
fsp->fs_next = fs_exclude_list;
fs_exclude_list = fsp;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
fputs (_("\
Show information about the filesystem on which each FILE resides,\n\
or all filesystems by default.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-a, --all include filesystems having 0 blocks\n\
-B, --block-size=SIZE use SIZE-byte blocks\n\
-h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
-H, --si likewise, but use powers of 1000 not 1024\n\
"), stdout);
fputs (_("\
-i, --inodes list inode information instead of block usage\n\
-k like --block-size=1K\n\
-l, --local limit listing to local filesystems\n\
--no-sync do not invoke sync before getting usage info (default)\n\
"), stdout);
fputs (_("\
-P, --portability use the POSIX output format\n\
--sync invoke sync before getting usage info\n\
-t, --type=TYPE limit listing to filesystems of type TYPE\n\
-T, --print-type print filesystem type\n\
-x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
-v (ignored)\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
SIZE may be (or may be an integer optionally followed by) one of following:\n\
kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int c;
struct stat *stats IF_LINT (= 0);
int n_valid_args = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
fs_select_list = NULL;
fs_exclude_list = NULL;
inode_format = 0;
show_all_fs = 0;
show_listed_fs = 0;
human_output_opts = human_options (getenv ("DF_BLOCK_SIZE"), false,
&output_block_size);
print_type = 0;
posix_format = 0;
exit_status = 0;
while ((c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options, NULL))
!= -1)
{
switch (c)
{
case 0: /* Long option. */
break;
case 'a':
show_all_fs = 1;
break;
case 'B':
human_output_opts = human_options (optarg, true, &output_block_size);
break;
case 'i':
inode_format = 1;
break;
case 'h':
human_output_opts = human_autoscale | human_SI | human_base_1024;
output_block_size = 1;
break;
case 'H':
human_output_opts = human_autoscale | human_SI;
output_block_size = 1;
break;
case 'k':
human_output_opts = 0;
output_block_size = 1024;
break;
case 'l':
show_local_fs = 1;
break;
case 'm': /* obsolescent */
human_output_opts = 0;
output_block_size = 1024 * 1024;
break;
case 'T':
print_type = 1;
break;
case 'P':
posix_format = 1;
break;
case SYNC_OPTION:
require_sync = 1;
break;
case NO_SYNC_OPTION:
require_sync = 0;
break;
case 'F':
/* Accept -F as a synonym for -t for compatibility with Solaris. */
case 't':
add_fs_type (optarg);
break;
case 'v': /* For SysV compatibility. */
/* ignore */
break;
case 'x':
add_excluded_fs_type (optarg);
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
/* Fail if the same file system type was both selected and excluded. */
{
int match = 0;
struct fs_type_list *fs_incl;
for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
{
struct fs_type_list *fs_excl;
for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
{
if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
{
error (0, 0,
_("file system type %s both selected and excluded"),
quote (fs_incl->fs_name));
match = 1;
break;
}
}
}
if (match)
exit (EXIT_FAILURE);
}
{
int i;
/* stat all the given entries to make sure they get automounted,
if necessary, before reading the filesystem table. */
stats = (struct stat *)
xmalloc ((argc - optind) * sizeof (struct stat));
for (i = optind; i < argc; ++i)
{
if (stat (argv[i], &stats[i - optind]))
{
error (0, errno, "%s", quote (argv[i]));
exit_status = 1;
argv[i] = NULL;
}
else
{
++n_valid_args;
}
}
}
mount_list =
read_filesystem_list ((fs_select_list != NULL
|| fs_exclude_list != NULL
|| print_type
|| show_local_fs));
if (mount_list == NULL)
{
/* Couldn't read the table of mounted filesystems.
Fail if df was invoked with no file name arguments;
Otherwise, merely give a warning and proceed. */
const char *warning = (optind == argc ? "" : _("Warning: "));
int status = (optind == argc ? 1 : 0);
error (status, errno,
_("%scannot read table of mounted filesystems"), warning);
}
if (require_sync)
sync ();
if (optind == argc)
{
print_header ();
show_all_entries ();
}
else
{
int i;
/* Display explicitly requested empty filesystems. */
show_listed_fs = 1;
if (n_valid_args > 0)
print_header ();
for (i = optind; i < argc; ++i)
if (argv[i])
show_entry (argv[i], &stats[i - optind]);
}
exit (exit_status);
}
+542
View File
@@ -0,0 +1,542 @@
/* dircolors - output commands to set the LS_COLOR environment variable
Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002 H. Peter Anvin
Copyright (C) 1996-2000 Free Software Foundation, Inc.
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, 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. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <getopt.h>
#include <stdio.h>
#include "system.h"
#include "dircolors.h"
#include "dirname.h"
#include "error.h"
#include "getline.h"
#include "obstack.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "dircolors"
#define AUTHORS "H. Peter Anvin"
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
enum Shell_syntax
{
SHELL_SYNTAX_BOURNE,
SHELL_SYNTAX_C,
SHELL_SYNTAX_UNKNOWN
};
#define APPEND_CHAR(C) obstack_1grow (&lsc_obstack, C)
#define APPEND_TWO_CHAR_STRING(S) \
do \
{ \
APPEND_CHAR (S[0]); \
APPEND_CHAR (S[1]); \
} \
while (0)
/* Accumulate in this obstack the value for the LS_COLORS environment
variable. */
static struct obstack lsc_obstack;
/* Nonzero if the input file was the standard input. */
static int have_read_stdin;
/* FIXME: associate with ls_codes? */
static const char *const slack_codes[] =
{
"NORMAL", "NORM", "FILE", "DIR", "LNK", "LINK",
"SYMLINK", "ORPHAN", "MISSING", "FIFO", "PIPE", "SOCK", "BLK", "BLOCK",
"CHR", "CHAR", "DOOR", "EXEC", "LEFT", "LEFTCODE", "RIGHT", "RIGHTCODE",
"END", "ENDCODE", NULL
};
static const char *const ls_codes[] =
{
"no", "no", "fi", "di", "ln", "ln", "ln", "or", "mi", "pi", "pi",
"so", "bd", "bd", "cd", "cd", "do", "ex", "lc", "lc", "rc", "rc", "ec", "ec"
};
static struct option const long_options[] =
{
{"bourne-shell", no_argument, NULL, 'b'},
{"sh", no_argument, NULL, 'b'},
{"csh", no_argument, NULL, 'c'},
{"c-shell", no_argument, NULL, 'c'},
{"print-database", no_argument, NULL, 'p'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name);
fputs (_("\
Output commands to set the LS_COLORS environment variable.\n\
\n\
Determine format of output:\n\
-b, --sh, --bourne-shell output Bourne shell code to set LS_COLORS\n\
-c, --csh, --c-shell output C shell code to set LS_COLORS\n\
-p, --print-database output defaults\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
If FILE is specified, read it to determine which colors to use for which\n\
file types and extensions. Otherwise, a precompiled database is used.\n\
For details on the format of these files, run `dircolors --print-database'.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
static void *
xstrndup (const char *s, size_t n)
{
char *new = strndup (s, n);
if (new == NULL)
xalloc_die ();
return new;
}
/* If the SHELL environment variable is set to `csh' or `tcsh,'
assume C shell. Else Bourne shell. */
static enum Shell_syntax
guess_shell_syntax (void)
{
char *shell;
shell = getenv ("SHELL");
if (shell == NULL || *shell == '\0')
return SHELL_SYNTAX_UNKNOWN;
shell = base_name (shell);
if (STREQ (shell, "csh") || STREQ (shell, "tcsh"))
return SHELL_SYNTAX_C;
return SHELL_SYNTAX_BOURNE;
}
static void
parse_line (unsigned char const *line, char **keyword, char **arg)
{
unsigned char const *p;
unsigned char const *keyword_start;
unsigned char const *arg_start;
*keyword = NULL;
*arg = NULL;
for (p = line; ISSPACE (*p); ++p)
;
/* Ignore blank lines and shell-style comments. */
if (*p == '\0' || *p == '#')
return;
keyword_start = p;
while (!ISSPACE (*p) && *p != '\0')
{
++p;
}
*keyword = xstrndup ((const char *) keyword_start, p - keyword_start);
if (*p == '\0')
return;
do
{
++p;
}
while (ISSPACE (*p));
if (*p == '\0' || *p == '#')
return;
arg_start = p;
while (*p != '\0' && *p != '#')
++p;
for (--p; ISSPACE (*p); --p)
{
/* empty */
}
++p;
*arg = xstrndup ((const char *) arg_start, p - arg_start);
}
/* FIXME: Write a string to standard out, while watching for "dangerous"
sequences like unescaped : and = characters. */
static void
append_quoted (const char *str)
{
int need_backslash = 1;
while (*str != '\0')
{
switch (*str)
{
case '\\':
case '^':
need_backslash = !need_backslash;
break;
case ':':
case '=':
if (need_backslash)
APPEND_CHAR ('\\');
/* Fall through */
default:
need_backslash = 1;
break;
}
APPEND_CHAR (*str);
++str;
}
}
/* Read the file open on FP (with name FILENAME). First, look for a
`TERM name' directive where name matches the current terminal type.
Once found, translate and accumulate the associated directives onto
the global obstack LSC_OBSTACK. Give a diagnostic and return nonzero
upon failure (unrecognized keyword is the only way to fail here).
Return zero otherwise. */
static int
dc_parse_stream (FILE *fp, const char *filename)
{
size_t line_number = 0;
char *line = NULL;
size_t line_chars_allocated = 0;
int state;
char *term;
int err = 0;
/* State for the parser. */
enum states { ST_TERMNO, ST_TERMYES, ST_TERMSURE, ST_GLOBAL };
state = ST_GLOBAL;
/* Get terminal type */
term = getenv ("TERM");
if (term == NULL || *term == '\0')
term = "none";
while (1)
{
int line_length;
char *keywd, *arg;
int unrecognized;
++line_number;
if (fp)
{
line_length = getline (&line, &line_chars_allocated, fp);
if (line_length <= 0)
{
if (line)
free (line);
break;
}
}
else
{
line = (char *) (G_line[line_number - 1]);
line_length = G_line_length[line_number - 1];
if (line_number > G_N_LINES)
break;
}
parse_line ((unsigned char *) line, &keywd, &arg);
if (keywd == NULL)
continue;
if (arg == NULL)
{
error (0, 0, _("%s:%lu: invalid line; missing second token"),
filename, (long unsigned) line_number);
err = 1;
free (keywd);
continue;
}
unrecognized = 0;
if (strcasecmp (keywd, "TERM") == 0)
{
if (STREQ (arg, term))
state = ST_TERMSURE;
else if (state != ST_TERMSURE)
state = ST_TERMNO;
}
else
{
if (state == ST_TERMSURE)
state = ST_TERMYES; /* Another TERM can cancel */
if (state != ST_TERMNO)
{
if (keywd[0] == '.')
{
APPEND_CHAR ('*');
append_quoted (keywd);
APPEND_CHAR ('=');
append_quoted (arg);
APPEND_CHAR (':');
}
else if (keywd[0] == '*')
{
append_quoted (keywd);
APPEND_CHAR ('=');
append_quoted (arg);
APPEND_CHAR (':');
}
else if (strcasecmp (keywd, "OPTIONS") == 0
|| strcasecmp (keywd, "COLOR") == 0
|| strcasecmp (keywd, "EIGHTBIT") == 0)
{
/* Ignore. */
}
else
{
int i;
for (i = 0; slack_codes[i] != NULL; ++i)
if (strcasecmp (keywd, slack_codes[i]) == 0)
break;
if (slack_codes[i] != NULL)
{
APPEND_TWO_CHAR_STRING (ls_codes[i]);
APPEND_CHAR ('=');
append_quoted (arg);
APPEND_CHAR (':');
}
else
{
unrecognized = 1;
}
}
}
else
{
unrecognized = 1;
}
}
if (unrecognized && (state == ST_TERMSURE || state == ST_TERMYES))
{
error (0, 0, _("%s:%lu: unrecognized keyword %s"),
(filename ? quote (filename) : _("<internal>")),
(long unsigned) line_number, keywd);
err = 1;
}
free (keywd);
if (arg)
free (arg);
}
return err;
}
static int
dc_parse_file (const char *filename)
{
FILE *fp;
int err;
if (STREQ (filename, "-"))
{
have_read_stdin = 1;
fp = stdin;
}
else
{
/* OPENOPTS is a macro. It varies with the system.
Some systems distinguish between internal and
external text representations. */
fp = fopen (filename, "r");
if (fp == NULL)
{
error (0, errno, "%s", quote (filename));
return 1;
}
}
err = dc_parse_stream (fp, filename);
if (fp != stdin && fclose (fp) == EOF)
{
error (0, errno, "%s", quote (filename));
return 1;
}
return err;
}
int
main (int argc, char **argv)
{
int err = 0;
int optc;
enum Shell_syntax syntax = SHELL_SYNTAX_UNKNOWN;
int print_database = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((optc = getopt_long (argc, argv, "bcp", long_options, NULL)) != -1)
switch (optc)
{
case 'b': /* Bourne shell syntax. */
syntax = SHELL_SYNTAX_BOURNE;
break;
case 'c': /* C shell syntax. */
syntax = SHELL_SYNTAX_C;
break;
case 'p':
print_database = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
argc -= optind;
argv += optind;
/* It doesn't make sense to use --print with either of
--bourne or --c-shell. */
if (print_database && syntax != SHELL_SYNTAX_UNKNOWN)
{
error (0, 0,
_("the options to output dircolors' internal database and\n\
to select a shell syntax are mutually exclusive"));
usage (EXIT_FAILURE);
}
if (print_database && argc > 0)
{
error (0, 0,
_("no FILE arguments may be used with the option to output\n\
dircolors' internal database"));
usage (EXIT_FAILURE);
}
if (!print_database && argc > 1)
{
error (0, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
if (print_database)
{
int i;
for (i = 0; i < G_N_LINES; i++)
{
fwrite (G_line[i], 1, G_line_length[i], stdout);
fputc ('\n', stdout);
}
}
else
{
/* If shell syntax was not explicitly specified, try to guess it. */
if (syntax == SHELL_SYNTAX_UNKNOWN)
{
syntax = guess_shell_syntax ();
if (syntax == SHELL_SYNTAX_UNKNOWN)
{
error (EXIT_FAILURE, 0,
_("no SHELL environment variable, and no shell type option given"));
}
}
obstack_init (&lsc_obstack);
if (argc == 0)
err = dc_parse_stream (NULL, NULL);
else
err = dc_parse_file (argv[0]);
if (!err)
{
size_t len = obstack_object_size (&lsc_obstack);
char *s = obstack_finish (&lsc_obstack);
const char *prefix;
const char *suffix;
if (syntax == SHELL_SYNTAX_BOURNE)
{
prefix = "LS_COLORS='";
suffix = "';\nexport LS_COLORS\n";
}
else
{
prefix = "setenv LS_COLORS '";
suffix = "'\n";
}
fputs (prefix, stdout);
fwrite (s, 1, len, stdout);
fputs (suffix, stdout);
}
}
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, _("standard input"));
exit (err == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+121
View File
@@ -0,0 +1,121 @@
#define G_N_LINES 106
const size_t G_line_length[G_N_LINES] =
{
65, 72, 0, 59, 61, 0, 77, 10, 12, 15, 12, 14, 14, 14, 14, 13, 13, 13, 13,
13, 13, 11, 10, 16, 17, 9, 11, 13, 10, 10, 0, 73, 64, 18, 64, 19, 72,
25, 72, 68, 22, 22, 71, 72, 17, 19, 17, 34, 39, 45, 0, 44, 10, 0, 70,
75, 48, 0, 73, 40, 11, 11, 11, 11, 0, 48, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 0, 15, 10, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10,
11, 10, 10, 11, 10, 10, 9, 9, 10, 10, 0, 15, 10, 10, 10
};
const char *const G_line[G_N_LINES] =
{
"# Configuration file for dircolors, a utility to help you set the",
"# LS_COLORS environment variable used by GNU ls with the --color option.",
"",
"# The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the",
"# slackware version of dircolors) are recognized but ignored.",
"",
"# Below, there should be one TERM entry for each termtype that is colorizable",
"TERM linux",
"TERM linux-c",
"TERM mach-color",
"TERM console",
"TERM con132x25",
"TERM con132x30",
"TERM con132x43",
"TERM con132x60",
"TERM con80x25",
"TERM con80x28",
"TERM con80x30",
"TERM con80x43",
"TERM con80x50",
"TERM con80x60",
"TERM dtterm",
"TERM xterm",
"TERM xterm-color",
"TERM xterm-debian",
"TERM rxvt",
"TERM screen",
"TERM screen-w",
"TERM vt100",
"TERM Eterm",
"",
"# Below are the color init strings for the basic file types. A color init",
"# string consists of one or more of the following numeric codes:",
"# Attribute codes:",
"# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed",
"# Text color codes:",
"# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white",
"# Background color codes:",
"# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white",
"NORMAL 00 # global default, although everything should be something.",
"FILE 00 # normal file",
"DIR 01;34 # directory",
"LINK 01;36 # symbolic link. (If you set this to 'target' instead of a",
" # numerical value, the color is as for the file pointed to.)",
"FIFO 40;33 # pipe",
"SOCK 01;35 # socket",
"DOOR 01;35 # door",
"BLK 40;33;01 # block device driver",
"CHR 40;33;01 # character device driver",
"ORPHAN 40;31;01 # symlink to nonexistent file",
"",
"# This is for files with execute permission:",
"EXEC 01;32",
"",
"# List any file extensions like '.gz' or '.tar' that you would like ls",
"# to colorize below. Put the extension, a space, and the color init string.",
"# (and any comments you want to add after a '#')",
"",
"# If you use DOS-style suffixes, you may want to uncomment the following:",
"#.cmd 01;32 # executables (bright green)",
"#.exe 01;32",
"#.com 01;32",
"#.btm 01;32",
"#.bat 01;32",
"",
".tar 01;31 # archives or compressed (bright red)",
".tgz 01;31",
".arj 01;31",
".taz 01;31",
".lzh 01;31",
".zip 01;31",
".z 01;31",
".Z 01;31",
".gz 01;31",
".bz2 01;31",
".deb 01;31",
".rpm 01;31",
".jar 01;31",
"",
"# image formats",
".jpg 01;35",
".jpeg 01;35",
".gif 01;35",
".bmp 01;35",
".pbm 01;35",
".pgm 01;35",
".ppm 01;35",
".tga 01;35",
".xbm 01;35",
".xpm 01;35",
".tif 01;35",
".tiff 01;35",
".png 01;35",
".mpg 01;35",
".mpeg 01;35",
".avi 01;35",
".fli 01;35",
".gl 01;35",
".dl 01;35",
".xcf 01;35",
".xwd 01;35",
"",
"# audio formats",
".ogg 01;35",
".mp3 01;35",
".wav 01;35"
};
@@ -0,0 +1,106 @@
# Configuration file for dircolors, a utility to help you set the
# LS_COLORS environment variable used by GNU ls with the --color option.
# The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the
# slackware version of dircolors) are recognized but ignored.
# Below, there should be one TERM entry for each termtype that is colorizable
TERM linux
TERM linux-c
TERM mach-color
TERM console
TERM con132x25
TERM con132x30
TERM con132x43
TERM con132x60
TERM con80x25
TERM con80x28
TERM con80x30
TERM con80x43
TERM con80x50
TERM con80x60
TERM dtterm
TERM xterm
TERM xterm-color
TERM xterm-debian
TERM rxvt
TERM screen
TERM screen-w
TERM vt100
TERM Eterm
# Below are the color init strings for the basic file types. A color init
# string consists of one or more of the following numeric codes:
# Attribute codes:
# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
# Text color codes:
# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
# Background color codes:
# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
NORMAL 00 # global default, although everything should be something.
FILE 00 # normal file
DIR 01;34 # directory
LINK 01;36 # symbolic link. (If you set this to 'target' instead of a
# numerical value, the color is as for the file pointed to.)
FIFO 40;33 # pipe
SOCK 01;35 # socket
DOOR 01;35 # door
BLK 40;33;01 # block device driver
CHR 40;33;01 # character device driver
ORPHAN 40;31;01 # symlink to nonexistent file
# This is for files with execute permission:
EXEC 01;32
# List any file extensions like '.gz' or '.tar' that you would like ls
# to colorize below. Put the extension, a space, and the color init string.
# (and any comments you want to add after a '#')
# If you use DOS-style suffixes, you may want to uncomment the following:
#.cmd 01;32 # executables (bright green)
#.exe 01;32
#.com 01;32
#.btm 01;32
#.bat 01;32
.tar 01;31 # archives or compressed (bright red)
.tgz 01;31
.arj 01;31
.taz 01;31
.lzh 01;31
.zip 01;31
.z 01;31
.Z 01;31
.gz 01;31
.bz2 01;31
.deb 01;31
.rpm 01;31
.jar 01;31
# image formats
.jpg 01;35
.jpeg 01;35
.gif 01;35
.bmp 01;35
.pbm 01;35
.pgm 01;35
.ppm 01;35
.tga 01;35
.xbm 01;35
.xpm 01;35
.tif 01;35
.tiff 01;35
.png 01;35
.mpg 01;35
.mpeg 01;35
.avi 01;35
.fli 01;35
.gl 01;35
.dl 01;35
.xcf 01;35
.xwd 01;35
# audio formats
.ogg 01;35
.mp3 01;35
.wav 01;35
+107
View File
@@ -0,0 +1,107 @@
/* dirname -- strip filename suffix from pathname
Copyright (C) 1990-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie and Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "long-options.h"
#include "error.h"
#include "dirname.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "dirname"
#define AUTHORS N_ ("David MacKenzie and Jim Meyering")
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s NAME\n\
or: %s OPTION\n\
"),
program_name, program_name);
fputs (_("\
Print NAME with its trailing /component removed; if NAME contains no /'s,\n\
output `.' (meaning the current directory).\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
static char const dot = '.';
char const *result;
size_t len;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
/* The above handles --help and --version.
Since there is no other invocation of getopt, handle `--' here. */
if (argc > 1 && STREQ (argv[1], "--"))
{
--argc;
++argv;
}
if (argc != 2)
{
error (0, 0, argc < 2 ? _("too few arguments")
: _("too many arguments"));
usage (EXIT_FAILURE);
}
result = argv[1];
len = dir_len (result);
if (! len)
{
result = &dot;
len = 1;
}
fwrite (result, 1, len, stdout);
putchar ('\n');
exit (EXIT_SUCCESS);
}
+735
View File
@@ -0,0 +1,735 @@
/* du -- summarize disk usage
Copyright (C) 1988-1991, 1995-2003 Free Software Foundation, Inc.
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, 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. */
/* Differences from the Unix du:
* Doesn't simply ignore the names of regular files given as arguments
when -a is given.
By tege@sics.se, Torbjorn Granlund,
and djm@ai.mit.edu, David MacKenzie.
Variable blocks added by lm@sgi.com and eggert@twinsun.com.
Rewritten to use nftw by Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#include "system.h"
#include "dirname.h" /* for strip_trailing_slashes */
#include "error.h"
#include "exclude.h"
#include "ftw.h"
#include "hash.h"
#include "human.h"
#include "quote.h"
#include "quotearg.h"
#include "same.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "du"
#define AUTHORS \
N_ ("Torbjorn Granlund, David MacKenzie, Larry McVoy, Paul Eggert, and Jim Meyering")
/* Initial size of the hash table. */
#define INITIAL_TABLE_SIZE 103
/* The maximum number of simultaneously open file handles that
may be used by ftw. */
#define MAX_N_DESCRIPTORS (3 * UTILS_OPEN_MAX / 4)
/* Hash structure for inode and device numbers. The separate entry
structure makes it easier to rehash "in place". */
struct entry
{
ino_t st_ino;
dev_t st_dev;
};
/* A set of dev/ino pairs. */
static Hash_table *htab;
/* Name under which this program was invoked. */
char *program_name;
/* If nonzero, display counts for all files, not just directories. */
static int opt_all = 0;
/* If nonzero, rather than using the disk usage of each file,
use the apparent size (a la stat.st_size). */
static int apparent_size = 0;
/* If nonzero, count each hard link of files with multiple links. */
static int opt_count_all = 0;
/* If nonzero, print a grand total at the end. */
static int print_totals = 0;
/* If nonzero, do not add sizes of subdirectories. */
static int opt_separate_dirs = 0;
/* If nonzero, dereference symlinks that are command line arguments.
Implementing this while still using nftw is a little tricky.
For each command line argument that is a symlink-to-directory,
call nftw with "command_line_arg/." and remember to omit the
added `/.' when printing. */
static int opt_dereference_arguments = 0;
/* Show the total for each directory (and file if --all) that is at
most MAX_DEPTH levels down from the root of the hierarchy. The root
is at level 0, so `du --max-depth=0' is equivalent to `du -s'. */
static int max_depth = INT_MAX;
/* Human-readable options for output. */
static int human_output_opts;
/* The units to use when printing sizes. */
static uintmax_t output_block_size;
/* File name patterns to exclude. */
static struct exclude *exclude;
/* Grand total size of all args, in bytes. */
static uintmax_t tot_size = 0;
/* In some cases, we have to append `/.' or just `.' to an argument
(to dereference a symlink). When we do that, we don't want to
expose this artifact when printing file/directory names, so these
variables keep track of the length of the original command line
argument and the length of the suffix we've added, respectively.
ARG_LENGTH == 0 indicates that we haven't added a suffix.
This information is used to omit any such added characters when
printing names. */
size_t arg_length;
size_t suffix_length;
/* Nonzero indicates that du should exit with EXIT_FAILURE upon completion. */
int G_fail;
#define IS_FTW_DIR_TYPE(Type) \
((Type) == FTW_D \
|| (Type) == FTW_DP \
|| (Type) == FTW_DNR)
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
APPARENT_SIZE_OPTION = CHAR_MAX + 1,
EXCLUDE_OPTION,
MAX_DEPTH_OPTION
};
static struct option const long_options[] =
{
{"all", no_argument, NULL, 'a'},
{"apparent-size", no_argument, NULL, APPARENT_SIZE_OPTION},
{"block-size", required_argument, 0, 'B'},
{"bytes", no_argument, NULL, 'b'},
{"count-links", no_argument, NULL, 'l'},
{"dereference", no_argument, NULL, 'L'},
{"dereference-args", no_argument, NULL, 'D'},
{"exclude", required_argument, 0, EXCLUDE_OPTION},
{"exclude-from", required_argument, 0, 'X'},
{"human-readable", no_argument, NULL, 'h'},
{"si", no_argument, 0, 'H'},
{"kilobytes", no_argument, NULL, 'k'}, /* long form is obsolescent */
{"max-depth", required_argument, NULL, MAX_DEPTH_OPTION},
{"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
{"one-file-system", no_argument, NULL, 'x'},
{"separate-dirs", no_argument, NULL, 'S'},
{"summarize", no_argument, NULL, 's'},
{"total", no_argument, NULL, 'c'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
fputs (_("\
Summarize disk usage of each FILE, recursively for directories.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-a, --all write counts for all files, not just directories\n\
--apparent-size print apparent sizes, rather than disk usage; although\n\
the apparent size is usually smaller, it may be\n\
larger due to holes in (`sparse') files, internal\n\
fragmentation, indirect blocks, and the like\n\
-B, --block-size=SIZE use SIZE-byte blocks\n\
-b, --bytes equivalent to `--apparent-size --block-size=1'\n\
-c, --total produce a grand total\n\
-D, --dereference-args dereference FILEs that are symbolic links\n\
"), stdout);
fputs (_("\
-h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
-H, --si likewise, but use powers of 1000 not 1024\n\
-k like --block-size=1K\n\
-l, --count-links count sizes many times if hard linked\n\
"), stdout);
fputs (_("\
-L, --dereference dereference all symbolic links\n\
-S, --separate-dirs do not include size of subdirectories\n\
-s, --summarize display only a total for each argument\n\
"), stdout);
fputs (_("\
-x, --one-file-system skip directories on different filesystems\n\
-X FILE, --exclude-from=FILE Exclude files that match any pattern in FILE.\n\
--exclude=PATTERN Exclude files that match PATTERN.\n\
--max-depth=N print the total for a directory (or file, with --all)\n\
only if it is N or fewer levels below the command\n\
line argument; --max-depth=0 is the same as\n\
--summarize\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
SIZE may be (or may be an integer optionally followed by) one of following:\n\
kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
static unsigned int
entry_hash (void const *x, unsigned int table_size)
{
struct entry const *p = x;
/* Ignoring the device number here should be fine. */
/* The cast to uintmax_t prevents negative remainders
if st_ino is negative. */
return (uintmax_t) p->st_ino % table_size;
}
/* Compare two dev/ino pairs. Return true if they are the same. */
static bool
entry_compare (void const *x, void const *y)
{
struct entry const *a = x;
struct entry const *b = y;
return SAME_INODE (*a, *b) ? true : false;
}
/* Try to insert the INO/DEV pair into the global table, HTAB.
If the pair is successfully inserted, return zero.
Upon failed memory allocation exit nonzero.
If the pair is already in the table, return nonzero. */
static int
hash_ins (ino_t ino, dev_t dev)
{
struct entry *ent;
struct entry *ent_from_table;
ent = (struct entry *) xmalloc (sizeof *ent);
ent->st_ino = ino;
ent->st_dev = dev;
ent_from_table = hash_insert (htab, ent);
if (ent_from_table == NULL)
{
/* Insertion failed due to lack of memory. */
xalloc_die ();
}
if (ent_from_table == ent)
{
/* Insertion succeeded. */
return 0;
}
/* That pair is already in the table, so ENT was not inserted. Free it. */
free (ent);
return 1;
}
/* Initialize the hash table. */
static void
hash_init (void)
{
htab = hash_initialize (INITIAL_TABLE_SIZE, NULL,
entry_hash, entry_compare, free);
if (htab == NULL)
xalloc_die ();
}
/* Print N_BYTES. Convert it to a readable value before printing. */
static void
print_only_size (uintmax_t n_bytes)
{
char buf[LONGEST_HUMAN_READABLE + 1];
fputs (human_readable (n_bytes, buf, human_output_opts,
1, output_block_size), stdout);
}
/* Print N_BYTES followed by STRING on a line.
Convert N_BYTES to a readable value before printing. */
static void
print_size (uintmax_t n_bytes, const char *string)
{
print_only_size (n_bytes);
printf ("\t%s\n", string);
fflush (stdout);
}
/* This function is called once for every file system object that nftw
encounters. nftw does a depth-first traversal. This function knows
that and accumulates per-directory totals based on changes in
the depth of the current entry. */
static int
process_file (const char *file, const struct stat *sb, int file_type,
struct FTW *info)
{
uintmax_t size;
uintmax_t size_to_print;
static int first_call = 1;
static size_t prev_level;
static size_t n_alloc;
static uintmax_t *sum_ent;
static uintmax_t *sum_subdir;
int print = 1;
/* Always define info->skip before returning. */
info->skip = excluded_filename (exclude, file + info->base);
switch (file_type)
{
case FTW_NS:
error (0, errno, _("cannot access %s"), quote (file));
G_fail = 1;
return 0;
case FTW_DCHP:
error (0, errno, _("cannot change to parent of directory %s"),
quote (file));
G_fail = 1;
return 0;
case FTW_DCH:
/* Don't return just yet, since although nftw couldn't chdir into the
directory, it was able to stat it, so we do have a size. */
error (0, errno, _("cannot change to directory %s"), quote (file));
G_fail = 1;
break;
case FTW_DNR:
/* Don't return just yet, since although nftw couldn't read the
directory, it was able to stat it, so we do have a size. */
error (0, errno, _("cannot read directory %s"), quote (file));
G_fail = 1;
break;
default:
break;
}
/* If this is the first (pre-order) encounter with a directory,
return right away. */
if (file_type == FTW_DPRE)
return 0;
/* If the file is being excluded or if it has already been counted
via a hard link, then don't let it contribute to the sums. */
if (info->skip
|| (!opt_count_all
&& 1 < sb->st_nlink
&& hash_ins (sb->st_ino, sb->st_dev)))
{
/* Note that we must not simply return here.
We still have to update prev_level and maybe propagate
some sums up the hierarchy. */
size = 0;
print = 0;
}
else
{
size = (apparent_size
? sb->st_size
: ST_NBLOCKS (*sb) * ST_NBLOCKSIZE);
}
if (first_call)
{
n_alloc = info->level + 10;
sum_ent = XCALLOC (uintmax_t, n_alloc);
sum_subdir = XCALLOC (uintmax_t, n_alloc);
}
else
{
/* FIXME: it's a shame that we need these `size_t' casts to avoid
warnings from gcc about `comparison between signed and unsigned'.
Probably unavoidable, assuming that the members of struct FTW
are of type `int' (historical), since I want variables like
n_alloc and prev_level to have types that make sense. */
if (n_alloc <= (size_t) info->level)
{
n_alloc = info->level * 2;
sum_ent = XREALLOC (sum_ent, uintmax_t, n_alloc);
sum_subdir = XREALLOC (sum_subdir, uintmax_t, n_alloc);
}
}
size_to_print = size;
if (! first_call)
{
if ((size_t) info->level == prev_level)
{
/* This is usually the most common case. Do nothing. */
}
else if ((size_t) info->level > prev_level)
{
/* Descending the hierarchy.
Clear the accumulators for *all* levels between prev_level
and the current one. The depth may change dramatically,
e.g., from 1 to 10. */
int i;
for (i = prev_level + 1; i <= info->level; i++)
sum_ent[i] = sum_subdir[i] = 0;
}
else /* info->level < prev_level */
{
/* Ascending the hierarchy.
nftw processes a directory only after all entries in that
directory have been processed. When the depth decreases,
propagate sums from the children (prev_level) to the parent.
Here, the current level is always one smaller than the
previous one. */
assert ((size_t) info->level == prev_level - 1);
size_to_print += sum_ent[prev_level];
if (!opt_separate_dirs)
size_to_print += sum_subdir[prev_level];
sum_subdir[info->level] += (sum_ent[prev_level]
+ sum_subdir[prev_level]);
}
}
prev_level = info->level;
first_call = 0;
/* Let the size of a directory entry contribute to the total for the
containing directory, unless --separate-dirs (-S) is specified. */
if ( ! (opt_separate_dirs && IS_FTW_DIR_TYPE (file_type)))
sum_ent[info->level] += size;
/* Even if this directory is unreadable or we can't chdir into it,
do let its size contribute to the total, ... */
tot_size += size;
/* ... but don't print out a total for it, since without the size(s)
of any potential entries, it could be very misleading. */
if (file_type == FTW_DNR || file_type == FTW_DCH)
return 0;
/* If we're not counting an entry, e.g., because it's a hard link
to a file we've already counted (and --count-links), then don't
print a line for it. */
if (!print)
return 0;
/* FIXME: This looks suspiciously like it could be simplified. */
if ((IS_FTW_DIR_TYPE (file_type) &&
(info->level <= max_depth || info->level == 0))
|| ((opt_all && info->level <= max_depth) || info->level == 0))
{
print_only_size (size_to_print);
fputc ('\t', stdout);
if (arg_length)
{
/* Print the file name, but without the `.' or `/.'
directory suffix that we may have added in main. */
/* Print everything before the part we appended. */
fwrite (file, arg_length, 1, stdout);
/* Print everything after what we appended. */
fputs (file + arg_length + suffix_length
+ (file[arg_length + suffix_length] == '/'), stdout);
}
else
{
fputs (file, stdout);
}
fputc ('\n', stdout);
fflush (stdout);
}
return 0;
}
static int
is_symlink_to_dir (char const *file)
{
char *f;
struct stat sb;
ASSIGN_STRDUPA (f, file);
strip_trailing_slashes (f);
return (lstat (f, &sb) == 0 && S_ISLNK (sb.st_mode)
&& stat (f, &sb) == 0 && S_ISDIR (sb.st_mode));
}
/* Recursively print the sizes of the directories (and, if selected, files)
named in FILES, the last entry of which is NULL.
FTW_FLAGS controls how nftw works.
Return nonzero upon error. */
static int
du_files (char **files, int ftw_flags)
{
int fail = 0;
int i;
for (i = 0; files[i]; i++)
{
char *file = files[i];
char *orig = file;
int err;
arg_length = 0;
if (!print_totals)
hash_clear (htab);
/* When dereferencing only command line arguments, we're using
nftw's FTW_PHYS flag, so a symlink-to-directory specified on
the command line wouldn't normally be dereferenced. To work
around that, we incur the overhead of appending `/.' (or `.')
now, and later removing it each time we output the name of
a derived file or directory name. */
if (opt_dereference_arguments && is_symlink_to_dir (file))
{
size_t len = strlen (file);
/* Append `/.', but if there's already a trailing slash,
append only the `.'. */
char const *suffix = (file[len - 1] == '/' ? "." : "/.");
char *new_file;
suffix_length = strlen (suffix);
new_file = xmalloc (len + suffix_length + 1);
memcpy (mempcpy (new_file, file, len), suffix, suffix_length + 1);
arg_length = len;
file = new_file;
}
err = nftw (file, process_file, MAX_N_DESCRIPTORS, ftw_flags);
if (err)
error (0, errno, "%s", quote (orig));
fail |= err;
if (arg_length)
free (file);
}
if (print_totals)
print_size (tot_size, _("total"));
return fail;
}
int
main (int argc, char **argv)
{
int c;
char *cwd_only[2];
int max_depth_specified = 0;
char **files;
int fail;
/* Bit flags that control how nftw works. */
int ftw_flags = FTW_DEPTH | FTW_PHYS | FTW_CHDIR;
/* If nonzero, display only a total for each argument. */
int opt_summarize_only = 0;
cwd_only[0] = ".";
cwd_only[1] = NULL;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
exclude = new_exclude ();
human_output_opts = human_options (getenv ("DU_BLOCK_SIZE"), false,
&output_block_size);
fail = 0;
while ((c = getopt_long (argc, argv, "abchHklmsxB:DLSX:", long_options, NULL))
!= -1)
{
long int tmp_long;
switch (c)
{
case 0: /* Long option. */
break;
case 'a':
opt_all = 1;
break;
case APPARENT_SIZE_OPTION:
apparent_size = 1;
break;
case 'b':
apparent_size = 1;
human_output_opts = 0;
output_block_size = 1;
break;
case 'c':
print_totals = 1;
break;
case 'h':
human_output_opts = human_autoscale | human_SI | human_base_1024;
output_block_size = 1;
break;
case 'H':
human_output_opts = human_autoscale | human_SI;
output_block_size = 1;
break;
case 'k':
human_output_opts = 0;
output_block_size = 1024;
break;
case MAX_DEPTH_OPTION: /* --max-depth=N */
if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) == LONGINT_OK
&& 0 <= tmp_long && tmp_long <= INT_MAX)
{
max_depth_specified = 1;
max_depth = (int) tmp_long;
}
else
{
error (0, 0, _("invalid maximum depth %s"),
quote (optarg));
fail = 1;
}
break;
case 'm': /* obsolescent */
human_output_opts = 0;
output_block_size = 1024 * 1024;
break;
case 'l':
opt_count_all = 1;
break;
case 's':
opt_summarize_only = 1;
break;
case 'x':
ftw_flags |= FTW_MOUNT;
break;
case 'B':
human_output_opts = human_options (optarg, true, &output_block_size);
break;
case 'D':
opt_dereference_arguments = 1;
break;
case 'L':
ftw_flags &= ~FTW_PHYS;
break;
case 'S':
opt_separate_dirs = 1;
break;
case 'X':
if (add_exclude_file (add_exclude, exclude, optarg,
EXCLUDE_WILDCARDS, '\n'))
{
error (0, errno, "%s", quotearg_colon (optarg));
fail = 1;
}
break;
case EXCLUDE_OPTION:
add_exclude (exclude, optarg, EXCLUDE_WILDCARDS);
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
fail = 1;
}
}
if (fail)
usage (EXIT_FAILURE);
if (opt_all && opt_summarize_only)
{
error (0, 0, _("cannot both summarize and show all entries"));
usage (EXIT_FAILURE);
}
if (opt_summarize_only && max_depth_specified && max_depth == 0)
{
error (0, 0,
_("warning: summarizing is the same as using --max-depth=0"));
}
if (opt_summarize_only && max_depth_specified && max_depth != 0)
{
error (0, 0,
_("warning: summarizing conflicts with --max-depth=%d"),
max_depth);
usage (EXIT_FAILURE);
}
if (opt_summarize_only)
max_depth = 0;
files = (optind == argc ? cwd_only : argv + optind);
/* Initialize the hash structure for inode numbers. */
hash_init ();
exit (du_files (files, ftw_flags) || G_fail
? EXIT_FAILURE : EXIT_SUCCESS);
}
+248
View File
@@ -0,0 +1,248 @@
/* echo.c, derived from code echo.c in Bash.
Copyright (C) 87,89, 1991-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "long-options.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "echo"
#define AUTHORS "FIXME unknown"
/* echo [-neE] [arg ...]
Output the ARGs. If -n is specified, the trailing newline is
suppressed. If the -e option is given, interpretation of the
following backslash-escaped characters is turned on:
\a alert (bell)
\b backspace
\c suppress trailing newline
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\num the character whose ASCII code is NUM (octal).
You can explicitly turn off the interpretation of the above characters
on System V systems with the -E option.
*/
/* If defined, interpret backslash escapes if -e is given. */
#define V9_ECHO
/* If defined, interpret backslash escapes unless -E is given.
V9_ECHO must also be defined. */
/* #define V9_DEFAULT */
#if defined (V9_ECHO)
# if defined (V9_DEFAULT)
# define VALID_ECHO_OPTIONS "neE"
# else
# define VALID_ECHO_OPTIONS "ne"
# endif /* !V9_DEFAULT */
#else /* !V9_ECHO */
# define VALID_ECHO_OPTIONS "n"
#endif /* !V9_ECHO */
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [STRING]...\n"), program_name);
fputs (_("\
Echo the STRING(s) to standard output.\n\
\n\
-n do not output the trailing newline\n\
-e enable interpretation of the backslash-escaped characters\n\
listed below\n\
-E disable interpretation of those sequences in STRINGs\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Without -E, the following sequences are recognized and interpolated:\n\
\n\
\\NNN the character whose ASCII code is NNN (octal)\n\
\\\\ backslash\n\
\\a alert (BEL)\n\
\\b backspace\n\
"), stdout);
fputs (_("\
\\c suppress trailing newline\n\
\\f form feed\n\
\\n new line\n\
\\r carriage return\n\
\\t horizontal tab\n\
\\v vertical tab\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Print the words in LIST to standard output. If the first word is
`-n', then don't print a trailing newline. We also support the
echo syntax from Version 9 unix systems. */
int
main (int argc, char **argv)
{
int display_return = 1, do_v9 = 0;
int allow_options = 1;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
/* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
if (getenv ("POSIXLY_CORRECT") == NULL)
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
else
allow_options = 0;
/* System V machines already have a /bin/sh with a v9 behaviour. We
use the identical behaviour for these machines so that the
existing system shell scripts won't barf. */
#if defined (V9_ECHO) && defined (V9_DEFAULT)
do_v9 = allow_options;
#endif
--argc;
++argv;
while (argc > 0 && *argv[0] == '-')
{
register char *temp;
register int i;
/* If it appears that we are handling options, then make sure that
all of the options specified are actually valid. Otherwise, the
string should just be echoed. */
temp = argv[0] + 1;
for (i = 0; temp[i]; i++)
{
if (strrchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
goto just_echo;
}
if (!*temp)
goto just_echo;
/* All of the options in TEMP are valid options to ECHO.
Handle them. */
while (*temp)
{
if (allow_options && *temp == 'n')
display_return = 0;
#if defined (V9_ECHO)
else if (allow_options && *temp == 'e')
do_v9 = 1;
# if defined (V9_DEFAULT)
else if (allow_options && *temp == 'E')
do_v9 = 0;
# endif /* V9_DEFAULT */
#endif /* V9_ECHO */
else
goto just_echo;
temp++;
}
argc--;
argv++;
}
just_echo:
if (argc > 0)
{
#if defined (V9_ECHO)
if (do_v9)
{
while (argc > 0)
{
register char *s = argv[0];
register int c;
while ((c = *s++))
{
if (c == '\\' && *s)
{
switch (c = *s++)
{
case 'a': c = '\007'; break;
case 'b': c = '\b'; break;
case 'c': display_return = 0; continue;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = (int) 0x0B; break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c -= '0';
if (*s >= '0' && *s <= '7')
c = c * 8 + (*s++ - '0');
if (*s >= '0' && *s <= '7')
c = c * 8 + (*s++ - '0');
break;
case '\\': break;
default: putchar ('\\'); break;
}
}
putchar(c);
}
argc--;
argv++;
if (argc > 0)
putchar(' ');
}
}
else
#endif /* V9_ECHO */
{
while (argc > 0)
{
fputs (argv[0], stdout);
argc--;
argv++;
if (argc > 0)
putchar (' ');
}
}
}
if (display_return)
putchar ('\n');
exit (EXIT_SUCCESS);
}
+207
View File
@@ -0,0 +1,207 @@
/* env - run a program in a modified environment
Copyright (C) 1986, 1991-2003 Free Software Foundation, Inc.
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, 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. */
/* Richard Mlynarik and David MacKenzie */
/* Options:
-
-i
--ignore-environment
Construct a new environment from scratch; normally the
environment is inherited from the parent process, except as
modified by other options.
-u variable
--unset=variable
Unset variable VARIABLE (remove it from the environment).
If VARIABLE was not set, does nothing.
variable=value (an arg containing a "=" character)
Set the environment variable VARIABLE to value VALUE. VALUE
may be of zero length ("variable="). Setting a variable to a
zero-length value is different from unsetting it.
--
Indicate that the following argument is the program
to invoke. This is necessary when the program's name
begins with "-" or contains a "=".
The first remaining argument specifies a program to invoke;
it is searched for according to the specification of the PATH
environment variable. Any arguments following that are
passed as arguments to that program.
If no command name is specified following the environment
specifications, the resulting environment is printed.
This is like specifying a command name of "printenv".
Examples:
If the environment passed to "env" is
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
env - foo
runs "foo" in a null environment.
env foo
runs "foo" in the environment
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
env DISPLAY=gnu:0 nemacs
runs "nemacs" in the environment
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks DISPLAY=gnu:0 }
env - LOGNAME=foo /hacks/hack bar baz
runs the "hack" program on arguments "bar" and "baz" in an
environment in which the only variable is "LOGNAME". Note that
the "-" option clears out the PATH variable, so one should be
careful to specify in which directory to find the program to
call.
env -u EDITOR LOGNAME=foo PATH=/energy -- e=mc2 bar baz
runs the program "/energy/e=mc2" with environment
{ LOGNAME=foo PATH=/energy }
*/
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "error.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "env"
#define AUTHORS N_ ("Richard Mlynarik and David MacKenzie")
int putenv ();
extern char **environ;
/* The name by which this program was run. */
char *program_name;
static struct option const longopts[] =
{
{"ignore-environment", no_argument, NULL, 'i'},
{"unset", required_argument, NULL, 'u'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]\n"),
program_name);
fputs (_("\
Set each NAME to VALUE in the environment and run COMMAND.\n\
\n\
-i, --ignore-environment start with an empty environment\n\
-u, --unset=NAME remove variable from the environment\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
A mere - implies -i. If no COMMAND, print the resulting environment.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (register int argc, register char **argv, char **envp)
{
char *dummy_environ[1];
int optc;
int ignore_environment = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((optc = getopt_long (argc, argv, "+iu:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'i':
ignore_environment = 1;
break;
case 'u':
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (2);
}
}
if (optind != argc && !strcmp (argv[optind], "-"))
ignore_environment = 1;
environ = dummy_environ;
environ[0] = NULL;
if (!ignore_environment)
for (; *envp; envp++)
putenv (*envp);
optind = 0; /* Force GNU getopt to re-initialize. */
while ((optc = getopt_long (argc, argv, "+iu:", longopts, NULL)) != -1)
if (optc == 'u')
putenv (optarg); /* Requires GNU putenv. */
if (optind != argc && !strcmp (argv[optind], "-"))
++optind;
while (optind < argc && strchr (argv[optind], '='))
putenv (argv[optind++]);
/* If no program is specified, print the environment and exit. */
if (optind == argc)
{
while (*environ)
puts (*environ++);
exit (EXIT_SUCCESS);
}
execvp (argv[optind], &argv[optind]);
{
int exit_status = (errno == ENOENT ? 127 : 126);
error (0, errno, "%s", argv[optind]);
exit (exit_status);
}
}
+412
View File
@@ -0,0 +1,412 @@
/* expand - convert tabs to spaces
Copyright (C) 89, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* By default, convert all tabs to spaces.
Preserves backspace characters in the output; they decrement the
column count for tab calculations.
The default action is equivalent to -8.
Options:
--tabs=tab1[,tab2[,...]]
-t tab1[,tab2[,...]]
-tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1
spaces apart instead of the default 8. Otherwise,
set the tabs at columns tab1, tab2, etc. (numbered from
0); replace any tabs beyond the tabstops given with
single spaces.
--initial
-i Only convert initial tabs on each line to spaces.
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "posixver.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "expand"
#define AUTHORS "David MacKenzie"
/* The number of bytes added at a time to the amount of memory
allocated for the output line. */
#define OUTPUT_BLOCK 256
/* The number of bytes added at a time to the amount of memory
allocated for the list of tabstops. */
#define TABLIST_BLOCK 256
/* The name this program was run with. */
char *program_name;
/* If nonzero, convert blanks even after nonblank characters have been
read on the line. */
static int convert_entire_line;
/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */
static int tab_size;
/* Array of the explicit column numbers of the tab stops;
after `tab_list' is exhausted, each additional tab is replaced
by a space. The first column is column 0. */
static int *tab_list;
/* The index of the first invalid element of `tab_list',
where the next element can be added. */
static int first_free_tab;
/* Null-terminated array of input filenames. */
static char **file_list;
/* Default for `file_list' if no files are given on the command line. */
static char *stdin_argv[] =
{
"-", NULL
};
/* Nonzero if we have ever read standard input. */
static int have_read_stdin;
/* Status to return to the system. */
static int exit_status;
static struct option const longopts[] =
{
{"tabs", required_argument, NULL, 't'},
{"initial", no_argument, NULL, 'i'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Convert tabs in each FILE to spaces, writing to standard output.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-i, --initial do not convert TABs after non whitespace\n\
-t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\
"), stdout);
fputs (_("\
-t, --tabs=LIST use comma separated list of explicit tab positions\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Add tab stop TABVAL to the end of `tab_list', except
if TABVAL is -1, do nothing. */
static void
add_tabstop (int tabval)
{
if (tabval == -1)
return;
if (first_free_tab % TABLIST_BLOCK == 0)
tab_list = (int *) xrealloc ((char *) tab_list,
(first_free_tab
+ TABLIST_BLOCK * sizeof (tab_list[0])));
tab_list[first_free_tab++] = tabval;
}
/* Add the comma or blank separated list of tabstops STOPS
to the list of tabstops. */
static void
parse_tabstops (char *stops)
{
int tabval = -1;
for (; *stops; stops++)
{
if (*stops == ',' || ISBLANK (*stops))
{
add_tabstop (tabval);
tabval = -1;
}
else if (ISDIGIT (*stops))
{
if (tabval == -1)
tabval = 0;
tabval = tabval * 10 + *stops - '0';
}
else
error (EXIT_FAILURE, 0, _("tab size contains an invalid character"));
}
add_tabstop (tabval);
}
/* Check that the list of tabstops TABS, with ENTRIES entries,
contains only nonzero, ascending values. */
static void
validate_tabstops (int *tabs, int entries)
{
int prev_tab = 0;
int i;
for (i = 0; i < entries; i++)
{
if (tabs[i] == 0)
error (EXIT_FAILURE, 0, _("tab size cannot be 0"));
if (tabs[i] <= prev_tab)
error (EXIT_FAILURE, 0, _("tab sizes must be ascending"));
prev_tab = tabs[i];
}
}
/* Close the old stream pointer FP if it is non-NULL,
and return a new one opened to read the next input file.
Open a filename of `-' as the standard input.
Return NULL if there are no more input files. */
static FILE *
next_file (FILE *fp)
{
static char *prev_file;
char *file;
if (fp)
{
if (ferror (fp))
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
if (fp == stdin)
clearerr (fp); /* Also clear EOF. */
else if (fclose (fp) == EOF)
{
error (0, errno, "%s", prev_file);
exit_status = 1;
}
}
while ((file = *file_list++) != NULL)
{
if (file[0] == '-' && file[1] == '\0')
{
have_read_stdin = 1;
prev_file = file;
return stdin;
}
fp = fopen (file, "r");
if (fp)
{
prev_file = file;
return fp;
}
error (0, errno, "%s", file);
exit_status = 1;
}
return NULL;
}
/* Change tabs to spaces, writing to stdout.
Read each file in `file_list', in order. */
static void
expand (void)
{
FILE *fp; /* Input stream. */
int c; /* Each input character. */
int tab_index = 0; /* Index in `tab_list' of next tabstop. */
int column = 0; /* Column on screen of the next char. */
int next_tab_column; /* Column the next tab stop is on. */
int convert = 1; /* If nonzero, perform translations. */
fp = next_file ((FILE *) NULL);
if (fp == NULL)
return;
/* Binary I/O will preserve the original EOL style (DOS/Unix) of files. */
SET_BINARY2 (fileno (fp), STDOUT_FILENO);
for (;;)
{
c = getc (fp);
if (c == EOF)
{
fp = next_file (fp);
if (fp == NULL)
break; /* No more files. */
else
{
SET_BINARY2 (fileno (fp), STDOUT_FILENO);
continue;
}
}
if (c == '\n')
{
putchar (c);
tab_index = 0;
column = 0;
convert = 1;
}
else if (c == '\t' && convert)
{
if (tab_size == 0)
{
/* Do not let tab_index == first_free_tab;
stop when it is 1 less. */
while (tab_index < first_free_tab - 1
&& column >= tab_list[tab_index])
tab_index++;
next_tab_column = tab_list[tab_index];
if (tab_index < first_free_tab - 1)
tab_index++;
if (column >= next_tab_column)
next_tab_column = column + 1; /* Ran out of tab stops. */
}
else
{
next_tab_column = column + tab_size - column % tab_size;
}
while (column < next_tab_column)
{
putchar (' ');
++column;
}
}
else
{
if (convert)
{
if (c == '\b')
{
if (column > 0)
--column;
}
else
{
++column;
if (convert_entire_line == 0)
convert = 0;
}
}
putchar (c);
}
}
}
int
main (int argc, char **argv)
{
int tabval = -1; /* Value of tabstop being read, or -1. */
int c; /* Option character. */
bool obsolete_tablist = false;
have_read_stdin = 0;
exit_status = 0;
convert_entire_line = 1;
tab_list = NULL;
first_free_tab = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, NULL)) != -1)
{
switch (c)
{
case 0:
break;
case '?':
usage (EXIT_FAILURE);
case 'i':
convert_entire_line = 0;
break;
case 't':
parse_tabstops (optarg);
break;
case ',':
add_tabstop (tabval);
tabval = -1;
obsolete_tablist = true;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
if (tabval == -1)
tabval = 0;
tabval = tabval * 10 + c - '0';
obsolete_tablist = true;
break;
}
}
if (obsolete_tablist && 200112 <= posix2_version ())
{
error (0, 0, _("`-LIST' option is obsolete; use `-t LIST'"));
usage (EXIT_FAILURE);
}
add_tabstop (tabval);
validate_tabstops (tab_list, first_free_tab);
if (first_free_tab == 0)
tab_size = 8;
else if (first_free_tab == 1)
tab_size = tab_list[0];
else
tab_size = 0;
if (optind == argc)
file_list = stdin_argv;
else
file_list = &argv[optind];
expand ();
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, "-");
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+753
View File
@@ -0,0 +1,753 @@
/* expr -- evaluate expressions.
Copyright (C) 86, 1991-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Author: Mike Parker.
This program evaluates expressions. Each token (operator, operand,
parenthesis) of the expression must be a seperate argument. The
parser used is a reasonably general one, though any incarnation of
it is language-specific. It is especially nice for expressions.
No parse tree is needed; a new node is evaluated immediately.
One function can handle multiple operators all of equal precedence,
provided they all associate ((x op x) op x).
Define EVAL_TRACE to print an evaluation trace. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include <regex.h>
#include "long-options.h"
#include "error.h"
#include "closeout.h"
#include "inttostr.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "expr"
#define AUTHORS "Mike Parker"
#undef NEW
#define NEW(Type) XMALLOC (Type, 1)
#define OLD(x) free ((char *) x)
/* The kinds of value we can have. */
enum valtype
{
integer,
string
};
typedef enum valtype TYPE;
/* A value is.... */
struct valinfo
{
TYPE type; /* Which kind. */
union
{ /* The value itself. */
intmax_t i;
char *s;
} u;
};
typedef struct valinfo VALUE;
/* The arguments given to the program, minus the program name. */
static char **args;
/* The name this program was run with. */
char *program_name;
static VALUE *eval (void);
static int nomoreargs (void);
static int null (VALUE *v);
static void printv (VALUE *v);
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s EXPRESSION\n\
or: %s OPTION\n\
"),
program_name, program_name);
putchar ('\n');
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Print the value of EXPRESSION to standard output. A blank line below\n\
separates increasing precedence groups. EXPRESSION may be:\n\
\n\
ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
\n\
ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
"), stdout);
fputs (_("\
\n\
ARG1 < ARG2 ARG1 is less than ARG2\n\
ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
ARG1 = ARG2 ARG1 is equal to ARG2\n\
ARG1 != ARG2 ARG1 is unequal to ARG2\n\
ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
ARG1 > ARG2 ARG1 is greater than ARG2\n\
"), stdout);
fputs (_("\
\n\
ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
"), stdout);
fputs (_("\
\n\
ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
"), stdout);
fputs (_("\
\n\
STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
\n\
match STRING REGEXP same as STRING : REGEXP\n\
substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
index STRING CHARS index in STRING where any CHARS is found, or 0\n\
length STRING length of STRING\n\
"), stdout);
fputs (_("\
+ TOKEN interpret TOKEN as a string, even if it is a\n\
keyword like `match' or an operator like `/'\n\
\n\
( EXPRESSION ) value of EXPRESSION\n\
"), stdout);
fputs (_("\
\n\
Beware that many operators need to be escaped or quoted for shells.\n\
Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
Pattern matches return the string matched between \\( and \\) or null; if\n\
\\( and \\) are not used, they return the number of characters matched or 0.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
VALUE *v;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
/* The above handles --help and --version.
Since there is no other invocation of getopt, handle `--' here. */
if (argc > 1 && STREQ (argv[1], "--"))
{
--argc;
++argv;
}
if (argc == 1)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
args = argv + 1;
v = eval ();
if (!nomoreargs ())
error (2, 0, _("syntax error"));
printv (v);
exit (null (v));
}
/* Return a VALUE for I. */
static VALUE *
int_value (intmax_t i)
{
VALUE *v;
v = NEW (VALUE);
v->type = integer;
v->u.i = i;
return v;
}
/* Return a VALUE for S. */
static VALUE *
str_value (char *s)
{
VALUE *v;
v = NEW (VALUE);
v->type = string;
v->u.s = xstrdup (s);
return v;
}
/* Free VALUE V, including structure components. */
static void
freev (VALUE *v)
{
if (v->type == string)
free (v->u.s);
OLD (v);
}
/* Print VALUE V. */
static void
printv (VALUE *v)
{
char *p;
char buf[INT_STRLEN_BOUND (intmax_t) + 1];
switch (v->type)
{
case integer:
p = imaxtostr (v->u.i, buf);
break;
case string:
p = v->u.s;
break;
default:
abort ();
}
puts (p);
}
/* Return nonzero if V is a null-string or zero-number. */
static int
null (VALUE *v)
{
switch (v->type)
{
case integer:
return v->u.i == 0;
case string:
return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
default:
abort ();
}
}
/* Coerce V to a string value (can't fail). */
static void
tostring (VALUE *v)
{
char buf[INT_STRLEN_BOUND (intmax_t) + 1];
switch (v->type)
{
case integer:
v->u.s = xstrdup (imaxtostr (v->u.i, buf));
v->type = string;
break;
case string:
break;
default:
abort ();
}
}
/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
static int
toarith (VALUE *v)
{
intmax_t i;
int neg;
char *cp;
switch (v->type)
{
case integer:
return 1;
case string:
i = 0;
cp = v->u.s;
neg = (*cp == '-');
if (neg)
cp++;
do
{
if (ISDIGIT (*cp))
i = i * 10 + *cp - '0';
else
return 0;
}
while (*++cp);
free (v->u.s);
v->u.i = i * (neg ? -1 : 1);
v->type = integer;
return 1;
default:
abort ();
}
}
/* Return nonzero and advance if the next token matches STR exactly.
STR must not be NULL. */
static int
nextarg (char *str)
{
if (*args == NULL)
return 0;
else
{
int r = strcoll (*args, str) == 0;
args += r;
return r;
}
}
/* Return nonzero if there no more tokens. */
static int
nomoreargs (void)
{
return *args == 0;
}
#ifdef EVAL_TRACE
/* Print evaluation trace and args remaining. */
static void
trace (fxn)
char *fxn;
{
char **a;
printf ("%s:", fxn);
for (a = args; *a; a++)
printf (" %s", *a);
putchar ('\n');
}
#endif
/* Do the : operator.
SV is the VALUE for the lhs (the string),
PV is the VALUE for the rhs (the pattern). */
static VALUE *
docolon (VALUE *sv, VALUE *pv)
{
VALUE *v;
const char *errmsg;
struct re_pattern_buffer re_buffer;
struct re_registers re_regs;
size_t len;
int matchlen;
tostring (sv);
tostring (pv);
if (pv->u.s[0] == '^')
{
error (0, 0, _("\
warning: unportable BRE: `%s': using `^' as the first character\n\
of the basic regular expression is not portable; it is being ignored"),
pv->u.s);
}
len = strlen (pv->u.s);
memset (&re_buffer, 0, sizeof (re_buffer));
memset (&re_regs, 0, sizeof (re_regs));
re_buffer.allocated = 2 * len;
if (re_buffer.allocated < len)
xalloc_die ();
re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
re_buffer.translate = 0;
re_syntax_options = RE_SYNTAX_POSIX_BASIC;
errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
if (errmsg)
error (2, 0, "%s", errmsg);
matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
if (0 <= matchlen)
{
/* Were \(...\) used? */
if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
{
sv->u.s[re_regs.end[1]] = '\0';
v = str_value (sv->u.s + re_regs.start[1]);
}
else
v = int_value (matchlen);
}
else
{
/* Match failed -- return the right kind of null. */
if (re_buffer.re_nsub > 0)
v = str_value ("");
else
v = int_value (0);
}
free (re_buffer.buffer);
return v;
}
/* Handle bare operands and ( expr ) syntax. */
static VALUE *
eval7 (void)
{
VALUE *v;
#ifdef EVAL_TRACE
trace ("eval7");
#endif
if (nomoreargs ())
error (2, 0, _("syntax error"));
if (nextarg ("("))
{
v = eval ();
if (!nextarg (")"))
error (2, 0, _("syntax error"));
return v;
}
if (nextarg (")"))
error (2, 0, _("syntax error"));
return str_value (*args++);
}
/* Handle match, substr, index, and length keywords, and quoting "+". */
static VALUE *
eval6 (void)
{
VALUE *l;
VALUE *r;
VALUE *v;
VALUE *i1;
VALUE *i2;
#ifdef EVAL_TRACE
trace ("eval6");
#endif
if (nextarg ("+"))
{
if (nomoreargs ())
error (2, 0, _("syntax error"));
return str_value (*args++);
}
else if (nextarg ("length"))
{
r = eval6 ();
tostring (r);
v = int_value (strlen (r->u.s));
freev (r);
return v;
}
else if (nextarg ("match"))
{
l = eval6 ();
r = eval6 ();
v = docolon (l, r);
freev (l);
freev (r);
return v;
}
else if (nextarg ("index"))
{
l = eval6 ();
r = eval6 ();
tostring (l);
tostring (r);
v = int_value (strcspn (l->u.s, r->u.s) + 1);
if (v->u.i == strlen (l->u.s) + 1)
v->u.i = 0;
freev (l);
freev (r);
return v;
}
else if (nextarg ("substr"))
{
l = eval6 ();
i1 = eval6 ();
i2 = eval6 ();
tostring (l);
if (!toarith (i1) || !toarith (i2)
|| strlen (l->u.s) < i1->u.i
|| i1->u.i <= 0 || i2->u.i <= 0)
v = str_value ("");
else
{
v = NEW (VALUE);
v->type = string;
v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
l->u.s + i1->u.i - 1, i2->u.i);
v->u.s[i2->u.i] = 0;
}
freev (l);
freev (i1);
freev (i2);
return v;
}
else
return eval7 ();
}
/* Handle : operator (pattern matching).
Calls docolon to do the real work. */
static VALUE *
eval5 (void)
{
VALUE *l;
VALUE *r;
VALUE *v;
#ifdef EVAL_TRACE
trace ("eval5");
#endif
l = eval6 ();
while (1)
{
if (nextarg (":"))
{
r = eval6 ();
v = docolon (l, r);
freev (l);
freev (r);
l = v;
}
else
return l;
}
}
/* Handle *, /, % operators. */
static VALUE *
eval4 (void)
{
VALUE *l;
VALUE *r;
enum { multiply, divide, mod } fxn;
intmax_t val;
#ifdef EVAL_TRACE
trace ("eval4");
#endif
l = eval5 ();
while (1)
{
if (nextarg ("*"))
fxn = multiply;
else if (nextarg ("/"))
fxn = divide;
else if (nextarg ("%"))
fxn = mod;
else
return l;
r = eval5 ();
if (!toarith (l) || !toarith (r))
error (2, 0, _("non-numeric argument"));
if (fxn == multiply)
val = l->u.i * r->u.i;
else
{
if (r->u.i == 0)
error (2, 0, _("division by zero"));
val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
}
freev (l);
freev (r);
l = int_value (val);
}
}
/* Handle +, - operators. */
static VALUE *
eval3 (void)
{
VALUE *l;
VALUE *r;
enum { plus, minus } fxn;
intmax_t val;
#ifdef EVAL_TRACE
trace ("eval3");
#endif
l = eval4 ();
while (1)
{
if (nextarg ("+"))
fxn = plus;
else if (nextarg ("-"))
fxn = minus;
else
return l;
r = eval4 ();
if (!toarith (l) || !toarith (r))
error (2, 0, _("non-numeric argument"));
val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
freev (l);
freev (r);
l = int_value (val);
}
}
/* Handle comparisons. */
static VALUE *
eval2 (void)
{
VALUE *l;
VALUE *r;
enum
{
less_than, less_equal, equal, not_equal, greater_equal, greater_than
} fxn;
int val;
intmax_t lval;
intmax_t rval;
#ifdef EVAL_TRACE
trace ("eval2");
#endif
l = eval3 ();
while (1)
{
if (nextarg ("<"))
fxn = less_than;
else if (nextarg ("<="))
fxn = less_equal;
else if (nextarg ("=") || nextarg ("=="))
fxn = equal;
else if (nextarg ("!="))
fxn = not_equal;
else if (nextarg (">="))
fxn = greater_equal;
else if (nextarg (">"))
fxn = greater_than;
else
return l;
r = eval3 ();
tostring (l);
tostring (r);
lval = strcoll (l->u.s, r->u.s);
rval = 0;
if (toarith (l) && toarith (r))
{
lval = l->u.i;
rval = r->u.i;
}
switch (fxn)
{
case less_than: val = (lval < rval); break;
case less_equal: val = (lval <= rval); break;
case equal: val = (lval == rval); break;
case not_equal: val = (lval != rval); break;
case greater_equal: val = (lval >= rval); break;
case greater_than: val = (lval > rval); break;
default: abort ();
}
freev (l);
freev (r);
l = int_value (val);
}
}
/* Handle &. */
static VALUE *
eval1 (void)
{
VALUE *l;
VALUE *r;
#ifdef EVAL_TRACE
trace ("eval1");
#endif
l = eval2 ();
while (1)
{
if (nextarg ("&"))
{
r = eval2 ();
if (null (l) || null (r))
{
freev (l);
freev (r);
l = int_value (0);
}
else
freev (r);
}
else
return l;
}
}
/* Handle |. */
static VALUE *
eval (void)
{
VALUE *l;
VALUE *r;
#ifdef EVAL_TRACE
trace ("eval");
#endif
l = eval1 ();
while (1)
{
if (nextarg ("|"))
{
r = eval1 ();
if (null (l))
{
freev (l);
l = r;
}
else
freev (r);
}
else
return l;
}
}
+223
View File
@@ -0,0 +1,223 @@
/* factor -- print prime factors of n.
Copyright (C) 86, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Paul Rubin <[email protected]>.
Adapted for GNU, fixed to factor UINT_MAX by Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <assert.h>
#define NDEBUG 1
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "inttostr.h"
#include "long-options.h"
#include "readtokens.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "factor"
#define AUTHORS "Paul Rubin"
/* Token delimiters when reading from a file. */
#define DELIM "\n\t "
/* FIXME: if this program is ever modified to factor integers larger
than 2^128, this constant (and the algorithm :-) will have to change. */
#define MAX_N_FACTORS 128
/* The trial divisor increment wheel. Use it to skip over divisors that
are composites of 2, 3, 5, 7, or 11. The part from WHEEL_START up to
WHEEL_END is reused periodically, while the "lead in" is used to test
for those primes and to jump onto the wheel. For more information, see
http://www.utm.edu/research/primes/glossary/WheelFactorization.html */
#include "wheel-size.h" /* For the definition of WHEEL_SIZE. */
static const unsigned int wheel_tab[] =
{
#include "wheel.h"
};
#define WHEEL_START (wheel_tab + WHEEL_SIZE)
#define WHEEL_END (wheel_tab + (sizeof wheel_tab / sizeof wheel_tab[0]))
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [NUMBER]...\n\
or: %s OPTION\n\
"),
program_name, program_name);
fputs (_("\
Print the prime factors of each NUMBER.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Print the prime factors of all specified integer NUMBERs. If no arguments\n\
are specified on the command line, they are read from standard input.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* FIXME: comment */
static int
factor (uintmax_t n0, int max_n_factors, uintmax_t *factors)
{
register uintmax_t n = n0, d, q;
int n_factors = 0;
unsigned int const *w = wheel_tab;
if (n < 1)
return n_factors;
/* The exit condition in the following loop is correct because
any time it is tested one of these 3 conditions holds:
(1) d divides n
(2) n is prime
(3) n is composite but has no factors less than d.
If (1) or (2) obviously the right thing happens.
If (3), then since n is composite it is >= d^2. */
d = 2;
do
{
q = n / d;
while (n == q * d)
{
assert (n_factors < max_n_factors);
factors[n_factors++] = d;
n = q;
q = n / d;
}
d += *(w++);
if (w == WHEEL_END)
w = WHEEL_START;
}
while (d <= q);
if (n != 1 || n0 == 1)
{
assert (n_factors < max_n_factors);
factors[n_factors++] = n;
}
return n_factors;
}
/* FIXME: comment */
static int
print_factors (const char *s)
{
uintmax_t factors[MAX_N_FACTORS];
uintmax_t n;
int n_factors;
int i;
char buf[INT_BUFSIZE_BOUND (uintmax_t)];
if (xstrtoumax (s, NULL, 10, &n, "") != LONGINT_OK)
{
error (0, 0, _("`%s' is not a valid positive integer"), s);
return 1;
}
n_factors = factor (n, MAX_N_FACTORS, factors);
printf ("%s:", umaxtostr (n, buf));
for (i = 0; i < n_factors; i++)
printf (" %s", umaxtostr (factors[i], buf));
putchar ('\n');
return 0;
}
static int
do_stdin (void)
{
int fail = 0;
token_buffer tokenbuffer;
init_tokenbuffer (&tokenbuffer);
for (;;)
{
long int token_length;
token_length = readtoken (stdin, DELIM, sizeof (DELIM) - 1,
&tokenbuffer);
if (token_length < 0)
break;
fail |= print_factors (tokenbuffer.buffer);
}
free (tokenbuffer.buffer);
return fail;
}
int
main (int argc, char **argv)
{
int fail;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
/* The above handles --help and --version.
Since there is no other invocation of getopt, handle `--' here. */
if (argc > 1 && STREQ (argv[1], "--"))
{
--argc;
++argv;
}
fail = 0;
if (argc == 1)
fail = do_stdin ();
else
{
int i;
for (i = 1; i < argc; i++)
fail |= print_factors (argv[i]);
}
if (fail)
usage (EXIT_FAILURE);
exit (fail);
}
+71
View File
@@ -0,0 +1,71 @@
/* Exit with a status code indicating failure.
Copyright (C) 1999-2003 Free Software Foundation, Inc.
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, 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. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "version-etc.h"
#include "closeout.h"
#define PROGRAM_NAME "false"
#define AUTHORS "Jim Meyering"
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
printf (_("\
Usage: %s [ignored command line arguments]\n\
or: %s OPTION\n\
Exit with a status code indicating failure.\n\
\n\
These option names may not be abbreviated.\n\
\n\
"),
program_name, program_name);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
exit (status);
}
int
main (int argc, char **argv)
{
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
/* Recognize --help or --version only if it's the only command-line
argument and if POSIXLY_CORRECT is not set. */
if (argc == 2 && getenv ("POSIXLY_CORRECT") == NULL)
{
if (STREQ (argv[1], "--help"))
usage (EXIT_FAILURE);
if (STREQ (argv[1], "--version"))
version_etc (stdout, PROGRAM_NAME, GNU_PACKAGE, VERSION, AUTHORS);
}
exit (EXIT_FAILURE);
}
File diff suppressed because it is too large Load Diff
+319
View File
@@ -0,0 +1,319 @@
/* fold -- wrap each input line to fit in specified width.
Copyright (C) 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie, [email protected]. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "posixver.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "fold"
#define AUTHORS "David MacKenzie"
/* The name this program was run with. */
char *program_name;
/* If nonzero, try to break on whitespace. */
static int break_spaces;
/* If nonzero, count bytes, not column positions. */
static int count_bytes;
/* If nonzero, at least one of the files we read was standard input. */
static int have_read_stdin;
static struct option const longopts[] =
{
{"bytes", no_argument, NULL, 'b'},
{"spaces", no_argument, NULL, 's'},
{"width", required_argument, NULL, 'w'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Wrap input lines in each FILE (standard input by default), writing to\n\
standard output.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-b, --bytes count bytes rather than columns\n\
-s, --spaces break at spaces\n\
-w, --width=WIDTH use WIDTH columns instead of 80\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Assuming the current column is COLUMN, return the column that
printing C will move the cursor to.
The first column is 0. */
static int
adjust_column (int column, char c)
{
if (!count_bytes)
{
if (c == '\b')
{
if (column > 0)
column--;
}
else if (c == '\r')
column = 0;
else if (c == '\t')
column = column + 8 - column % 8;
else /* if (isprint (c)) */
column++;
}
else
column++;
return column;
}
/* Fold file FILENAME, or standard input if FILENAME is "-",
to stdout, with maximum line length WIDTH.
Return 0 if successful, 1 if an error occurs. */
static int
fold_file (char *filename, int width)
{
FILE *istream;
register int c;
int column = 0; /* Screen column where next char will go. */
int offset_out = 0; /* Index in `line_out' for next char. */
static char *line_out = NULL;
static int allocated_out = 0;
if (STREQ (filename, "-"))
{
istream = stdin;
have_read_stdin = 1;
}
else
istream = fopen (filename, "r");
if (istream == NULL)
{
error (0, errno, "%s", filename);
return 1;
}
while ((c = getc (istream)) != EOF)
{
if (offset_out + 1 >= allocated_out)
{
allocated_out += 1024;
line_out = xrealloc (line_out, allocated_out);
}
if (c == '\n')
{
line_out[offset_out++] = c;
fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
column = offset_out = 0;
continue;
}
rescan:
column = adjust_column (column, c);
if (column > width)
{
/* This character would make the line too long.
Print the line plus a newline, and make this character
start the next line. */
if (break_spaces)
{
/* Look for the last blank. */
int logical_end;
for (logical_end = offset_out - 1; logical_end >= 0;
logical_end--)
if (ISBLANK (line_out[logical_end]))
break;
if (logical_end >= 0)
{
int i;
/* Found a blank. Don't output the part after it. */
logical_end++;
fwrite (line_out, sizeof (char), (size_t) logical_end,
stdout);
putchar ('\n');
/* Move the remainder to the beginning of the next line.
The areas being copied here might overlap. */
memmove (line_out, line_out + logical_end,
offset_out - logical_end);
offset_out -= logical_end;
for (column = i = 0; i < offset_out; i++)
column = adjust_column (column, line_out[i]);
goto rescan;
}
}
else
{
if (offset_out == 0)
{
line_out[offset_out++] = c;
continue;
}
}
line_out[offset_out++] = '\n';
fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
column = offset_out = 0;
goto rescan;
}
line_out[offset_out++] = c;
}
if (offset_out)
fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
if (ferror (istream))
{
error (0, errno, "%s", filename);
if (!STREQ (filename, "-"))
fclose (istream);
return 1;
}
if (!STREQ (filename, "-") && fclose (istream) == EOF)
{
error (0, errno, "%s", filename);
return 1;
}
return 0;
}
int
main (int argc, char **argv)
{
int width = 80;
int i;
int optc;
int errs = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
break_spaces = count_bytes = have_read_stdin = 0;
/* Turn any numeric options into -w options. */
for (i = 1; i < argc; i++)
{
char const *a = argv[i];
if (a[0] == '-')
{
if (a[1] == '-' && ! a[2])
break;
if (ISDIGIT (a[1]))
{
char *s = xmalloc (strlen (a) + 2);
s[0] = '-';
s[1] = 'w';
strcpy (s + 2, a + 1);
argv[i] = s;
if (200112 <= posix2_version ())
{
error (0, 0, _("`%s' option is obsolete; use `%s'"), a, s);
usage (EXIT_FAILURE);
}
}
}
}
while ((optc = getopt_long (argc, argv, "bsw:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'b': /* Count bytes rather than columns. */
count_bytes = 1;
break;
case 's': /* Break at word boundaries. */
break_spaces = 1;
break;
case 'w': /* Line width. */
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0,
_("invalid number of columns: `%s'"), optarg);
width = (int) tmp_long;
}
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc == optind)
errs |= fold_file ("-", width);
else
for (i = optind; i < argc; i++)
errs |= fold_file (argv[i], width);
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, "-");
exit (errs == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
/* define the magic numbers as given by statfs(2) */
/* please send additions to [email protected] */
#if defined __linux__
# define S_MAGIC_AFFS 0xADFF
# define S_MAGIC_EXT 0x137D
# define S_MAGIC_EXT2_OLD 0xEF51
# define S_MAGIC_EXT2 0xEF53
# define S_MAGIC_HPFS 0xF995E849
# define S_MAGIC_ISOFS 0x9660
# define S_MAGIC_ISOFS_WIN 0x4000
# define S_MAGIC_ISOFS_R_WIN 0x4004
# define S_MAGIC_MINIX 0x137F
# define S_MAGIC_MINIX_30 0x138F
# define S_MAGIC_MINIX_V2 0x2468
# define S_MAGIC_MINIX_V2_30 0x2478
# define S_MAGIC_MSDOS 0x4d44
# define S_MAGIC_FAT 0x4006
# define S_MAGIC_NCP 0x564c
# define S_MAGIC_NFS 0x6969
# define S_MAGIC_PROC 0x9fa0
# define S_MAGIC_SMB 0x517B
# define S_MAGIC_XENIX 0x012FF7B4
# define S_MAGIC_SYSV4 0x012FF7B5
# define S_MAGIC_SYSV2 0x012FF7B6
# define S_MAGIC_COH 0x012FF7B7
# define S_MAGIC_UFS 0x00011954
# define S_MAGIC_XIAFS 0x012FD16D
# define S_MAGIC_NTFS 0x5346544e
# define S_MAGIC_TMPFS 0x1021994
# define S_MAGIC_REISERFS 0x52654973
# define S_MAGIC_CRAMFS 0x28cd3d45
# define S_MAGIC_ROMFS 0x7275
#elif defined __GNU__
# include <hurd/hurd_types.h>
#endif
+62
View File
@@ -0,0 +1,62 @@
#!/bin/sh
# groups -- print the groups a user is in
# Copyright (C) 1991, 1997, 2000, 2002 Free Software Foundation, Inc.
# 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, 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. */
# Written by David MacKenzie <[email protected]>.
# Make sure we get GNU id, if possible; also allow
# it to be somewhere else in PATH if not installed yet.
PATH=@bindir@:$PATH
usage="Usage: $0 [OPTION]... [USERNAME]...
--help display this help and exit
--version output version information and exit
Same as id -Gn. If no USERNAME, use current process.
Report bugs to <@PACKAGE_BUGREPORT@>."
fail=0
case $# in
1 )
case "z${1}" in
z--help )
echo "$usage" || fail=1; exit $fail;;
z--version )
echo "groups (@GNU_PACKAGE@) @VERSION@" || fail=1; exit $fail;;
* ) ;;
esac
;;
* ) ;;
esac
if [ $# -eq 0 ]; then
id -Gn
fail=$?
else
for name in "$@"; do
groups=`id -Gn -- $name`
status=$?
if test $status = 0; then
echo $name : $groups
else
fail=$status
fi
done
fi
exit $fail
+421
View File
@@ -0,0 +1,421 @@
/* head -- output first part of file(s)
Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Options: (see usage)
Reads from standard input if no files are given or when a filename of
``-'' is encountered.
By default, filename headers are printed only if more than one file
is given.
By default, prints the first 10 lines (head -n 10).
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "posixver.h"
#include "xstrtol.h"
#include "safe-read.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "head"
#define AUTHORS "David MacKenzie"
/* Number of lines/chars/blocks to head. */
#define DEFAULT_NUMBER 10
/* Size of atomic reads. */
#define BUFSIZE (512 * 8)
/* If nonzero, print filename headers. */
static int print_headers;
/* When to print the filename banners. */
enum header_mode
{
multiple_files, always, never
};
/* Options corresponding to header_mode values. */
static char const header_mode_option[][4] = { "", " -v", " -q" };
/* The name this program was run with. */
char *program_name;
/* Have we ever read standard input? */
static int have_read_stdin;
static struct option const long_options[] =
{
{"bytes", required_argument, NULL, 'c'},
{"lines", required_argument, NULL, 'n'},
{"quiet", no_argument, NULL, 'q'},
{"silent", no_argument, NULL, 'q'},
{"verbose", no_argument, NULL, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Print first 10 lines of each FILE to standard output.\n\
With more than one FILE, precede each with a header giving the file name.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-c, --bytes=SIZE print first SIZE bytes\n\
-n, --lines=NUMBER print first NUMBER lines instead of first 10\n\
"), stdout);
fputs (_("\
-q, --quiet, --silent never print headers giving file names\n\
-v, --verbose always print headers giving file names\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
static void
write_header (const char *filename)
{
static int first_file = 1;
printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
first_file = 0;
}
static int
head_bytes (const char *filename, int fd, uintmax_t bytes_to_write)
{
char buffer[BUFSIZE];
size_t bytes_to_read = BUFSIZE;
/* Need BINARY I/O for the byte counts to be accurate. */
SET_BINARY2 (fd, fileno (stdout));
while (bytes_to_write)
{
size_t bytes_read;
if (bytes_to_write < bytes_to_read)
bytes_to_read = bytes_to_write;
bytes_read = safe_read (fd, buffer, bytes_to_read);
if (bytes_read == SAFE_READ_ERROR)
{
error (0, errno, "%s", filename);
return 1;
}
if (bytes_read == 0)
break;
if (fwrite (buffer, 1, bytes_read, stdout) == 0)
error (EXIT_FAILURE, errno, _("write error"));
bytes_to_write -= bytes_read;
}
return 0;
}
static int
head_lines (const char *filename, int fd, uintmax_t lines_to_write)
{
char buffer[BUFSIZE];
/* Need BINARY I/O for the byte counts to be accurate. */
SET_BINARY2 (fd, fileno (stdout));
while (lines_to_write)
{
size_t bytes_read = safe_read (fd, buffer, BUFSIZE);
size_t bytes_to_write = 0;
if (bytes_read == SAFE_READ_ERROR)
{
error (0, errno, "%s", filename);
return 1;
}
if (bytes_read == 0)
break;
while (bytes_to_write < bytes_read)
if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
{
off_t n_bytes_past_EOL = bytes_read - bytes_to_write;
/* If we have read more data than that on the specified number
of lines, try to seek back to the position we would have
gotten to had we been reading one byte at a time. */
if (lseek (fd, -n_bytes_past_EOL, SEEK_CUR) < 0)
{
int e = errno;
struct stat st;
if (fstat (fd, &st) != 0 || S_ISREG (st.st_mode))
error (0, e, _("cannot reposition file pointer for %s"),
filename);
}
break;
}
if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
error (EXIT_FAILURE, errno, _("write error"));
}
return 0;
}
static int
head (const char *filename, int fd, uintmax_t n_units, int count_lines)
{
if (print_headers)
write_header (filename);
if (count_lines)
return head_lines (filename, fd, n_units);
else
return head_bytes (filename, fd, n_units);
}
static int
head_file (const char *filename, uintmax_t n_units, int count_lines)
{
int fd;
if (STREQ (filename, "-"))
{
have_read_stdin = 1;
return head (_("standard input"), STDIN_FILENO, n_units, count_lines);
}
else
{
fd = open (filename, O_RDONLY);
if (fd >= 0)
{
int errors;
errors = head (filename, fd, n_units, count_lines);
if (close (fd) == 0)
return errors;
}
error (0, errno, "%s", filename);
return 1;
}
}
/* Convert a string of decimal digits, N_STRING, with a single, optional suffix
character (b, k, or m) to an integral value. Upon successful conversion,
return that value. If it cannot be converted, give a diagnostic and exit.
COUNT_LINES indicates whether N_STRING is a number of bytes or a number
of lines. It is used solely to give a more specific diagnostic. */
static uintmax_t
string_to_integer (int count_lines, const char *n_string)
{
strtol_error s_err;
uintmax_t n;
s_err = xstrtoumax (n_string, NULL, 10, &n, "bkm");
if (s_err == LONGINT_OVERFLOW)
{
error (EXIT_FAILURE, 0,
_("%s: %s is so large that it is not representable"), n_string,
count_lines ? _("number of lines") : _("number of bytes"));
}
if (s_err != LONGINT_OK)
{
error (EXIT_FAILURE, 0, "%s: %s", n_string,
(count_lines
? _("invalid number of lines")
: _("invalid number of bytes")));
}
return n;
}
int
main (int argc, char **argv)
{
enum header_mode header_mode = multiple_files;
int exit_status = 0;
int c;
/* Number of items to print. */
uintmax_t n_units = DEFAULT_NUMBER;
/* If nonzero, interpret the numeric argument as the number of lines.
Otherwise, interpret it as the number of bytes. */
int count_lines = 1;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
have_read_stdin = 0;
print_headers = 0;
if (1 < argc && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
{
char *a = argv[1];
char *n_string = ++a;
char *end_n_string;
char multiplier_char = 0;
/* Old option syntax; a dash, one or more digits, and one or
more option letters. Move past the number. */
do ++a;
while (ISDIGIT (*a));
/* Pointer to the byte after the last digit. */
end_n_string = a;
/* Parse any appended option letters. */
for (; *a; a++)
{
switch (*a)
{
case 'c':
count_lines = 0;
multiplier_char = 0;
break;
case 'b':
case 'k':
case 'm':
count_lines = 0;
multiplier_char = *a;
break;
case 'l':
count_lines = 1;
break;
case 'q':
header_mode = never;
break;
case 'v':
header_mode = always;
break;
default:
error (0, 0, _("unrecognized option `-%c'"), *a);
usage (EXIT_FAILURE);
}
}
if (200112 <= posix2_version ())
{
error (0, 0, _("`-%s' option is obsolete; use `-%c %.*s%.*s%s'"),
n_string, count_lines ? 'n' : 'c',
(int) (end_n_string - n_string), n_string,
multiplier_char != 0, &multiplier_char,
header_mode_option[header_mode]);
usage (EXIT_FAILURE);
}
/* Append the multiplier character (if any) onto the end of
the digit string. Then add NUL byte if necessary. */
*end_n_string = multiplier_char;
if (multiplier_char)
*(++end_n_string) = 0;
n_units = string_to_integer (count_lines, n_string);
/* Make the options we just parsed invisible to getopt. */
argv[1] = argv[0];
argv++;
argc--;
/* FIXME: allow POSIX options if there were obsolescent ones? */
}
while ((c = getopt_long (argc, argv, "c:n:qv", long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
case 'c':
count_lines = 0;
n_units = string_to_integer (count_lines, optarg);
break;
case 'n':
count_lines = 1;
n_units = string_to_integer (count_lines, optarg);
break;
case 'q':
header_mode = never;
break;
case 'v':
header_mode = always;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (header_mode == always
|| (header_mode == multiple_files && optind < argc - 1))
print_headers = 1;
if (optind == argc)
exit_status |= head_file ("-", n_units, count_lines);
for (; optind < argc; ++optind)
exit_status |= head_file (argv[optind], n_units, count_lines);
if (have_read_stdin && close (STDIN_FILENO) < 0)
error (EXIT_FAILURE, errno, "-");
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+87
View File
@@ -0,0 +1,87 @@
/* print the hexadecimal identifier for the current host
Copyright (C) 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Jim Meyering. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "system.h"
#include "closeout.h"
#include "long-options.h"
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "hostid"
#define AUTHORS "Jim Meyering"
/* The name this program was run with, for error messages. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s\n\
or: %s OPTION\n\
Print the numeric identifier (in hexadecimal) for the current host.\n\
\n\
"),
program_name, program_name);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
long int id;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
if (argc > 1)
{
error (0, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
id = gethostid ();
printf ("%lx\n", id);
exit (EXIT_SUCCESS);
}
+127
View File
@@ -0,0 +1,127 @@
/* hostname - set or print the name of current host system
Copyright (C) 1994-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Jim Meyering <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "long-options.h"
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "hostname"
#define AUTHORS "Jim Meyering"
#if !defined(HAVE_SETHOSTNAME) && defined(HAVE_SYSINFO) && \
defined (HAVE_SYS_SYSTEMINFO_H) && defined(HAVE_LIMITS_H)
# include <sys/systeminfo.h>
int
sethostname (name, namelen)
char *name;
int namelen;
{
/* Using sysinfo() is the SVR4 mechanism to set a hostname. */
int result;
result = sysinfo (SI_SET_HOSTNAME, name, namelen);
return (result == -1 ? result : 0);
}
# define HAVE_SETHOSTNAME 1 /* Now we have it... */
#endif
char *xgethostname ();
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [NAME]\n\
or: %s OPTION\n\
Print or set the hostname of the current system.\n\
\n\
"),
program_name, program_name);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
char *hostname;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
#ifdef HAVE_SETHOSTNAME
if (argc == 2)
{
int err;
/* Set hostname to argv[1]. */
err = sethostname (argv[1], strlen (argv[1]));
if (err != 0)
error (EXIT_FAILURE, errno, _("cannot set hostname to `%s'"), argv[1]);
exit (EXIT_SUCCESS);
}
#else
if (argc == 2)
error (EXIT_FAILURE, 0,
_("cannot set hostname; this system lacks the functionality"));
#endif
if (argc == 1)
{
hostname = xgethostname ();
if (hostname == NULL)
error (EXIT_FAILURE, errno, _("cannot determine hostname"));
printf ("%s\n", hostname);
}
else
{
error (2, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}
+400
View File
@@ -0,0 +1,400 @@
/* id -- print real and effective UIDs and GIDs
Copyright (C) 1989-2003 Free Software Foundation, Inc.
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, 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. */
/* Written by Arnold Robbins.
Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <getopt.h>
#include "system.h"
#include "error.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "id"
#define AUTHORS N_ ("Arnold Robbins and David MacKenzie")
#ifndef _POSIX_VERSION
struct passwd *getpwuid ();
struct group *getgrgid ();
uid_t getuid ();
gid_t getgid ();
uid_t geteuid ();
gid_t getegid ();
#endif /* not _POSIX_VERSION */
int getugroups ();
static void print_user (uid_t uid);
static void print_group (gid_t gid);
static void print_group_list (const char *username);
static void print_full_info (const char *username);
/* The name this program was run with. */
char *program_name;
/* If nonzero, output user/group name instead of ID number. -n */
static int use_name = 0;
/* The real and effective IDs of the user to print. */
static uid_t ruid, euid;
static gid_t rgid, egid;
/* The number of errors encountered so far. */
static int problems = 0;
static struct option const longopts[] =
{
{"group", no_argument, NULL, 'g'},
{"groups", no_argument, NULL, 'G'},
{"name", no_argument, NULL, 'n'},
{"real", no_argument, NULL, 'r'},
{"user", no_argument, NULL, 'u'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name);
fputs (_("\
Print information for USERNAME, or the current user.\n\
\n\
-a ignore, for compatibility with other versions\n\
-g, --group print only the effective group ID\n\
-G, --groups print all group IDs\n\
-n, --name print a name instead of a number, for -ugG\n\
-r, --real print the real ID instead of the effective ID, with -ugG\n\
-u, --user print only the effective user ID\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Without any OPTION, print some useful set of identified information.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int optc;
/* If nonzero, output the list of all group IDs. -G */
int just_group_list = 0;
/* If nonzero, output only the group ID(s). -g */
int just_group = 0;
/* If nonzero, output real UID/GID instead of default effective UID/GID. -r */
int use_real = 0;
/* If nonzero, output only the user ID(s). -u */
int just_user = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'a':
/* Ignore -a, for compatibility with SVR4. */
break;
case 'g':
just_group = 1;
break;
case 'n':
use_name = 1;
break;
case 'r':
use_real = 1;
break;
case 'u':
just_user = 1;
break;
case 'G':
just_group_list = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (just_user + just_group + just_group_list > 1)
error (EXIT_FAILURE, 0, _("cannot print only user and only group"));
if (just_user + just_group + just_group_list == 0 && (use_real || use_name))
error (EXIT_FAILURE, 0,
_("cannot print only names or real IDs in default format"));
if (argc - optind > 1)
usage (EXIT_FAILURE);
if (argc - optind == 1)
{
struct passwd *pwd = getpwnam (argv[optind]);
if (pwd == NULL)
error (EXIT_FAILURE, 0, _("%s: No such user"), argv[optind]);
ruid = euid = pwd->pw_uid;
rgid = egid = pwd->pw_gid;
}
else
{
euid = geteuid ();
ruid = getuid ();
egid = getegid ();
rgid = getgid ();
}
if (just_user)
print_user (use_real ? ruid : euid);
else if (just_group)
print_group (use_real ? rgid : egid);
else if (just_group_list)
print_group_list (argv[optind]);
else
print_full_info (argv[optind]);
putchar ('\n');
exit (problems != 0);
}
/* Print the name or value of user ID UID. */
static void
print_user (uid_t uid)
{
struct passwd *pwd = NULL;
if (use_name)
{
pwd = getpwuid (uid);
if (pwd == NULL)
{
error (0, 0, _("cannot find name for user ID %u"), uid);
problems++;
}
}
if (pwd == NULL)
printf ("%u", (unsigned) uid);
else
printf ("%s", pwd->pw_name);
}
/* Print the name or value of group ID GID. */
static void
print_group (gid_t gid)
{
struct group *grp = NULL;
if (use_name)
{
grp = getgrgid (gid);
if (grp == NULL)
{
error (0, 0, _("cannot find name for group ID %u"), gid);
problems++;
}
}
if (grp == NULL)
printf ("%u", (unsigned) gid);
else
printf ("%s", grp->gr_name);
}
#if HAVE_GETGROUPS
/* FIXME: document */
static int
xgetgroups (const char *username, gid_t gid, int *n_groups,
GETGROUPS_T **groups)
{
int max_n_groups;
int ng;
GETGROUPS_T *g;
int fail = 0;
if (username == 0)
max_n_groups = getgroups (0, NULL);
else
max_n_groups = getugroups (0, NULL, username, gid);
/* Add 1 just in case max_n_groups is zero. */
g = (GETGROUPS_T *) xmalloc (max_n_groups * sizeof (GETGROUPS_T) + 1);
if (username == 0)
ng = getgroups (max_n_groups, g);
else
ng = getugroups (max_n_groups, g, username, gid);
if (ng < 0)
{
error (0, errno, _("cannot get supplemental group list"));
++fail;
free (groups);
}
if (!fail)
{
*n_groups = ng;
*groups = g;
}
return fail;
}
#endif /* HAVE_GETGROUPS */
/* Print all of the distinct groups the user is in. */
static void
print_group_list (const char *username)
{
struct passwd *pwd;
pwd = getpwuid (ruid);
if (pwd == NULL)
problems++;
print_group (rgid);
if (egid != rgid)
{
putchar (' ');
print_group (egid);
}
#if HAVE_GETGROUPS
{
int n_groups;
GETGROUPS_T *groups;
register int i;
if (xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
&n_groups, &groups))
{
++problems;
return;
}
for (i = 0; i < n_groups; i++)
if (groups[i] != rgid && groups[i] != egid)
{
putchar (' ');
print_group (groups[i]);
}
free (groups);
}
#endif /* HAVE_GETGROUPS */
}
/* Print all of the info about the user's user and group IDs. */
static void
print_full_info (const char *username)
{
struct passwd *pwd;
struct group *grp;
printf ("uid=%u", (unsigned) ruid);
pwd = getpwuid (ruid);
if (pwd == NULL)
problems++;
else
printf ("(%s)", pwd->pw_name);
printf (" gid=%u", (unsigned) rgid);
grp = getgrgid (rgid);
if (grp == NULL)
problems++;
else
printf ("(%s)", grp->gr_name);
if (euid != ruid)
{
printf (" euid=%u", (unsigned) euid);
pwd = getpwuid (euid);
if (pwd == NULL)
problems++;
else
printf ("(%s)", pwd->pw_name);
}
if (egid != rgid)
{
printf (" egid=%u", (unsigned) egid);
grp = getgrgid (egid);
if (grp == NULL)
problems++;
else
printf ("(%s)", grp->gr_name);
}
#if HAVE_GETGROUPS
{
int n_groups;
GETGROUPS_T *groups;
register int i;
if (xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
&n_groups, &groups))
{
++problems;
return;
}
if (n_groups > 0)
fputs (_(" groups="), stdout);
for (i = 0; i < n_groups; i++)
{
if (i > 0)
putchar (',');
printf ("%u", (unsigned) groups[i]);
grp = getgrgid (groups[i]);
if (grp == NULL)
problems++;
else
printf ("(%s)", grp->gr_name);
}
free (groups);
}
#endif /* HAVE_GETGROUPS */
}
+651
View File
@@ -0,0 +1,651 @@
/* install - copy files and set attributes
Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie <[email protected]> */
#ifdef _AIX
#pragma alloca
#endif
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include "system.h"
#include "backupfile.h"
#include "error.h"
#include "cp-hash.h"
#include "copy.h"
#include "dirname.h"
#include "makepath.h"
#include "modechange.h"
#include "path-concat.h"
#include "quote.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "install"
#define AUTHORS "David MacKenzie"
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
struct passwd *getpwnam ();
struct group *getgrnam ();
#ifndef _POSIX_VERSION
uid_t getuid ();
gid_t getgid ();
#endif
#if ! HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
#if ! HAVE_ENDPWENT
# define endpwent() ((void) 0)
#endif
/* Initial number of entries in each hash table entry's table of inodes. */
#define INITIAL_HASH_MODULE 100
/* Initial number of entries in the inode hash table. */
#define INITIAL_ENTRY_TAB_SIZE 70
/* Number of bytes of a file to copy at a time. */
#define READ_SIZE (32 * 1024)
int isdir ();
int stat ();
static int change_timestamps (const char *from, const char *to);
static int change_attributes (const char *path);
static int copy_file (const char *from, const char *to,
const struct cp_options *x);
static int install_file_to_path (const char *from, const char *to,
const struct cp_options *x);
static int install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x);
static int install_file_in_file (const char *from, const char *to,
const struct cp_options *x);
static void get_ids (void);
static void strip (const char *path);
void usage (int status);
/* The name this program was run with, for error messages. */
char *program_name;
/* The user name that will own the files, or NULL to make the owner
the current user ID. */
static char *owner_name;
/* The user ID corresponding to `owner_name'. */
static uid_t owner_id;
/* The group name that will own the files, or NULL to make the group
the current group ID. */
static char *group_name;
/* The group ID corresponding to `group_name'. */
static gid_t group_id;
/* The permissions to which the files will be set. The umask has
no effect. */
static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
/* If nonzero, strip executable files after copying them. */
static int strip_files;
/* If nonzero, install a directory instead of a regular file. */
static int dir_arg;
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
{"directory", no_argument, NULL, 'd'},
{"group", required_argument, NULL, 'g'},
{"mode", required_argument, NULL, 'm'},
{"owner", required_argument, NULL, 'o'},
{"preserve-timestamps", no_argument, NULL, 'p'},
{"strip", no_argument, NULL, 's'},
{"suffix", required_argument, NULL, 'S'},
{"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */
{"verbose", no_argument, NULL, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
static void
cp_option_init (struct cp_options *x)
{
x->copy_as_regular = 1;
x->dereference = DEREF_ALWAYS;
x->unlink_dest_before_opening = 1;
x->unlink_dest_after_failed_open = 0;
x->hard_link = 0;
x->interactive = I_UNSPECIFIED;
x->move_mode = 0;
x->myeuid = geteuid ();
x->one_file_system = 0;
x->preserve_ownership = 0;
x->preserve_links = 0;
x->preserve_mode = 0;
x->preserve_timestamps = 0;
x->require_preserve = 0;
x->recursive = 0;
x->sparse_mode = SPARSE_AUTO;
x->symbolic_link = 0;
x->backup_type = none;
/* Create destination files initially writable so we can run strip on them.
Although GNU strip works fine on read-only files, some others
would fail. */
x->set_mode = 1;
x->mode = S_IRUSR | S_IWUSR;
x->stdin_tty = 0;
x->umask_kill = 0;
x->update = 0;
x->verbose = 0;
x->xstat = stat;
x->dest_info = NULL;
x->src_info = NULL;
}
int
main (int argc, char **argv)
{
int optc;
int errors = 0;
const char *specified_mode = NULL;
int make_backups = 0;
char *backup_suffix_string;
char *version_control_string = NULL;
int mkdir_and_install = 0;
struct cp_options x;
int n_files;
char **file;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
cp_option_init (&x);
owner_name = NULL;
group_name = NULL;
strip_files = 0;
dir_arg = 0;
umask (0);
/* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options,
NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'V': /* FIXME: this is deprecated. Remove it in 2001. */
error (0, 0,
_("warning: --version-control (-V) is obsolete; support for\
it\nwill be removed in some future release. Use --backup=%s instead."
), optarg);
/* Fall through. */
case 'b':
make_backups = 1;
if (optarg)
version_control_string = optarg;
break;
case 'c':
break;
case 's':
strip_files = 1;
break;
case 'd':
dir_arg = 1;
break;
case 'D':
mkdir_and_install = 1;
break;
case 'v':
x.verbose = 1;
break;
case 'g':
group_name = optarg;
break;
case 'm':
specified_mode = optarg;
break;
case 'o':
owner_name = optarg;
break;
case 'p':
x.preserve_timestamps = 1;
break;
case 'S':
make_backups = 1;
backup_suffix_string = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
/* Check for invalid combinations of arguments. */
if (dir_arg && strip_files)
error (EXIT_FAILURE, 0,
_("the strip option may not be used when installing a directory"));
if (backup_suffix_string)
simple_backup_suffix = xstrdup (backup_suffix_string);
x.backup_type = (make_backups
? xget_version (_("backup type"),
version_control_string)
: none);
n_files = argc - optind;
file = argv + optind;
if (n_files == 0 || (n_files == 1 && !dir_arg))
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
if (specified_mode)
{
struct mode_change *change = mode_compile (specified_mode, 0);
if (change == MODE_INVALID)
error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
else if (change == MODE_MEMORY_EXHAUSTED)
xalloc_die ();
mode = mode_adjust (0, change);
}
get_ids ();
if (dir_arg)
{
int i;
for (i = 0; i < n_files; i++)
{
errors |=
make_path (file[i], mode, mode, owner_id, group_id, 0,
(x.verbose ? _("creating directory %s") : NULL));
}
}
else
{
/* FIXME: it's a little gross that this initialization is
required by copy.c::copy. */
hash_init ();
if (n_files == 2)
{
if (mkdir_and_install)
errors = install_file_to_path (file[0], file[1], &x);
else if (!isdir (file[1]))
errors = install_file_in_file (file[0], file[1], &x);
else
errors = install_file_in_dir (file[0], file[1], &x);
}
else
{
int i;
const char *dest = file[n_files - 1];
if (!isdir (dest))
{
error (0, 0,
_("installing multiple files, but last argument, %s \
is not a directory"),
quote (dest));
usage (EXIT_FAILURE);
}
dest_info_init (&x);
for (i = 0; i < n_files - 1; i++)
{
errors |= install_file_in_dir (file[i], dest, &x);
}
}
}
exit (errors);
}
/* Copy file FROM onto file TO, creating any missing parent directories of TO.
Return 0 if successful, 1 if an error occurs */
static int
install_file_to_path (const char *from, const char *to,
const struct cp_options *x)
{
char *dest_dir;
int fail = 0;
dest_dir = dir_name (to);
/* check to make sure this is a path (not install a b ) */
if (!STREQ (dest_dir, ".")
&& !isdir (dest_dir))
{
/* Someone will probably ask for a new option or three to specify
owner, group, and permissions for parent directories. Remember
that this option is intended mainly to help installers when the
distribution doesn't provide proper install rules. */
#define DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
fail = make_path (dest_dir, DIR_MODE, DIR_MODE, owner_id, group_id, 0,
(x->verbose ? _("creating directory %s") : NULL));
}
if (fail == 0)
fail = install_file_in_file (from, to, x);
free (dest_dir);
return fail;
}
/* Copy file FROM onto file TO and give TO the appropriate
attributes.
Return 0 if successful, 1 if an error occurs. */
static int
install_file_in_file (const char *from, const char *to,
const struct cp_options *x)
{
if (copy_file (from, to, x))
return 1;
if (strip_files)
strip (to);
if (change_attributes (to))
return 1;
if (x->preserve_timestamps)
return change_timestamps (from, to);
return 0;
}
/* Copy file FROM into directory TO_DIR, keeping its same name,
and give the copy the appropriate attributes.
Return 0 if successful, 1 if not. */
static int
install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x)
{
const char *from_base;
char *to;
int ret;
from_base = base_name (from);
to = path_concat (to_dir, from_base, NULL);
ret = install_file_in_file (from, to, x);
free (to);
return ret;
}
/* Copy file FROM onto file TO, creating TO if necessary.
Return 0 if the copy is successful, 1 if not. */
static int
copy_file (const char *from, const char *to, const struct cp_options *x)
{
int fail;
int nonexistent_dst = 0;
int copy_into_self;
/* Allow installing from non-regular files like /dev/null.
Charles Karney reported that some Sun version of install allows that
and that sendmail's installation process relies on the behavior. */
if (isdir (from))
{
error (0, 0, _("%s is a directory"), quote (from));
return 1;
}
fail = copy (from, to, nonexistent_dst, x, &copy_into_self, NULL);
return fail;
}
/* Set the attributes of file or directory PATH.
Return 0 if successful, 1 if not. */
static int
change_attributes (const char *path)
{
int err = 0;
/* chown must precede chmod because on some systems,
chown clears the set[ug]id bits for non-superusers,
resulting in incorrect permissions.
On System V, users can give away files with chown and then not
be able to chmod them. So don't give files away.
We don't normally ignore errors from chown because the idea of
the install command is that the file is supposed to end up with
precisely the attributes that the user specified (or defaulted).
If the file doesn't end up with the group they asked for, they'll
want to know. But AFS returns EPERM when you try to change a
file's group; thus the kludge. */
if (chown (path, owner_id, group_id)
#ifdef AFS
&& errno != EPERM
#endif
)
{
error (0, errno, "cannot change ownership of %s", quote (path));
err = 1;
}
if (!err && chmod (path, mode))
{
error (0, errno, "cannot change permissions of %s", quote (path));
err = 1;
}
return err;
}
/* Set the timestamps of file TO to match those of file FROM.
Return 0 if successful, 1 if not. */
static int
change_timestamps (const char *from, const char *to)
{
struct stat stb;
struct utimbuf utb;
if (stat (from, &stb))
{
error (0, errno, _("cannot obtain time stamps for %s"), quote (from));
return 1;
}
/* There's currently no interface to set file timestamps with
better than 1-second resolution, so discard any fractional
part of the source timestamp. */
utb.actime = stb.st_atime;
utb.modtime = stb.st_mtime;
if (utime (to, &utb))
{
error (0, errno, _("cannot set time stamps for %s"), quote (to));
return 1;
}
return 0;
}
/* Strip the symbol table from the file PATH.
We could dig the magic number out of the file first to
determine whether to strip it, but the header files and
magic numbers vary so much from system to system that making
it portable would be very difficult. Not worth the effort. */
static void
strip (const char *path)
{
int status;
pid_t pid = fork ();
switch (pid)
{
case -1:
error (EXIT_FAILURE, errno, _("fork system call failed"));
break;
case 0: /* Child. */
execlp ("strip", "strip", path, NULL);
error (EXIT_FAILURE, errno, _("cannot run strip"));
break;
default: /* Parent. */
/* Parent process. */
while (pid != wait (&status)) /* Wait for kid to finish. */
/* Do nothing. */ ;
if (status)
error (EXIT_FAILURE, 0, _("strip failed"));
break;
}
}
/* Initialize the user and group ownership of the files to install. */
static void
get_ids (void)
{
struct passwd *pw;
struct group *gr;
if (owner_name)
{
pw = getpwnam (owner_name);
if (pw == NULL)
{
unsigned long int tmp;
if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
|| UID_T_MAX < tmp)
error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
owner_id = tmp;
}
else
owner_id = pw->pw_uid;
endpwent ();
}
else
owner_id = (uid_t) -1;
if (group_name)
{
gr = getgrnam (group_name);
if (gr == NULL)
{
unsigned long int tmp;
if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
|| GID_T_MAX < tmp)
error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
group_id = tmp;
}
else
group_id = gr->gr_gid;
endgrent ();
}
else
group_id = (gid_t) -1;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... SOURCE DEST (1st format)\n\
or: %s [OPTION]... SOURCE... DIRECTORY (2nd format)\n\
or: %s -d [OPTION]... DIRECTORY... (3rd format)\n\
"),
program_name, program_name, program_name);
fputs (_("\
In the first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\
the existing DIRECTORY, while setting permission modes and owner/group.\n\
In the third format, create all components of the given DIRECTORY(ies).\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--backup[=CONTROL] make a backup of each existing destination file\n\
-b like --backup but does not accept an argument\n\
-c (ignored)\n\
-d, --directory treat all arguments as directory names; create all\n\
components of the specified directories\n\
"), stdout);
fputs (_("\
-D create all leading components of DEST except the last,\n\
then copy SOURCE to DEST; useful in the 1st format\n\
-g, --group=GROUP set group ownership, instead of process' current group\n\
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
-o, --owner=OWNER set ownership (super-user only)\n\
"), stdout);
fputs (_("\
-p, --preserve-timestamps apply access/modification times of SOURCE files\n\
to corresponding destination files\n\
-s, --strip strip symbol tables, only for 1st and 2nd formats\n\
-S, --suffix=SUFFIX override the usual backup suffix\n\
-v, --verbose print the name of each directory as it is created\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
The version control method may be selected via the --backup option or through\n\
the VERSION_CONTROL environment variable. Here are the values:\n\
\n\
"), stdout);
fputs (_("\
none, off never make backups (even if --backup is given)\n\
numbered, t make numbered backups\n\
existing, nil numbered if numbered backups exist, simple otherwise\n\
simple, never always make simple backups\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
+877
View File
@@ -0,0 +1,877 @@
/* join - join lines of two files on a common field
Copyright (C) 91, 1995-2003 Free Software Foundation, Inc.
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, 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.
Written by Mike Haertel, mike@gnu.ai.mit.edu. */
#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "hard-locale.h"
#include "linebuffer.h"
#include "memcasecmp.h"
#include "xmemcoll.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "join"
#define AUTHORS "Mike Haertel"
#define join system_join
/* Undefine, to avoid warning about redefinition on some systems. */
#undef min
#undef max
#define min(A, B) ((A) < (B) ? (A) : (B))
#define max(A, B) ((A) > (B) ? (A) : (B))
/* An element of the list identifying which fields to print for each
output line. */
struct outlist
{
/* File number: 0, 1, or 2. 0 means use the join field.
1 means use the first file argument, 2 the second. */
int file;
/* Field index (zero-based), specified only when FILE is 1 or 2. */
int field;
struct outlist *next;
};
/* A field of a line. */
struct field
{
const unsigned char *beg; /* First character in field. */
size_t len; /* The length of the field. */
};
/* A line read from an input file. */
struct line
{
struct linebuffer buf; /* The line itself. */
int nfields; /* Number of elements in `fields'. */
int nfields_allocated; /* Number of elements in `fields'. */
struct field *fields;
};
/* One or more consecutive lines read from a file that all have the
same join field value. */
struct seq
{
int count; /* Elements used in `lines'. */
int alloc; /* Elements allocated in `lines'. */
struct line *lines;
};
/* The name this program was run with. */
char *program_name;
/* Nonzero if the LC_COLLATE locale is hard. */
static int hard_LC_COLLATE;
/* If nonzero, print unpairable lines in file 1 or 2. */
static int print_unpairables_1, print_unpairables_2;
/* If nonzero, print pairable lines. */
static int print_pairables;
/* Empty output field filler. */
static char *empty_filler;
/* Field to join on. */
static int join_field_1, join_field_2;
/* List of fields to print. */
static struct outlist outlist_head;
/* Last element in `outlist', where a new element can be added. */
static struct outlist *outlist_end = &outlist_head;
/* Tab character separating fields; if this is NUL fields are separated
by any nonempty string of white space, otherwise by exactly one
tab character. */
static unsigned char tab;
/* When using getopt_long_only, no long option can start with
a character that is a short option. */
static struct option const longopts[] =
{
{"ignore-case", no_argument, NULL, 'i'},
{"j", required_argument, NULL, 'j'},
{"j1", required_argument, NULL, '1'},
{"j2", required_argument, NULL, '2'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
/* Used to print non-joining lines */
static struct line uni_blank;
/* If nonzero, ignore case when comparing join fields. */
static int ignore_case;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... FILE1 FILE2\n\
"),
program_name);
fputs (_("\
For each pair of input lines with identical join fields, write a line to\n\
standard output. The default join field is the first, delimited\n\
by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\
\n\
-a FILENUM print unpairable lines coming from file FILENUM, where\n\
FILENUM is 1 or 2, corresponding to FILE1 or FILE2\n\
-e EMPTY replace missing input fields with EMPTY\n\
"), stdout);
fputs (_("\
-i, --ignore-case ignore differences in case when comparing fields\n\
-j FIELD (obsolescent) equivalent to `-1 FIELD -2 FIELD'\n\
-j1 FIELD (obsolescent) equivalent to `-1 FIELD'\n\
-j2 FIELD (obsolescent) equivalent to `-2 FIELD'\n\
-o FORMAT obey FORMAT while constructing output line\n\
-t CHAR use CHAR as input and output field separator\n\
"), stdout);
fputs (_("\
-v FILENUM like -a FILENUM, but suppress joined output lines\n\
-1 FIELD join on this FIELD of file 1\n\
-2 FIELD join on this FIELD of file 2\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\
else fields are separated by CHAR. Any FIELD is a field number counted\n\
from 1. FORMAT is one or more comma or blank separated specifications,\n\
each being `FILENUM.FIELD' or `0'. Default FORMAT outputs the join field,\n\
the remaining fields from FILE1, the remaining fields from FILE2, all\n\
separated by CHAR.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
static void
ADD_FIELD (struct line *line, const unsigned char *field, size_t len)
{
if (line->nfields >= line->nfields_allocated)
{
line->nfields_allocated = (3 * line->nfields_allocated) / 2 + 1;
line->fields = (struct field *) xrealloc ((char *) line->fields,
(line->nfields_allocated
* sizeof (struct field)));
}
line->fields[line->nfields].beg = field;
line->fields[line->nfields].len = len;
++(line->nfields);
}
/* Fill in the `fields' structure in LINE. */
static void
xfields (struct line *line)
{
int i;
unsigned char *ptr0 = (unsigned char *) line->buf.buffer;
unsigned char *ptr;
unsigned char *lim;
ptr = ptr0;
lim = ptr0 + line->buf.length - 1;
if (!tab)
{
/* Skip leading blanks before the first field. */
while (ptr < lim && ISBLANK (*ptr))
++ptr;
}
for (i = 0; ptr < lim; ++i)
{
if (tab)
{
unsigned char *beg;
beg = ptr;
while (ptr < lim && *ptr != tab)
++ptr;
ADD_FIELD (line, beg, ptr - beg);
if (ptr < lim)
++ptr;
}
else
{
unsigned char *beg;
beg = ptr;
while (ptr < lim && !ISBLANK (*ptr))
++ptr;
ADD_FIELD (line, beg, ptr - beg);
while (ptr < lim && ISBLANK (*ptr))
++ptr;
}
}
if (ptr != ptr0 && ((!tab && ISBLANK (ptr[-1])) || ptr[-1] == tab))
{
/* Add one more (empty) field because the last character of the
line was a delimiter. */
ADD_FIELD (line, NULL, 0);
}
}
/* Read a line from FP into LINE and split it into fields.
Return 0 if EOF, 1 otherwise. */
static int
get_line (FILE *fp, struct line *line)
{
initbuffer (&line->buf);
if (! readline (&line->buf, fp))
{
free (line->buf.buffer);
line->buf.buffer = NULL;
return 0;
}
line->nfields_allocated = 0;
line->nfields = 0;
line->fields = NULL;
xfields (line);
return 1;
}
static void
freeline (struct line *line)
{
free ((char *) line->fields);
free (line->buf.buffer);
line->buf.buffer = NULL;
}
static void
initseq (struct seq *seq)
{
seq->count = 0;
seq->alloc = 1;
seq->lines = (struct line *) xmalloc (seq->alloc * sizeof (struct line));
}
/* Read a line from FP and add it to SEQ. Return 0 if EOF, 1 otherwise. */
static int
getseq (FILE *fp, struct seq *seq)
{
if (seq->count == seq->alloc)
{
seq->alloc *= 2;
seq->lines = (struct line *)
xrealloc ((char *) seq->lines, seq->alloc * sizeof (struct line));
}
if (get_line (fp, &seq->lines[seq->count]))
{
++seq->count;
return 1;
}
return 0;
}
static void
delseq (struct seq *seq)
{
int i;
for (i = 0; i < seq->count; i++)
if (seq->lines[i].buf.buffer)
freeline (&seq->lines[i]);
free ((char *) seq->lines);
}
/* Return <0 if the join field in LINE1 compares less than the one in LINE2;
>0 if it compares greater; 0 if it compares equal.
Report an error and exit if the comparison fails. */
static int
keycmp (struct line *line1, struct line *line2)
{
/* Start of field to compare in each file. */
const unsigned char *beg1, *beg2;
size_t len1, len2; /* Length of fields to compare. */
int diff;
if (join_field_1 < line1->nfields)
{
beg1 = line1->fields[join_field_1].beg;
len1 = line1->fields[join_field_1].len;
}
else
{
beg1 = NULL;
len1 = 0;
}
if (join_field_2 < line2->nfields)
{
beg2 = line2->fields[join_field_2].beg;
len2 = line2->fields[join_field_2].len;
}
else
{
beg2 = NULL;
len2 = 0;
}
if (len1 == 0)
return len2 == 0 ? 0 : -1;
if (len2 == 0)
return 1;
/* Use an if-statement here rather than a function variable to
avoid portability hassles of getting a non-conflicting declaration
of memcmp. */
if (ignore_case)
{
/* FIXME: ignore_case does not work with NLS (in particular,
with multibyte chars). */
diff = memcasecmp (beg1, beg2, min (len1, len2));
}
else
{
if (HAVE_SETLOCALE && hard_LC_COLLATE)
return xmemcoll ((char *) beg1, len1, (char *) beg2, len2);
diff = memcmp (beg1, beg2, min (len1, len2));
}
if (diff)
return diff;
return len1 < len2 ? -1 : len1 != len2;
}
/* Print field N of LINE if it exists and is nonempty, otherwise
`empty_filler' if it is nonempty. */
static void
prfield (int n, struct line *line)
{
size_t len;
if (n < line->nfields)
{
len = line->fields[n].len;
if (len)
fwrite (line->fields[n].beg, 1, len, stdout);
else if (empty_filler)
fputs (empty_filler, stdout);
}
else if (empty_filler)
fputs (empty_filler, stdout);
}
/* Print the join of LINE1 and LINE2. */
static void
prjoin (struct line *line1, struct line *line2)
{
const struct outlist *outlist;
outlist = outlist_head.next;
if (outlist)
{
const struct outlist *o;
o = outlist;
while (1)
{
int field;
struct line *line;
if (o->file == 0)
{
if (line1 == &uni_blank)
{
line = line2;
field = join_field_2;
}
else
{
line = line1;
field = join_field_1;
}
}
else
{
line = (o->file == 1 ? line1 : line2);
assert (o->field >= 0);
field = o->field;
}
prfield (field, line);
o = o->next;
if (o == NULL)
break;
putchar (tab ? tab : ' ');
}
putchar ('\n');
}
else
{
int i;
if (line1 == &uni_blank)
{
struct line *t;
t = line1;
line1 = line2;
line2 = t;
}
prfield (join_field_1, line1);
for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
{
putchar (tab ? tab : ' ');
prfield (i, line1);
}
for (i = join_field_1 + 1; i < line1->nfields; ++i)
{
putchar (tab ? tab : ' ');
prfield (i, line1);
}
for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
{
putchar (tab ? tab : ' ');
prfield (i, line2);
}
for (i = join_field_2 + 1; i < line2->nfields; ++i)
{
putchar (tab ? tab : ' ');
prfield (i, line2);
}
putchar ('\n');
}
}
/* Print the join of the files in FP1 and FP2. */
static void
join (FILE *fp1, FILE *fp2)
{
struct seq seq1, seq2;
struct line line;
int diff, i, j, eof1, eof2;
/* Read the first line of each file. */
initseq (&seq1);
getseq (fp1, &seq1);
initseq (&seq2);
getseq (fp2, &seq2);
while (seq1.count && seq2.count)
{
diff = keycmp (&seq1.lines[0], &seq2.lines[0]);
if (diff < 0)
{
if (print_unpairables_1)
prjoin (&seq1.lines[0], &uni_blank);
freeline (&seq1.lines[0]);
seq1.count = 0;
getseq (fp1, &seq1);
continue;
}
if (diff > 0)
{
if (print_unpairables_2)
prjoin (&uni_blank, &seq2.lines[0]);
freeline (&seq2.lines[0]);
seq2.count = 0;
getseq (fp2, &seq2);
continue;
}
/* Keep reading lines from file1 as long as they continue to
match the current line from file2. */
eof1 = 0;
do
if (!getseq (fp1, &seq1))
{
eof1 = 1;
++seq1.count;
break;
}
while (!keycmp (&seq1.lines[seq1.count - 1], &seq2.lines[0]));
/* Keep reading lines from file2 as long as they continue to
match the current line from file1. */
eof2 = 0;
do
if (!getseq (fp2, &seq2))
{
eof2 = 1;
++seq2.count;
break;
}
while (!keycmp (&seq1.lines[0], &seq2.lines[seq2.count - 1]));
if (print_pairables)
{
for (i = 0; i < seq1.count - 1; ++i)
for (j = 0; j < seq2.count - 1; ++j)
prjoin (&seq1.lines[i], &seq2.lines[j]);
}
for (i = 0; i < seq1.count - 1; ++i)
freeline (&seq1.lines[i]);
if (!eof1)
{
seq1.lines[0] = seq1.lines[seq1.count - 1];
seq1.count = 1;
}
else
seq1.count = 0;
for (i = 0; i < seq2.count - 1; ++i)
freeline (&seq2.lines[i]);
if (!eof2)
{
seq2.lines[0] = seq2.lines[seq2.count - 1];
seq2.count = 1;
}
else
seq2.count = 0;
}
if (print_unpairables_1 && seq1.count)
{
prjoin (&seq1.lines[0], &uni_blank);
freeline (&seq1.lines[0]);
while (get_line (fp1, &line))
{
prjoin (&line, &uni_blank);
freeline (&line);
}
}
if (print_unpairables_2 && seq2.count)
{
prjoin (&uni_blank, &seq2.lines[0]);
freeline (&seq2.lines[0]);
while (get_line (fp2, &line))
{
prjoin (&uni_blank, &line);
freeline (&line);
}
}
delseq (&seq1);
delseq (&seq2);
}
/* Add a field spec for field FIELD of file FILE to `outlist'. */
static void
add_field (int file, int field)
{
struct outlist *o;
assert (file == 0 || file == 1 || file == 2);
assert (file == 0 ? field < 0 : field >= 0);
o = (struct outlist *) xmalloc (sizeof (struct outlist));
o->file = file;
o->field = field;
o->next = NULL;
/* Add to the end of the list so the fields are in the right order. */
outlist_end->next = o;
outlist_end = o;
}
/* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX
pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based.
If S is valid, return zero. Otherwise, give a diagnostic, don't update
*FILE_INDEX or *FIELD_INDEX, and return nonzero. */
static int
decode_field_spec (const char *s, int *file_index, int *field_index)
{
int invalid = 1;
/* The first character must be 0, 1, or 2. */
switch (s[0])
{
case '0':
if (s[1] == '\0')
{
*file_index = 0;
/* Give *field_index an invalid value. */
*field_index = -1;
invalid = 0;
}
else
{
/* `0' must be all alone -- no `.FIELD'. */
error (0, 0, _("invalid field specifier: `%s'"), s);
}
break;
case '1':
case '2':
if (s[1] == '.' && s[2] != '\0')
{
strtol_error s_err;
long int tmp_long;
s_err = xstrtol (s + 2, NULL, 10, &tmp_long, "");
if (s_err != LONGINT_OK || tmp_long <= 0 || tmp_long > INT_MAX)
{
error (0, 0, _("invalid field number: `%s'"), s + 2);
}
else
{
*file_index = s[0] - '0';
/* Convert to a zero-based index. */
*field_index = (int) tmp_long - 1;
invalid = 0;
}
}
break;
default:
error (0, 0, _("invalid file number in field spec: `%s'"), s);
break;
}
return invalid;
}
/* Add the comma or blank separated field spec(s) in STR to `outlist'.
Return nonzero to indicate failure. */
static int
add_field_list (const char *c_str)
{
char *p, *str;
/* Make a writable copy of c_str. */
str = (char *) alloca (strlen (c_str) + 1);
strcpy (str, c_str);
p = str;
do
{
int invalid;
int file_index, field_index;
char *spec_item = p;
p = strpbrk (p, ", \t");
if (p)
*p++ = 0;
invalid = decode_field_spec (spec_item, &file_index, &field_index);
if (invalid)
return 1;
add_field (file_index, field_index);
uni_blank.nfields = max (uni_blank.nfields, field_index);
}
while (p);
return 0;
}
/* Create a blank line with COUNT fields separated by tabs. */
static void
make_blank (struct line *blank, int count)
{
int i;
unsigned char *buffer;
struct field *fields;
blank->nfields = count;
blank->buf.size = blank->buf.length = count + 1;
blank->buf.buffer = xmalloc (blank->buf.size);
buffer = (unsigned char *) blank->buf.buffer;
blank->fields = fields =
(struct field *) xmalloc (sizeof (struct field) * count);
for (i = 0; i < count; i++)
{
buffer[i] = '\t';
fields[i].beg = &buffer[i];
fields[i].len = 0;
}
buffer[i] = '\n';
}
int
main (int argc, char **argv)
{
char *names[2];
FILE *fp1, *fp2;
int optc, prev_optc = 0, nfiles;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
hard_LC_COLLATE = hard_locale (LC_COLLATE);
atexit (close_stdout);
/* Initialize this before parsing options. In parsing options,
it may be increased. */
uni_blank.nfields = 1;
nfiles = 0;
print_pairables = 1;
while ((optc = getopt_long_only (argc, argv, "-a:e:i1:2:o:t:v:", longopts,
NULL)) != -1)
{
long int val;
switch (optc)
{
case 0:
break;
case 'v':
print_pairables = 0;
/* Fall through. */
case 'a':
if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
|| (val != 1 && val != 2))
error (EXIT_FAILURE, 0, _("invalid field number: `%s'"), optarg);
if (val == 1)
print_unpairables_1 = 1;
else
print_unpairables_2 = 1;
break;
case 'e':
empty_filler = optarg;
break;
case 'i':
ignore_case = 1;
break;
case '1':
if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
|| val <= 0 || val > INT_MAX)
{
error (EXIT_FAILURE, 0,
_("invalid field number for file 1: `%s'"), optarg);
}
join_field_1 = (int) val - 1;
break;
case '2':
if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
|| val <= 0 || val > INT_MAX)
error (EXIT_FAILURE, 0,
_("invalid field number for file 2: `%s'"), optarg);
join_field_2 = (int) val - 1;
break;
case 'j':
if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
|| val <= 0 || val > INT_MAX)
error (EXIT_FAILURE, 0, _("invalid field number: `%s'"), optarg);
join_field_1 = join_field_2 = (int) val - 1;
break;
case 'o':
if (add_field_list (optarg))
exit (EXIT_FAILURE);
break;
case 't':
tab = *optarg;
break;
case 1: /* Non-option argument. */
if (prev_optc == 'o' && optind <= argc - 2)
{
if (add_field_list (optarg))
exit (EXIT_FAILURE);
/* Might be continuation of args to -o. */
continue; /* Don't change `prev_optc'. */
}
if (nfiles > 1)
{
error (0, 0, _("too many non-option arguments"));
usage (EXIT_FAILURE);
}
names[nfiles++] = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
prev_optc = optc;
}
/* Now that we've seen the options, we can construct the blank line
structure. */
make_blank (&uni_blank, uni_blank.nfields);
if (nfiles != 2)
{
error (0, 0, _("too few non-option arguments"));
usage (EXIT_FAILURE);
}
fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r");
if (!fp1)
error (EXIT_FAILURE, errno, "%s", names[0]);
fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r");
if (!fp2)
error (EXIT_FAILURE, errno, "%s", names[1]);
if (fp1 == fp2)
error (EXIT_FAILURE, errno, _("both files cannot be standard input"));
join (fp1, fp2);
if (fp1 != stdin && fclose (fp1) == EOF)
error (EXIT_FAILURE, errno, "%s", names[0]);
if (fp2 != stdin && fclose (fp2) == EOF)
error (EXIT_FAILURE, errno, "%s", names[1]);
if ((fp1 == stdin || fp2 == stdin) && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, "-");
exit (EXIT_SUCCESS);
}
+374
View File
@@ -0,0 +1,374 @@
/* kill -- send a signal to a process
Copyright (C) 2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Paul Eggert. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <signal.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef WIFSIGNALED
# define WIFSIGNALED(s) (((s) & 0xFFFF) - 1 < (unsigned int) 0xFF)
#endif
#ifndef WTERMSIG
# define WTERMSIG(s) ((s) & 0x7F)
#endif
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "sig2str.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "kill"
#define AUTHORS "Paul Eggert"
#if ! (HAVE_DECL_STRTOIMAX || defined strtoimax)
intmax_t strtoimax ();
#endif
#if ! (HAVE_DECL_STRSIGNAL || defined strsignal)
# if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist)
# if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist
# define sys_siglist _sys_siglist
# endif
# endif
# if HAVE_DECL_SYS_SIGLIST || defined sys_siglist
# define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \
? sys_siglist[signum] \
: 0)
# endif
# ifndef strsignal
# define strsignal(signum) 0
# endif
#endif
/* The name this program was run with, for error messages. */
char *program_name;
static char const short_options[] =
"0::1::2::3::4::5::6::7::8::9::"
"A::B::C::D::E::F::G::H::I::J::K::L::M::"
"N::O::P::Q::R::S::T::U::V::W::X::Y::Z::"
"ln:s:t";
static struct option const long_options[] =
{
{"list", no_argument, NULL, 'l'},
{"signal", required_argument, NULL, 's'},
{"table", no_argument, NULL, 't'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\
or: %s -l [SIGNAL]...\n\
or: %s -t [SIGNAL]...\n\
"),
program_name, program_name, program_name);
fputs (_("\
Send signals to processes, or list signals.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-s, --signal=SIGNAL, -SIGNAL\n\
specify the name or number of the signal to be sent\n\
-l, --list list signal names, or convert signal names to/from numbers\n\
-t, --table print a table of signal information\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\
or an exit status of a process terminated by a signal.\n\
PID is an integer; if negative it identifies a process group.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Convert OPERAND to a signal number with printable representation SIGNAME.
Return the signal number, or -1 if unsuccessful. */
static int
operand2sig (char const *operand, char *signame)
{
int signum;
if (ISDIGIT (*operand))
{
char *endp;
long int l = (errno = 0, strtol (operand, &endp, 10));
int i = l;
signum = (operand == endp || *endp || errno || i != l ? -1
: WIFSIGNALED (i) ? WTERMSIG (i)
: i);
}
else
{
/* Convert signal to upper case in the C locale, not in the
current locale. Don't assume ASCII; it might be EBCDIC. */
char *upcased = xstrdup (operand);
char *p;
for (p = upcased; *p; p++)
if (strchr ("abcdefghijklmnopqrstuvwxyz", *p))
*p += 'A' - 'a';
/* Look for the signal name, possibly prefixed by "SIG",
and possibly lowercased. */
if (! (str2sig (upcased, &signum) == 0
|| (upcased[0] == 'S' && upcased[1] == 'I' && upcased[2] == 'G'
&& str2sig (upcased + 3, &signum) == 0)))
signum = -1;
free (upcased);
}
if (signum < 0 || sig2str (signum, signame) != 0)
{
error (0, 0, _("%s: invalid signal"), operand);
return -1;
}
return signum;
}
/* Print a row of `kill -t' output. NUM_WIDTH is the maximum signal
number width, and SIGNUM is the signal number to print. The
maximum name width is NAME_WIDTH, and SIGNAME is the name to print. */
static void
print_table_row (unsigned int num_width, int signum,
unsigned int name_width, char const *signame)
{
char const *description = strsignal (signum);
printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,
description ? description : "?");
}
/* Print a list of signal names. If TABLE, print a table.
Print the names specified by ARGV if nonzero; otherwise,
print all known names. Return a suitable exit status. */
static int
list_signals (bool table, char *const *argv)
{
int signum;
int status = EXIT_SUCCESS;
char signame[SIG2STR_MAX];
if (table)
{
unsigned int name_width = 0;
/* Compute the maximum width of a signal number. */
unsigned int num_width = 1;
for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10)
num_width++;
/* Compute the maximum width of a signal name. */
for (signum = 1; signum <= SIGNUM_BOUND; signum++)
if (sig2str (signum, signame) == 0)
{
size_t len = strlen (signame);
if (name_width < len)
name_width = len;
}
if (argv)
for (; *argv; argv++)
{
signum = operand2sig (*argv, signame);
if (signum < 0)
status = EXIT_FAILURE;
else
print_table_row (num_width, signum, name_width, signame);
}
else
for (signum = 1; signum <= SIGNUM_BOUND; signum++)
if (sig2str (signum, signame) == 0)
print_table_row (num_width, signum, name_width, signame);
}
else
{
if (argv)
for (; *argv; argv++)
{
signum = operand2sig (*argv, signame);
if (signum < 0)
status = EXIT_FAILURE;
else
{
if (ISDIGIT (**argv))
puts (signame);
else
printf ("%d\n", signum);
}
}
else
for (signum = 1; signum <= SIGNUM_BOUND; signum++)
if (sig2str (signum, signame) == 0)
puts (signame);
}
return status;
}
/* Send signal SIGNUM to all the processes or process groups specified
by ARGV. Return a suitable exit status. */
static int
send_signals (int signum, char *const *argv)
{
int status = EXIT_SUCCESS;
char const *arg = *argv;
if (! arg)
{
error (0, 0, _("missing operand after `%s'"), argv[-1]);
usage (EXIT_FAILURE);
}
do
{
char *endp;
intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
pid_t pid = n;
if (errno == ERANGE || pid != n || arg == endp || *endp)
{
error (0, 0, _("%s: invalid process id"), arg);
status = EXIT_FAILURE;
}
else if (kill (pid, signum) != 0)
{
error (0, errno, "%s", arg);
status = EXIT_FAILURE;
}
}
while ((arg = *++argv));
return status;
}
int
main (int argc, char **argv)
{
int optc;
bool list = false;
bool table = false;
int signum = -1;
char signame[SIG2STR_MAX];
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
!= -1)
switch (optc)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (optind != 2)
{
/* This option is actually a process-id. */
optind--;
goto no_more_options;
}
/* Fall through. */
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
if (! optarg)
optarg = argv[optind - 1] + strlen (argv[optind - 1]);
if (optarg != argv[optind - 1] + 2)
{
error (0, 0, _("invalid option -- %c"), optc);
usage (EXIT_FAILURE);
}
optarg--;
/* Fall through. */
case 'n': /* -n is not documented, but is for Bash compatibility. */
case 's':
if (0 <= signum)
{
error (0, 0, _("%s: multiple signals specified"), optarg);
usage (EXIT_FAILURE);
}
signum = operand2sig (optarg, signame);
if (signum < 0)
usage (EXIT_FAILURE);
break;
case 't':
table = true;
/* Fall through. */
case 'l':
if (list)
{
error (0, 0, _("multiple -l or -t options specified"));
usage (EXIT_FAILURE);
}
list = true;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
no_more_options:;
if (signum < 0)
signum = SIGTERM;
else if (list)
{
error (0, 0, _("cannot combine signal with -l or -t"));
usage (EXIT_FAILURE);
}
return (list
? list_signals (table, optind == argc ? NULL : argv + optind)
: send_signals (signum, argv + optind));
}
+102
View File
@@ -0,0 +1,102 @@
/* link utility for GNU.
Copyright (C) 2001-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Michael Stone */
/* Implementation overview:
Simply call the system 'link' function */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#include "system.h"
#include "error.h"
#include "long-options.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "link"
#define AUTHORS "Michael Stone"
/* Name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s FILE1 FILE2\n\
or: %s OPTION\n"), program_name, program_name);
fputs (_("Call the link function to create a link named FILE2\
to an existing FILE1.\n\n"),
stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
/* The above handles --help and --version.
Since there is no other invocation of getopt, handle `--' here. */
if (1 < argc && STREQ (argv[1], "--"))
{
--argc;
++argv;
}
if (argc < 3)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
if (3 < argc)
{
error (0, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
if (link (argv[1], argv[2]) != 0)
error (EXIT_FAILURE, errno, _("cannot create link %s to %s"),
quote_n (0, argv[2]), quote_n (1, argv[1]));
exit (EXIT_SUCCESS);
}
+575
View File
@@ -0,0 +1,575 @@
/* `ln' program to create links between files.
Copyright (C) 86, 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Mike Parker and David MacKenzie. */
#ifdef _AIX
#pragma alloca
#endif
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "same.h"
#include "backupfile.h"
#include "dirname.h"
#include "error.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "ln"
#define AUTHORS N_ ("Mike Parker and David MacKenzie")
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
TARGET_DIRECTORY_OPTION = CHAR_MAX + 1
};
int link (); /* Some systems don't declare this anywhere. */
#ifdef S_ISLNK
int symlink ();
#endif
/* In being careful not even to try to make hard links to directories,
we have to know whether link(2) follows symlinks. If it does, then
we have to *stat* the `source' to see if the resulting link would be
to a directory. Otherwise, we have to use *lstat* so that we allow
users to make hard links to symlinks-that-point-to-directories. */
#if LINK_FOLLOWS_SYMLINKS
# define STAT_LIKE_LINK(File, Stat_buf) \
stat (File, Stat_buf)
#else
# define STAT_LIKE_LINK(File, Stat_buf) \
lstat (File, Stat_buf)
#endif
/* Construct a string NEW_DEST by concatenating DEST, a slash, and
basename(SOURCE) in alloca'd memory. Don't modify DEST or SOURCE. */
#define PATH_BASENAME_CONCAT(new_dest, dest, source) \
do \
{ \
const char *source_base; \
char *tmp_source; \
\
tmp_source = (char *) alloca (strlen ((source)) + 1); \
strcpy (tmp_source, (source)); \
strip_trailing_slashes (tmp_source); \
source_base = base_name (tmp_source); \
\
(new_dest) = (char *) alloca (strlen ((dest)) + 1 \
+ strlen (source_base) + 1); \
stpcpy (stpcpy (stpcpy ((new_dest), (dest)), "/"), source_base);\
} \
while (0)
int isdir ();
int yesno ();
/* The name by which the program was run, for error messages. */
char *program_name;
/* FIXME: document */
enum backup_type backup_type;
/* A pointer to the function used to make links. This will point to either
`link' or `symlink'. */
static int (*linkfunc) ();
/* If nonzero, make symbolic links; otherwise, make hard links. */
static int symbolic_link;
/* If nonzero, ask the user before removing existing files. */
static int interactive;
/* If nonzero, remove existing files unconditionally. */
static int remove_existing_files;
/* If nonzero, list each file as it is moved. */
static int verbose;
/* If nonzero, allow the superuser to make hard links to directories. */
static int hard_dir_link;
/* If nonzero, and the specified destination is a symbolic link to a
directory, treat it just as if it were a directory. Otherwise, the
command `ln --force --no-dereference file symlink-to-dir' deletes
symlink-to-dir before creating the new link. */
static int dereference_dest_dir_symlinks = 1;
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
{"directory", no_argument, NULL, 'F'},
{"no-dereference", no_argument, NULL, 'n'},
{"force", no_argument, NULL, 'f'},
{"interactive", no_argument, NULL, 'i'},
{"suffix", required_argument, NULL, 'S'},
{"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
{"symbolic", no_argument, NULL, 's'},
{"verbose", no_argument, NULL, 'v'},
{"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
/* Make a link DEST to the (usually) existing file SOURCE.
Symbolic links to nonexistent files are allowed.
If DEST is a directory, put the link to SOURCE in that directory.
Return 1 if there is an error, otherwise 0. */
static int
do_link (const char *source, const char *dest)
{
struct stat source_stats;
struct stat dest_stats;
char *dest_backup = NULL;
int lstat_status;
int backup_succeeded = 0;
/* Use stat here instead of lstat.
On SVR4, link does not follow symlinks, so this check disallows
making hard links to symlinks that point to directories. Big deal.
On other systems, link follows symlinks, so this check is right. */
if (!symbolic_link)
{
if (STAT_LIKE_LINK (source, &source_stats) != 0)
{
error (0, errno, _("accessing %s"), quote (source));
return 1;
}
if (S_ISLNK (source_stats.st_mode))
{
error (0, 0, _("%s: warning: making a hard link to a symbolic link\
is not portable"),
quote (source));
}
if (!hard_dir_link && S_ISDIR (source_stats.st_mode))
{
error (0, 0, _("%s: hard link not allowed for directory"),
quote (source));
return 1;
}
}
lstat_status = lstat (dest, &dest_stats);
if (lstat_status != 0 && errno != ENOENT)
{
error (0, errno, _("accessing %s"), quote (dest));
return 1;
}
/* If the destination is a directory or (it is a symlink to a directory
and the user has not specified --no-dereference), then form the
actual destination name by appending base_name (source) to the
specified destination directory. */
if ((lstat_status == 0
&& S_ISDIR (dest_stats.st_mode))
#ifdef S_ISLNK
|| (dereference_dest_dir_symlinks
&& (lstat_status == 0
&& S_ISLNK (dest_stats.st_mode)
&& isdir (dest)))
#endif
)
{
/* Target is a directory; build the full filename. */
char *new_dest;
PATH_BASENAME_CONCAT (new_dest, dest, source);
dest = new_dest;
/* Get stats for new DEST. */
lstat_status = lstat (dest, &dest_stats);
if (lstat_status != 0 && errno != ENOENT)
{
error (0, errno, _("accessing %s"), quote (dest));
return 1;
}
}
/* If --force (-f) has been specified without --backup, then before
making a link ln must remove the destination file if it exists.
(with --backup, it just renames any existing destination file)
But if the source and destination are the same, don't remove
anything and fail right here. */
if (remove_existing_files
&& lstat_status == 0
/* Allow `ln -sf --backup k k' to succeed in creating the
self-referential symlink, but don't allow the hard-linking
equivalent: `ln -f k k' (with or without --backup) to get
beyond this point, because the error message you'd get is
misleading. */
&& (backup_type == none || !symbolic_link)
&& (!symbolic_link || stat (source, &source_stats) == 0)
&& source_stats.st_dev == dest_stats.st_dev
&& source_stats.st_ino == dest_stats.st_ino
/* The following detects whether removing DEST will also remove
SOURCE. If the file has only one link then both are surely
the same link. Otherwise check whether they point to the same
name in the same directory. */
&& (source_stats.st_nlink == 1 || same_name (source, dest)))
{
error (0, 0, _("%s and %s are the same file"),
quote_n (0, source), quote_n (1, dest));
return 1;
}
if (lstat_status == 0 || lstat (dest, &dest_stats) == 0)
{
if (S_ISDIR (dest_stats.st_mode))
{
error (0, 0, _("%s: cannot overwrite directory"), quote (dest));
return 1;
}
if (interactive)
{
fprintf (stderr, _("%s: replace %s? "), program_name, quote (dest));
if (!yesno ())
return 0;
}
else if (!remove_existing_files && backup_type == none)
{
error (0, 0, _("%s: File exists"), quote (dest));
return 1;
}
if (backup_type != none)
{
char *tmp_backup = find_backup_file_name (dest, backup_type);
if (tmp_backup == NULL)
xalloc_die ();
dest_backup = (char *) alloca (strlen (tmp_backup) + 1);
strcpy (dest_backup, tmp_backup);
free (tmp_backup);
if (rename (dest, dest_backup))
{
if (errno != ENOENT)
{
error (0, errno, _("cannot backup %s"), quote (dest));
return 1;
}
else
dest_backup = NULL;
}
else
{
backup_succeeded = 1;
}
}
/* Try to unlink DEST even if we may have renamed it. In some unusual
cases (when DEST and DEST_BACKUP are hard-links that refer to the
same file), rename succeeds and DEST remains. If we didn't remove
DEST in that case, the subsequent LINKFUNC call would fail. */
if (unlink (dest) && errno != ENOENT)
{
error (0, errno, _("cannot remove %s"), quote (dest));
return 1;
}
}
else if (errno != ENOENT)
{
error (0, errno, _("accessing %s"), quote (dest));
return 1;
}
if (verbose)
{
printf ((symbolic_link
? _("create symbolic link %s to %s")
: _("create hard link %s to %s")),
quote_n (0, dest), quote_n (1, source));
if (backup_succeeded)
printf (_(" (backup: %s)"), quote (dest_backup));
putchar ('\n');
}
if ((*linkfunc) (source, dest) == 0)
{
return 0;
}
error (0, errno,
(symbolic_link
? _("creating symbolic link %s to %s")
: _("creating hard link %s to %s")),
quote_n (0, dest), quote_n (1, source));
if (dest_backup)
{
if (rename (dest_backup, dest))
error (0, errno, _("cannot un-backup %s"), quote (dest));
}
return 1;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... TARGET [LINK_NAME]\n\
or: %s [OPTION]... TARGET... DIRECTORY\n\
or: %s [OPTION]... --target-directory=DIRECTORY TARGET...\n\
"),
program_name, program_name, program_name);
fputs (_("\
Create a link to the specified TARGET with optional LINK_NAME.\n\
If LINK_NAME is omitted, a link with the same basename as the TARGET is\n\
created in the current directory. When using the second form with more\n\
than one TARGET, the last argument must be a directory; create links\n\
in DIRECTORY to each TARGET. Create hard links by default, symbolic\n\
links with --symbolic. When creating hard links, each TARGET must exist.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--backup[=CONTROL] make a backup of each existing destination file\n\
-b like --backup but does not accept an argument\n\
-d, -F, --directory hard link directories (super-user only)\n\
-f, --force remove existing destination files\n\
"), stdout);
fputs (_("\
-n, --no-dereference treat destination that is a symlink to a\n\
directory as if it were a normal file\n\
-i, --interactive prompt whether to remove destinations\n\
-s, --symbolic make symbolic links instead of hard links\n\
"), stdout);
fputs (_("\
-S, --suffix=SUFFIX override the usual backup suffix\n\
--target-directory=DIRECTORY specify the DIRECTORY in which to create\n\
the links\n\
-v, --verbose print name of each file before linking\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
The version control method may be selected via the --backup option or through\n\
the VERSION_CONTROL environment variable. Here are the values:\n\
\n\
"), stdout);
fputs (_("\
none, off never make backups (even if --backup is given)\n\
numbered, t make numbered backups\n\
existing, nil numbered if numbered backups exist, simple otherwise\n\
simple, never always make simple backups\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int c;
int errors;
int make_backups = 0;
char *backup_suffix_string;
char *version_control_string = NULL;
char *target_directory = NULL;
int target_directory_specified;
unsigned int n_files;
char **file;
int dest_is_dir;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
/* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
symbolic_link = remove_existing_files = interactive = verbose
= hard_dir_link = 0;
errors = 0;
while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL))
!= -1)
{
switch (c)
{
case 0: /* Long-named option. */
break;
case 'V': /* FIXME: this is deprecated. Remove it in 2001. */
error (0, 0,
_("warning: --version-control (-V) is obsolete; support for\
it\nwill be removed in some future release. Use --backup=%s instead."
), optarg);
/* Fall through. */
case 'b':
make_backups = 1;
if (optarg)
version_control_string = optarg;
break;
case 'd':
case 'F':
hard_dir_link = 1;
break;
case 'f':
remove_existing_files = 1;
interactive = 0;
break;
case 'i':
remove_existing_files = 0;
interactive = 1;
break;
case 'n':
dereference_dest_dir_symlinks = 0;
break;
case 's':
#ifdef S_ISLNK
symbolic_link = 1;
#else
error (EXIT_FAILURE, 0,
_("symbolic links are not supported on this system"));
#endif
break;
case TARGET_DIRECTORY_OPTION:
target_directory = optarg;
break;
case 'v':
verbose = 1;
break;
case 'S':
make_backups = 1;
backup_suffix_string = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
break;
}
}
n_files = argc - optind;
file = argv + optind;
if (n_files == 0)
{
error (0, 0, _("missing file argument"));
usage (EXIT_FAILURE);
}
target_directory_specified = (target_directory != NULL);
if (!target_directory)
target_directory = file[n_files - 1];
/* If target directory is not specified, and there's only one
file argument, then pretend `.' was given as the second argument. */
if (!target_directory_specified && n_files == 1)
{
static char *dummy[2];
dummy[0] = file[0];
dummy[1] = ".";
file = dummy;
n_files = 2;
dest_is_dir = 1;
}
else
{
dest_is_dir = isdir (target_directory);
}
if (symbolic_link)
linkfunc = symlink;
else
linkfunc = link;
if (target_directory_specified && !dest_is_dir)
{
error (0, 0, _("%s: specified target directory is not a directory"),
quote (target_directory));
usage (EXIT_FAILURE);
}
if (backup_suffix_string)
simple_backup_suffix = xstrdup (backup_suffix_string);
backup_type = (make_backups
? xget_version (_("backup type"), version_control_string)
: none);
if (target_directory_specified || n_files > 2)
{
unsigned int i;
unsigned int last_file_idx = (target_directory_specified
? n_files - 1
: n_files - 2);
if (!target_directory_specified && !dest_is_dir)
error (EXIT_FAILURE, 0,
_("when making multiple links, last argument must be a directory"));
for (i = 0; i <= last_file_idx; ++i)
errors += do_link (file[i], target_directory);
}
else
{
struct stat source_stats;
const char *source;
char *dest;
char *new_dest;
source = file[0];
dest = file[1];
/* When the destination is specified with a trailing slash and the
source exists but is not a directory, convert the user's command
`ln source dest/' to `ln source dest/basename(source)'. */
if (dest[strlen (dest) - 1] == '/'
&& lstat (source, &source_stats) == 0
&& !S_ISDIR (source_stats.st_mode))
{
PATH_BASENAME_CONCAT (new_dest, dest, source);
}
else
{
new_dest = dest;
}
errors = do_link (source, new_dest);
}
exit (errors != 0);
}
+101
View File
@@ -0,0 +1,101 @@
/* logname -- print user's login name
Copyright (C) 1990-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include "long-options.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "logname"
#define AUTHORS "FIXME: unknown"
/* The name this program was run with. */
char *program_name;
static struct option const long_options[] =
{
{0, 0, 0, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]\n"), program_name);
fputs (_("\
Print the name of the current user.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
register char *cp;
int c;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
default:
usage (EXIT_FAILURE);
}
}
if (argc - optind != 0)
usage (EXIT_FAILURE);
/* POSIX requires using getlogin (or equivalent code). */
cp = getlogin ();
if (cp)
{
puts (cp);
exit (EXIT_SUCCESS);
}
/* POSIX prohibits using a fallback technique. */
fprintf (stderr, _("%s: no login name\n"), argv[0]);
exit (EXIT_FAILURE);
}
+2
View File
@@ -0,0 +1,2 @@
#include "ls.h"
int ls_mode = LS_MULTI_COL;
+2
View File
@@ -0,0 +1,2 @@
#include "ls.h"
int ls_mode = LS_LS;
+2
View File
@@ -0,0 +1,2 @@
#include "ls.h"
int ls_mode = LS_LONG_FORMAT;
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
/* This is for the `ls' program. */
#define LS_LS 1
/* This is for the `dir' program. */
#define LS_MULTI_COL 2
/* This is for the `vdir' program. */
#define LS_LONG_FORMAT 3
extern int ls_mode;
+7
View File
@@ -0,0 +1,7 @@
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "checksum.h"
int algorithm = ALG_MD5;
+684
View File
@@ -0,0 +1,684 @@
/* Compute MD5 or SHA1 checksum of files or strings
Copyright (C) 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Ulrich Drepper <[email protected]>. */
#include <config.h>
#include <getopt.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "md5.h"
#include "sha.h"
#include "checksum.h"
#include "getline.h"
#include "closeout.h"
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME (algorithm == ALG_MD5 ? "md5sum" : "shasum")
#define AUTHORS N_ ("Ulrich Drepper and Scott Miller")
/* Most systems do not distinguish between external and internal
text representations. */
/* FIXME: This begs for an autoconf test. */
#if O_BINARY
# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT)
# define TEXT1TO1 "rb"
# define TEXTCNVT "r"
#else
# if defined VMS
# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT)
# define TEXT1TO1 "rb", "ctx=stm"
# define TEXTCNVT "r", "ctx=stm"
# else
# if UNIX || __UNIX__ || unix || __unix__ || _POSIX_VERSION
# define OPENOPTS(BINARY) "r"
# else
/* The following line is intended to evoke an error.
Using #error is not portable enough. */
"Cannot determine system type."
# endif
# endif
#endif
#define DIGEST_TYPE_STRING(Alg) ((Alg) == ALG_MD5 ? "MD5" : "SHA1")
#define DIGEST_STREAM(Alg) ((Alg) == ALG_MD5 ? md5_stream : sha_stream)
#define DIGEST_BITS(Alg) ((Alg) == ALG_MD5 ? 128 : 160)
#define DIGEST_HEX_BYTES(Alg) (DIGEST_BITS (Alg) / 4)
#define DIGEST_BIN_BYTES(Alg) (DIGEST_BITS (Alg) / 8)
#define MAX_DIGEST_BIN_BYTES MAX (DIGEST_BIN_BYTES (ALG_MD5), \
DIGEST_BIN_BYTES (ALG_SHA1))
/* The minimum length of a valid digest line. This length does
not include any newline character at the end of a line. */
#define MIN_DIGEST_LINE_LENGTH(Alg) \
(DIGEST_HEX_BYTES (Alg) /* length of hexadecimal message digest */ \
+ 2 /* blank and binary indicator */ \
+ 1 /* minimum filename length */ )
/* Nonzero if any of the files read were the standard input. */
static int have_read_stdin;
/* The minimum length of a valid checksum line for the selected algorithm. */
static size_t min_digest_line_length;
/* Set to the length of a digest hex string for the selected algorithm. */
static size_t digest_hex_bytes;
/* With --check, don't generate any output.
The exit code indicates success or failure. */
static int status_only = 0;
/* With --check, print a message to standard error warning about each
improperly formatted checksum line. */
static int warn = 0;
/* Declared and set via one of the wrapper .c files. */
/* int algorithm = ALG_UNSPECIFIED; */
/* The name this program was run with. */
char *program_name;
static const struct option long_options[] =
{
{ "binary", no_argument, 0, 'b' },
{ "check", no_argument, 0, 'c' },
{ "status", no_argument, 0, 2 },
{ "string", required_argument, 0, 1 },
{ "text", no_argument, 0, 't' },
{ "warn", no_argument, 0, 'w' },
{ GETOPT_HELP_OPTION_DECL },
{ GETOPT_VERSION_OPTION_DECL },
{ NULL, 0, NULL, 0 }
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION] [FILE]...\n\
or: %s [OPTION] --check [FILE]\n\
Print or check %s (%d-bit) checksums.\n\
With no FILE, or when FILE is -, read standard input.\n\
"),
program_name, program_name,
DIGEST_TYPE_STRING (algorithm),
DIGEST_BITS (algorithm));
printf (_("\
\n\
-b, --binary read files in binary mode (default on DOS/Windows)\n\
-c, --check check %s sums against given list\n\
-t, --text read files in text mode (default)\n\
\n\
"),
DIGEST_TYPE_STRING (algorithm));
fputs (_("\
The following two options are useful only when verifying checksums:\n\
--status don't output anything, status code shows success\n\
-w, --warn warn about improperly formated checksum lines\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\
\n\
The sums are computed as described in %s. When checking, the input\n\
should be a former output of this program. The default mode is to print\n\
a line with checksum, a character indicating type (`*' for binary, ` ' for\n\
text), and name for each FILE.\n"),
(algorithm == ALG_MD5 ? "RFC 1321" : "FIPS-180-1"));
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Split the string S (of length S_LEN) into three parts:
a hexadecimal digest, binary flag, and the file name.
S is modified. */
static int
split_3 (char *s, size_t s_len,
unsigned char **hex_digest, int *binary, char **file_name)
{
size_t i;
int escaped_filename = 0;
#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
i = 0;
while (ISWHITE (s[i]))
++i;
/* Ignore this line if it is too short.
Each line must have at least `min_digest_line_length - 1' (or one more, if
the first is a backslash) more characters to contain correct message digest
information. */
if (s_len - i < min_digest_line_length + (s[i] == '\\'))
return 1;
if (s[i] == '\\')
{
++i;
escaped_filename = 1;
}
*hex_digest = (unsigned char *) &s[i];
/* The first field has to be the n-character hexadecimal
representation of the message digest. If it is not followed
immediately by a white space it's an error. */
i += digest_hex_bytes;
if (!ISWHITE (s[i]))
return 1;
s[i++] = '\0';
if (s[i] != ' ' && s[i] != '*')
return 1;
*binary = (s[i++] == '*');
/* All characters between the type indicator and end of line are
significant -- that includes leading and trailing white space. */
*file_name = &s[i];
if (escaped_filename)
{
/* Translate each `\n' string in the file name to a NEWLINE,
and each `\\' string to a backslash. */
char *dst = &s[i];
while (i < s_len)
{
switch (s[i])
{
case '\\':
if (i == s_len - 1)
{
/* A valid line does not end with a backslash. */
return 1;
}
++i;
switch (s[i++])
{
case 'n':
*dst++ = '\n';
break;
case '\\':
*dst++ = '\\';
break;
default:
/* Only `\' or `n' may follow a backslash. */
return 1;
}
break;
case '\0':
/* The file name may not contain a NUL. */
return 1;
break;
default:
*dst++ = s[i++];
break;
}
}
*dst = '\0';
}
return 0;
}
static int
hex_digits (unsigned char const *s)
{
while (*s)
{
if (!ISXDIGIT (*s))
return 0;
++s;
}
return 1;
}
/* An interface to the function, DIGEST_STREAM,
(either md5_stream or sha_stream).
Operate on FILENAME (it may be "-") and put the result in *BIN_RESULT.
Return non-zero upon failure, zero to indicate success. */
static int
digest_file (const char *filename, int binary, unsigned char *bin_result,
int (*digest_stream)(FILE *, void *))
{
FILE *fp;
int err;
if (STREQ (filename, "-"))
{
have_read_stdin = 1;
fp = stdin;
#if O_BINARY
/* If we need binary reads from a pipe or redirected stdin, we need
to switch it to BINARY mode here, since stdin is already open. */
if (binary)
SET_BINARY (fileno (stdin));
#endif
}
else
{
/* OPENOPTS is a macro. It varies with the system.
Some systems distinguish between internal and
external text representations. */
fp = fopen (filename, OPENOPTS (binary));
if (fp == NULL)
{
error (0, errno, "%s", filename);
return 1;
}
}
err = (*digest_stream) (fp, bin_result);
if (err)
{
error (0, errno, "%s", filename);
if (fp != stdin)
fclose (fp);
return 1;
}
if (fp != stdin && fclose (fp) == EOF)
{
error (0, errno, "%s", filename);
return 1;
}
return 0;
}
static int
digest_check (const char *checkfile_name, int (*digest_stream)(FILE *, void *))
{
FILE *checkfile_stream;
int n_properly_formated_lines = 0;
int n_mismatched_checksums = 0;
int n_open_or_read_failures = 0;
unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
size_t line_number;
char *line;
size_t line_chars_allocated;
if (STREQ (checkfile_name, "-"))
{
have_read_stdin = 1;
checkfile_name = _("standard input");
checkfile_stream = stdin;
}
else
{
checkfile_stream = fopen (checkfile_name, "r");
if (checkfile_stream == NULL)
{
error (0, errno, "%s", checkfile_name);
return 1;
}
}
SET_MODE (fileno (checkfile_stream), O_TEXT);
line_number = 0;
line = NULL;
line_chars_allocated = 0;
do
{
char *filename;
int binary;
unsigned char *hex_digest;
int err;
int line_length;
++line_number;
line_length = getline (&line, &line_chars_allocated, checkfile_stream);
if (line_length <= 0)
break;
/* Ignore comment lines, which begin with a '#' character. */
if (line[0] == '#')
continue;
/* Remove any trailing newline. */
if (line[line_length - 1] == '\n')
line[--line_length] = '\0';
err = split_3 (line, line_length, &hex_digest, &binary, &filename);
if (err || !hex_digits (hex_digest))
{
if (warn)
{
error (0, 0,
_("%s: %lu: improperly formatted %s checksum line"),
checkfile_name, (unsigned long) line_number,
DIGEST_TYPE_STRING (algorithm));
}
}
else
{
static const char bin2hex[] = { '0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f' };
int fail;
++n_properly_formated_lines;
fail = digest_file (filename, binary, bin_buffer, digest_stream);
if (fail)
{
++n_open_or_read_failures;
if (!status_only)
{
printf (_("%s: FAILED open or read\n"), filename);
fflush (stdout);
}
}
else
{
size_t digest_bin_bytes = digest_hex_bytes / 2;
size_t cnt;
/* Compare generated binary number with text representation
in check file. Ignore case of hex digits. */
for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
{
if (TOLOWER (hex_digest[2 * cnt])
!= bin2hex[bin_buffer[cnt] >> 4]
|| (TOLOWER (hex_digest[2 * cnt + 1])
!= (bin2hex[bin_buffer[cnt] & 0xf])))
break;
}
if (cnt != digest_bin_bytes)
++n_mismatched_checksums;
if (!status_only)
{
printf ("%s: %s\n", filename,
(cnt != digest_bin_bytes ? _("FAILED") : _("OK")));
fflush (stdout);
}
}
}
}
while (!feof (checkfile_stream) && !ferror (checkfile_stream));
if (line)
free (line);
if (ferror (checkfile_stream))
{
error (0, 0, _("%s: read error"), checkfile_name);
return 1;
}
if (checkfile_stream != stdin && fclose (checkfile_stream) == EOF)
{
error (0, errno, "%s", checkfile_name);
return 1;
}
if (n_properly_formated_lines == 0)
{
/* Warn if no tests are found. */
error (0, 0, _("%s: no properly formatted %s checksum lines found"),
checkfile_name, DIGEST_TYPE_STRING (algorithm));
}
else
{
if (!status_only)
{
int n_computed_checkums = (n_properly_formated_lines
- n_open_or_read_failures);
if (n_open_or_read_failures > 0)
{
error (0, 0,
_("WARNING: %d of %d listed %s could not be read"),
n_open_or_read_failures, n_properly_formated_lines,
(n_properly_formated_lines == 1
? _("file") : _("files")));
}
if (n_mismatched_checksums > 0)
{
error (0, 0,
_("WARNING: %d of %d computed %s did NOT match"),
n_mismatched_checksums, n_computed_checkums,
(n_computed_checkums == 1
? _("checksum") : _("checksums")));
}
}
}
return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
&& n_open_or_read_failures == 0) ? 0 : 1);
}
int
main (int argc, char **argv)
{
unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
int do_check = 0;
int opt;
char **string = NULL;
size_t n_strings = 0;
size_t err = 0;
int file_type_specified = 0;
#if O_BINARY
/* Binary is default on MSDOS, so the actual file contents
are used in computation. */
int binary = 1;
#else
/* Text is default of the Plumb/Lankester format. */
int binary = 0;
#endif
/* Setting values of global variables. */
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
switch (opt)
{
case 0: /* long option */
break;
case 1: /* --string */
{
if (string == NULL)
string = (char **) xmalloc ((argc - 1) * sizeof (char *));
if (optarg == NULL)
optarg = "";
string[n_strings++] = optarg;
}
break;
case 'b':
file_type_specified = 1;
binary = 1;
break;
case 'c':
do_check = 1;
break;
case 2:
status_only = 1;
warn = 0;
break;
case 't':
file_type_specified = 1;
binary = 0;
break;
case 'w':
status_only = 0;
warn = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
min_digest_line_length = MIN_DIGEST_LINE_LENGTH (algorithm);
digest_hex_bytes = DIGEST_HEX_BYTES (algorithm);
if (file_type_specified && do_check)
{
error (0, 0, _("the --binary and --text options are meaningless when \
verifying checksums"));
usage (EXIT_FAILURE);
}
if (n_strings > 0 && do_check)
{
error (0, 0,
_("the --string and --check options are mutually exclusive"));
usage (EXIT_FAILURE);
}
if (status_only && !do_check)
{
error (0, 0,
_("the --status option is meaningful only when verifying checksums"));
usage (EXIT_FAILURE);
}
if (warn && !do_check)
{
error (0, 0,
_("the --warn option is meaningful only when verifying checksums"));
usage (EXIT_FAILURE);
}
if (n_strings > 0)
{
size_t i;
if (optind < argc)
{
error (0, 0, _("no files may be specified when using --string"));
usage (EXIT_FAILURE);
}
for (i = 0; i < n_strings; ++i)
{
size_t cnt;
if (algorithm == ALG_MD5)
md5_buffer (string[i], strlen (string[i]), bin_buffer);
else
sha_buffer (string[i], strlen (string[i]), bin_buffer);
for (cnt = 0; cnt < (digest_hex_bytes / 2); ++cnt)
printf ("%02x", bin_buffer[cnt]);
printf (" \"%s\"\n", string[i]);
}
}
else if (do_check)
{
if (optind + 1 < argc)
{
error (0, 0,
_("only one argument may be specified when using --check"));
usage (EXIT_FAILURE);
}
err = digest_check ((optind == argc) ? "-" : argv[optind],
DIGEST_STREAM (algorithm));
}
else
{
if (optind == argc)
argv[argc++] = "-";
for (; optind < argc; ++optind)
{
int fail;
char *file = argv[optind];
fail = digest_file (file, binary, bin_buffer,
DIGEST_STREAM (algorithm));
err |= fail;
if (!fail)
{
size_t i;
/* Output a leading backslash if the file name contains
a newline or backslash. */
if (strchr (file, '\n') || strchr (file, '\\'))
putchar ('\\');
for (i = 0; i < (digest_hex_bytes / 2); ++i)
printf ("%02x", bin_buffer[i]);
putchar (' ');
if (binary)
putchar ('*');
else
putchar (' ');
/* Translate each NEWLINE byte to the string, "\\n",
and each backslash to "\\\\". */
for (i = 0; i < strlen (file); ++i)
{
switch (file[i])
{
case '\n':
fputs ("\\n", stdout);
break;
case '\\':
fputs ("\\\\", stdout);
break;
default:
putchar (file[i]);
break;
}
}
putchar ('\n');
}
}
}
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, _("standard input"));
exit (err == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+200
View File
@@ -0,0 +1,200 @@
/* mkdir -- make directories
Copyright (C) 90, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* David MacKenzie <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "dirname.h"
#include "error.h"
#include "makepath.h"
#include "modechange.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "mkdir"
#define AUTHORS "David MacKenzie"
/* The name this program was run with. */
char *program_name;
/* If nonzero, ensure that all parents of the specified directory exist. */
static int create_parents;
static struct option const longopts[] =
{
{"mode", required_argument, NULL, 'm'},
{"parents", no_argument, NULL, 'p'},
{"verbose", no_argument, NULL, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION] DIRECTORY...\n"), program_name);
fputs (_("\
Create the DIRECTORY(ies), if they do not already exist.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-m, --mode=MODE set permission mode (as in chmod), not rwxrwxrwx - umask\n\
-p, --parents no error if existing, make parent directories as needed\n\
-v, --verbose print a message for each created directory\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
mode_t newmode;
mode_t parent_mode;
const char *specified_mode = NULL;
const char *verbose_fmt_string = NULL;
int errors = 0;
int optc;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
create_parents = 0;
while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1)
{
switch (optc)
{
case 0: /* Long option. */
break;
case 'p':
create_parents = 1;
break;
case 'm':
specified_mode = optarg;
break;
case 'v': /* --verbose */
verbose_fmt_string = _("created directory %s");
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
newmode = S_IRWXUGO;
{
mode_t umask_value = umask (0);
umask (umask_value); /* Restore the old value. */
parent_mode = (newmode & (~ umask_value)) | S_IWUSR | S_IXUSR;
}
if (specified_mode)
{
struct mode_change *change = mode_compile (specified_mode, 0);
newmode &= ~ umask (0);
if (change == MODE_INVALID)
error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
else if (change == MODE_MEMORY_EXHAUSTED)
xalloc_die ();
newmode = mode_adjust (newmode, change);
}
for (; optind < argc; ++optind)
{
int fail = 0;
if (create_parents)
{
char *dir = argv[optind];
fail = make_path (dir, newmode, parent_mode,
-1, -1, 1, verbose_fmt_string);
}
else
{
const char *dir = argv[optind];
int dir_created;
fail = make_dir (dir, dir, newmode, &dir_created);
if (fail)
{
/* make_dir already gave a diagnostic. */
}
else if (!create_parents && !dir_created)
{
/* make_dir `succeeds' when DIR already exists.
In that case, mkdir must fail, unless --parents (-p)
was specified. */
error (0, EEXIST, _("cannot create directory %s"),
quote (dir));
fail = 1;
}
else if (verbose_fmt_string)
error (0, 0, verbose_fmt_string, quote (dir));
/* mkdir(2) is required to honor only the file permission bits.
In particular, it needn't do anything about `special' bits,
so if any were set in newmode, apply them with chmod.
This extra step is necessary in some cases when the containing
directory has a default ACL. */
/* Set the permissions only if this directory has just
been created. */
if (fail == 0 && specified_mode && dir_created)
{
fail = chmod (dir, newmode);
if (fail)
error (0, errno, _("cannot set permissions of directory %s"),
quote (dir));
}
}
if (fail)
errors = 1;
}
exit (errors);
}
+152
View File
@@ -0,0 +1,152 @@
/* mkfifo -- make fifo's (named pipes)
Copyright (C) 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* David MacKenzie <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "error.h"
#include "modechange.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "mkfifo"
#define AUTHORS "David MacKenzie"
/* The name this program was run with. */
char *program_name;
static struct option const longopts[] =
{
{"mode", required_argument, NULL, 'm'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
#ifdef S_ISFIFO
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION] NAME...\n"), program_name);
fputs (_("\
Create named pipes (FIFOs) with the given NAMEs.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
#endif
int
main (int argc, char **argv)
{
mode_t newmode;
struct mode_change *change;
const char *specified_mode;
int errors = 0;
int optc;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
specified_mode = NULL;
#ifndef S_ISFIFO
error (4, 0, _("fifo files not supported"));
#else
while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'm':
specified_mode = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (specified_mode)
{
newmode &= ~ umask (0);
change = mode_compile (specified_mode, 0);
if (change == MODE_INVALID)
error (EXIT_FAILURE, 0, _("invalid mode"));
else if (change == MODE_MEMORY_EXHAUSTED)
xalloc_die ();
newmode = mode_adjust (newmode, change);
}
for (; optind < argc; ++optind)
{
int fail = mkfifo (argv[optind], newmode);
if (fail)
error (0, errno, _("cannot create fifo %s"), quote (argv[optind]));
/* If the containing directory happens to have a default ACL, chmod
ensures the file mode permission bits are still set as desired. */
if (fail == 0 && specified_mode)
{
fail = chmod (argv[optind], newmode);
if (fail)
error (0, errno, _("cannot set permissions of fifo %s"),
quote (argv[optind]));
}
if (fail)
errors = 1;
}
exit (errors);
#endif
}
+236
View File
@@ -0,0 +1,236 @@
/* mknod -- make special files
Copyright (C) 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by David MacKenzie <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "error.h"
#include "modechange.h"
#include "quote.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "mknod"
#define AUTHORS "David MacKenzie"
/* The name this program was run with. */
char *program_name;
static struct option const longopts[] =
{
{"mode", required_argument, NULL, 'm'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"),
program_name);
fputs (_("\
Create the special file NAME of the given TYPE.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they\n\
must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X,\n\
it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;\n\
otherwise, as decimal. TYPE may be:\n\
"), stdout);
fputs (_("\
\n\
b create a block (buffered) special file\n\
c, u create a character (unbuffered) special file\n\
p create a FIFO\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
mode_t newmode;
struct mode_change *change;
const char *specified_mode;
int optc;
mode_t node_type;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
specified_mode = NULL;
while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'm':
specified_mode = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (specified_mode)
{
newmode &= ~ umask (0);
change = mode_compile (specified_mode, 0);
if (change == MODE_INVALID)
error (EXIT_FAILURE, 0, _("invalid mode"));
else if (change == MODE_MEMORY_EXHAUSTED)
xalloc_die ();
newmode = mode_adjust (newmode, change);
}
if (argc - optind != 2 && argc - optind != 4)
{
const char *msg;
if (argc - optind < 2)
msg = _("too few arguments");
else if (argc - optind > 4)
msg = _("too many arguments");
else
msg = _("wrong number of arguments");
error (0, 0, "%s", msg);
usage (EXIT_FAILURE);
}
/* Only check the first character, to allow mnemonic usage like
`mknod /dev/rst0 character 18 0'. */
switch (argv[optind + 1][0])
{
case 'b': /* `block' or `buffered' */
#ifndef S_IFBLK
error (4, 0, _("block special files not supported"));
#else
node_type = S_IFBLK;
#endif
goto block_or_character;
case 'c': /* `character' */
case 'u': /* `unbuffered' */
#ifndef S_IFCHR
error (4, 0, _("character special files not supported"));
#else
node_type = S_IFCHR;
#endif
goto block_or_character;
block_or_character:
if (argc - optind != 4)
{
error (0, 0, _("\
when creating special files, major and minor device\n\
numbers must be specified"));
usage (EXIT_FAILURE);
}
{
char const *s_major = argv[optind + 2];
char const *s_minor = argv[optind + 3];
uintmax_t i_major, i_minor;
dev_t device;
if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK
|| i_major != (major_t) i_major)
error (EXIT_FAILURE, 0,
_("invalid major device number %s"), quote (s_major));
if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK
|| i_minor != (minor_t) i_minor)
error (EXIT_FAILURE, 0,
_("invalid minor device number %s"), quote (s_minor));
device = makedev (i_major, i_minor);
#ifdef NODEV
if (device == NODEV)
error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor);
#endif
if (mknod (argv[optind], newmode | node_type, device) != 0)
error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
}
break;
case 'p': /* `pipe' */
#ifndef S_ISFIFO
error (4, 0, _("fifo files not supported"));
#else
if (argc - optind != 2)
{
error (0, 0, _("\
major and minor device numbers may not be specified for fifo files"));
usage (EXIT_FAILURE);
}
if (mkfifo (argv[optind], newmode))
error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
#endif
break;
default:
error (0, 0, "invalid device type %s", quote (argv[optind + 1]));
usage (EXIT_FAILURE);
}
/* Perform an explicit chmod to ensure the file mode permission bits
are set as specified. This extra step is necessary in some cases
when the containing directory has a default ACL. */
if (specified_mode)
{
if (chmod (argv[optind], newmode))
error (0, errno, _("cannot set permissions of %s"),
quote (argv[optind]));
}
exit (EXIT_SUCCESS);
}
+505
View File
@@ -0,0 +1,505 @@
/* mv -- move or rename files
Copyright (C) 86, 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Mike Parker, David MacKenzie, and Jim Meyering */
#ifdef _AIX
#pragma alloca
#endif
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#include "system.h"
#include "argmatch.h"
#include "backupfile.h"
#include "copy.h"
#include "cp-hash.h"
#include "dirname.h"
#include "error.h"
#include "path-concat.h"
#include "quote.h"
#include "remove.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "mv"
#define AUTHORS N_ ("Mike Parker, David MacKenzie, and Jim Meyering")
/* Initial number of entries in each hash table entry's table of inodes. */
#define INITIAL_HASH_MODULE 100
/* Initial number of entries in the inode hash table. */
#define INITIAL_ENTRY_TAB_SIZE 70
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
TARGET_DIRECTORY_OPTION = CHAR_MAX + 1,
STRIP_TRAILING_SLASHES_OPTION,
REPLY_OPTION
};
int isdir ();
int lstat ();
/* The name this program was run with. */
char *program_name;
/* Remove any trailing slashes from each SOURCE argument. */
static int remove_trailing_slashes;
/* Valid arguments to the `--reply' option. */
static char const* const reply_args[] =
{
"yes", "no", "query", 0
};
/* The values that correspond to the above strings. */
static int const reply_vals[] =
{
I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER
};
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
{"force", no_argument, NULL, 'f'},
{"interactive", no_argument, NULL, 'i'},
{"reply", required_argument, NULL, REPLY_OPTION},
{"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
{"suffix", required_argument, NULL, 'S'},
{"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
{"update", no_argument, NULL, 'u'},
{"verbose", no_argument, NULL, 'v'},
{"version-control", required_argument, NULL, 'V'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
static void
rm_option_init (struct rm_options *x)
{
x->unlink_dirs = 0;
x->ignore_missing_files = 0;
x->recursive = 1;
/* Should we prompt for removal, too? No. Prompting for the `move'
part is enough. It implies removal. */
x->interactive = 0;
x->stdin_tty = 0;
x->verbose = 0;
}
static void
cp_option_init (struct cp_options *x)
{
x->copy_as_regular = 0; /* FIXME: maybe make this an option */
x->dereference = DEREF_NEVER;
x->unlink_dest_before_opening = 0;
x->unlink_dest_after_failed_open = 0;
x->hard_link = 0;
x->interactive = I_UNSPECIFIED;
x->move_mode = 1;
x->myeuid = geteuid ();
x->one_file_system = 0;
x->preserve_ownership = 1;
x->preserve_links = 1;
x->preserve_mode = 1;
x->preserve_timestamps = 1;
x->require_preserve = 0; /* FIXME: maybe make this an option */
x->recursive = 1;
x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */
x->symbolic_link = 0;
x->set_mode = 0;
x->mode = 0;
x->stdin_tty = isatty (STDIN_FILENO);
/* Find out the current file creation mask, to knock the right bits
when using chmod. The creation mask is set to be liberal, so
that created directories can be written, even if it would not
have been allowed with the mask this process was started with. */
x->umask_kill = ~ umask (0);
x->update = 0;
x->verbose = 0;
x->xstat = lstat;
x->dest_info = NULL;
x->src_info = NULL;
}
/* If PATH is an existing directory, return nonzero, else 0. */
static int
is_real_dir (const char *path)
{
struct stat stats;
return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
}
/* Move SOURCE onto DEST. Handles cross-filesystem moves.
If SOURCE is a directory, DEST must not exist.
Return 0 if successful, non-zero if an error occurred. */
static int
do_move (const char *source, const char *dest, const struct cp_options *x)
{
static int first = 1;
int copy_into_self;
int rename_succeeded;
int fail;
if (first)
{
first = 0;
/* Allocate space for remembering copied and created files. */
hash_init ();
}
fail = copy (source, dest, 0, x, &copy_into_self, &rename_succeeded);
if (!fail)
{
char const *dir_to_remove;
if (copy_into_self)
{
/* In general, when copy returns with copy_into_self set, SOURCE is
the same as, or a parent of DEST. In this case we know it's a
parent. It doesn't make sense to move a directory into itself, and
besides in some situations doing so would give highly nonintuitive
results. Run this `mkdir b; touch a c; mv * b' in an empty
directory. Here's the result of running echo `find b -print`:
b b/a b/b b/b/a b/c. Notice that only file `a' was copied
into b/b. Handle this by giving a diagnostic, removing the
copied-into-self directory, DEST (`b/b' in the example),
and failing. */
dir_to_remove = NULL;
fail = 1;
}
else if (rename_succeeded)
{
/* No need to remove anything. SOURCE was successfully
renamed to DEST. Or the user declined to rename a file. */
dir_to_remove = NULL;
}
else
{
/* This may mean SOURCE and DEST referred to different devices.
It may also conceivably mean that even though they referred
to the same device, rename wasn't implemented for that device.
E.g., (from Joel N. Weber),
[...] there might someday be cases where you can't rename
but you can copy where the device name is the same, especially
on Hurd. Consider an ftpfs with a primitive ftp server that
supports uploading, downloading and deleting, but not renaming.
Also, note that comparing device numbers is not a reliable
check for `can-rename'. Some systems can be set up so that
files from many different physical devices all have the same
st_dev field. This is a feature of some NFS mounting
configurations.
We reach this point if SOURCE has been successfully copied
to DEST. Now we have to remove SOURCE.
This function used to resort to copying only when rename
failed and set errno to EXDEV. */
dir_to_remove = source;
}
if (dir_to_remove != NULL)
{
struct rm_options rm_options;
enum RM_status status;
rm_option_init (&rm_options);
rm_options.verbose = x->verbose;
status = rm (1, &dir_to_remove, &rm_options);
assert (VALID_STATUS (status));
if (status == RM_ERROR)
fail = 1;
}
}
return fail;
}
/* Move file SOURCE onto DEST. Handles the case when DEST is a directory.
DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a
directory and zero otherwise.
Return 0 if successful, non-zero if an error occurred. */
static int
movefile (char *source, char *dest, int dest_is_dir,
const struct cp_options *x)
{
int dest_had_trailing_slash = strip_trailing_slashes (dest);
int fail;
/* This code was introduced to handle the ambiguity in the semantics
of mv that is induced by the varying semantics of the rename function.
Some systems (e.g., Linux) have a rename function that honors a
trailing slash, while others (like Solaris 5,6,7) have a rename
function that ignores a trailing slash. I believe the Linux
rename semantics are POSIX and susv2 compliant. */
if (remove_trailing_slashes)
strip_trailing_slashes (source);
/* In addition to when DEST is a directory, if DEST has a trailing
slash and neither SOURCE nor DEST is a directory, presume the target
is DEST/`basename source`. This converts `mv x y/' to `mv x y/x'.
This change means that the command `mv any file/' will now fail
rather than performing the move. The case when SOURCE is a
directory and DEST is not is properly diagnosed by do_move. */
if (dest_is_dir || (dest_had_trailing_slash && !is_real_dir (source)))
{
/* DEST is a directory; build full target filename. */
char const *src_basename = base_name (source);
char *new_dest = path_concat (dest, src_basename, NULL);
if (new_dest == NULL)
xalloc_die ();
strip_trailing_slashes (new_dest);
fail = do_move (source, new_dest, x);
free (new_dest);
}
else
{
fail = do_move (source, dest, x);
}
return fail;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... SOURCE DEST\n\
or: %s [OPTION]... SOURCE... DIRECTORY\n\
or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\
"),
program_name, program_name, program_name);
fputs (_("\
Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--backup[=CONTROL] make a backup of each existing destination file\n\
-b like --backup but does not accept an argument\n\
-f, --force do not prompt before overwriting\n\
equivalent to --reply=yes\n\
-i, --interactive prompt before overwrite\n\
equivalent to --reply=query\n\
"), stdout);
fputs (_("\
--reply={yes,no,query} specify how to handle the prompt about an\n\
existing destination file\n\
--strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
argument\n\
-S, --suffix=SUFFIX override the usual backup suffix\n\
"), stdout);
fputs (_("\
--target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\
-u, --update move only when the SOURCE file is newer\n\
than the destination file or when the\n\
destination file is missing\n\
-v, --verbose explain what is being done\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
The version control method may be selected via the --backup option or through\n\
the VERSION_CONTROL environment variable. Here are the values:\n\
\n\
"), stdout);
fputs (_("\
none, off never make backups (even if --backup is given)\n\
numbered, t make numbered backups\n\
existing, nil numbered if numbered backups exist, simple otherwise\n\
simple, never always make simple backups\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int c;
int errors;
int make_backups = 0;
int dest_is_dir;
char *backup_suffix_string;
char *version_control_string = NULL;
struct cp_options x;
char *target_directory = NULL;
int target_directory_specified;
unsigned int n_files;
char **file;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
cp_option_init (&x);
/* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
errors = 0;
while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
case 'V': /* FIXME: this is deprecated. Remove it in 2001. */
error (0, 0,
_("warning: --version-control (-V) is obsolete; support for\
it\nwill be removed in some future release. Use --backup=%s instead."
), optarg);
/* Fall through. */
case 'b':
make_backups = 1;
if (optarg)
version_control_string = optarg;
break;
case 'f':
x.interactive = I_ALWAYS_YES;
break;
case 'i':
x.interactive = I_ASK_USER;
break;
case REPLY_OPTION:
x.interactive = XARGMATCH ("--reply", optarg,
reply_args, reply_vals);
break;
case STRIP_TRAILING_SLASHES_OPTION:
remove_trailing_slashes = 1;
break;
case TARGET_DIRECTORY_OPTION:
target_directory = optarg;
break;
case 'u':
x.update = 1;
break;
case 'v':
x.verbose = 1;
break;
case 'S':
make_backups = 1;
backup_suffix_string = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
n_files = argc - optind;
file = argv + optind;
target_directory_specified = (target_directory != NULL);
if (target_directory == NULL && n_files != 0)
target_directory = file[n_files - 1];
dest_is_dir = (n_files > 0 && isdir (target_directory));
if (n_files == 0 || (n_files == 1 && !target_directory_specified))
{
error (0, 0, _("missing file argument"));
usage (EXIT_FAILURE);
}
if (target_directory_specified)
{
if (!dest_is_dir)
{
error (0, 0, _("specified target, %s is not a directory"),
quote (target_directory));
usage (EXIT_FAILURE);
}
}
else if (n_files > 2 && !dest_is_dir)
{
error (0, 0,
_("when moving multiple files, last argument must be a directory"));
usage (EXIT_FAILURE);
}
if (backup_suffix_string)
simple_backup_suffix = xstrdup (backup_suffix_string);
x.backup_type = (make_backups
? xget_version (_("backup type"),
version_control_string)
: none);
/* Move each arg but the last into the target_directory. */
{
unsigned int last_file_idx = (target_directory_specified
? n_files - 1
: n_files - 2);
unsigned int i;
/* Initialize the hash table only if we'll need it.
The problem it is used to detect can arise only if there are
two or more files to move. */
if (last_file_idx)
dest_info_init (&x);
for (i = 0; i <= last_file_idx; ++i)
errors |= movefile (file[i], target_directory, dest_is_dir, &x);
}
exit (errors);
}
+201
View File
@@ -0,0 +1,201 @@
/* nice -- run a program with modified scheduling priority
Copyright (C) 1990-2002 Free Software Foundation, Inc.
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, 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. */
/* David MacKenzie <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <getopt.h>
#include <sys/types.h>
#ifndef NICE_PRIORITY
# include <sys/time.h>
# include <sys/resource.h>
#endif
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "long-options.h"
#include "posixver.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "nice"
#define AUTHORS "David MacKenzie"
#ifdef NICE_PRIORITY
# define GET_PRIORITY() nice (0)
#else
# define GET_PRIORITY() getpriority (PRIO_PROCESS, 0)
#endif
/* The name this program was run with. */
char *program_name;
static struct option const longopts[] =
{
{"adjustment", required_argument, NULL, 'n'},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION] [COMMAND [ARG]...]\n"), program_name);
fputs (_("\
Run COMMAND with an adjusted scheduling priority.\n\
With no COMMAND, print the current scheduling priority. ADJUST is 10\n\
by default. Range goes from -20 (highest priority) to 19 (lowest).\n\
\n\
-n, --adjustment=ADJUST increment priority by ADJUST first\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int current_priority;
long int adjustment = 0;
int minusflag = 0;
int adjustment_given = 0;
int i;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
for (i = 1; i < argc; /* empty */)
{
char *s = argv[i];
if (s[0] == '-' && s[1] == '-' && ISDIGIT (s[2])
&& posix2_version () < 200112)
{
if (xstrtol (&s[2], NULL, 10, &adjustment, "") != LONGINT_OK)
error (EXIT_FAILURE, 0, _("invalid option `%s'"), s);
minusflag = 1;
adjustment_given = 1;
++i;
}
else if (s[0] == '-'
&& (ISDIGIT (s[1]) || (s[1] == '+' && ISDIGIT (s[2])))
&& posix2_version () < 200112)
{
if (s[1] == '+')
++s;
if (xstrtol (&s[1], NULL, 10, &adjustment, "") != LONGINT_OK)
error (EXIT_FAILURE, 0, _("invalid option `%s'"), s);
minusflag = 0;
adjustment_given = 1;
++i;
}
else
{
int optc;
char **fake_argv = argv + i - 1;
/* Initialize getopt_long's internal state. */
optind = 0;
if ((optc = getopt_long (argc - (i - 1), fake_argv, "+n:",
longopts, NULL)) != -1)
{
switch (optc)
{
case '?':
usage (EXIT_FAILURE);
case 'n':
if (xstrtol (optarg, NULL, 10, &adjustment, "")
!= LONGINT_OK)
error (EXIT_FAILURE, 0, _("invalid priority `%s'"), optarg);
minusflag = 0;
adjustment_given = 1;
break;
}
}
i += optind - 1;
if (optc == EOF)
break;
}
}
if (minusflag)
adjustment = -adjustment;
if (!adjustment_given)
adjustment = 10;
if (i == argc)
{
if (adjustment_given)
{
error (0, 0, _("a command must be given with an adjustment"));
usage (EXIT_FAILURE);
}
/* No command given; print the priority. */
errno = 0;
current_priority = GET_PRIORITY ();
if (current_priority == -1 && errno != 0)
error (EXIT_FAILURE, errno, _("cannot get priority"));
printf ("%d\n", current_priority);
exit (EXIT_SUCCESS);
}
#ifndef NICE_PRIORITY
errno = 0;
current_priority = GET_PRIORITY ();
if (current_priority == -1 && errno != 0)
error (EXIT_FAILURE, errno, _("cannot get priority"));
if (setpriority (PRIO_PROCESS, 0, current_priority + adjustment))
#else
if (nice (adjustment) == -1)
#endif
error (EXIT_FAILURE, errno, _("cannot set priority"));
execvp (argv[i], &argv[i]);
{
int exit_status = (errno == ENOENT ? 127 : 126);
error (0, errno, "%s", argv[i]);
exit (exit_status);
}
}
+629
View File
@@ -0,0 +1,629 @@
/* nl -- number lines of files
Copyright (C) 89, 92, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Scott Bartram ([email protected])
Revised by David MacKenzie (djm@gnu.ai.mit.edu) */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include <regex.h>
#include "error.h"
#include "linebuffer.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "nl"
#define AUTHORS N_ ("Scott Bartram and David MacKenzie")
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
/* Line-number formats. */
enum number_format
{
FORMAT_RIGHT_NOLZ, /* Right justified, no leading zeroes. */
FORMAT_RIGHT_LZ, /* Right justified, leading zeroes. */
FORMAT_LEFT /* Left justified, no leading zeroes. */
};
/* Default section delimiter characters. */
#define DEFAULT_SECTION_DELIMITERS "\\:"
/* Types of input lines: either one of the section delimiters,
or text to output. */
enum section
{
Header, Body, Footer, Text
};
/* The name this program was run with. */
char *program_name;
/* Format of body lines (-b). */
static char *body_type = "t";
/* Format of header lines (-h). */
static char *header_type = "n";
/* Format of footer lines (-f). */
static char *footer_type = "n";
/* Format currently being used (body, header, or footer). */
static char *current_type;
/* Regex for body lines to number (-bp). */
static struct re_pattern_buffer body_regex;
/* Regex for header lines to number (-hp). */
static struct re_pattern_buffer header_regex;
/* Regex for footer lines to number (-fp). */
static struct re_pattern_buffer footer_regex;
/* Pointer to current regex, if any. */
static struct re_pattern_buffer *current_regex = NULL;
/* Separator string to print after line number (-s). */
static char *separator_str = "\t";
/* Input section delimiter string (-d). */
static char *section_del = DEFAULT_SECTION_DELIMITERS;
/* Header delimiter string. */
static char *header_del = NULL;
/* Header section delimiter length. */
static size_t header_del_len;
/* Body delimiter string. */
static char *body_del = NULL;
/* Body section delimiter length. */
static size_t body_del_len;
/* Footer delimiter string. */
static char *footer_del = NULL;
/* Footer section delimiter length. */
static size_t footer_del_len;
/* Input buffer. */
static struct linebuffer line_buf;
/* printf format string for line number. */
static char *print_fmt;
/* printf format string for unnumbered lines. */
static char *print_no_line_fmt = NULL;
/* Starting line number on each page (-v). */
static int starting_line_number = 1;
/* Line number increment (-i). */
static int page_incr = 1;
/* If TRUE, reset line number at start of each page (-p). */
static int reset_numbers = TRUE;
/* Number of blank lines to consider to be one line for numbering (-l). */
static int blank_join = 1;
/* Width of line numbers (-w). */
static int lineno_width = 6;
/* Line number format (-n). */
static enum number_format lineno_format = FORMAT_RIGHT_NOLZ;
/* Current print line number. */
static int line_no;
/* Nonzero if we have ever read standard input. */
static int have_read_stdin;
static struct option const longopts[] =
{
{"header-numbering", required_argument, NULL, 'h'},
{"body-numbering", required_argument, NULL, 'b'},
{"footer-numbering", required_argument, NULL, 'f'},
{"starting-line-number", required_argument, NULL, 'v'},
{"page-increment", required_argument, NULL, 'i'},
{"no-renumber", no_argument, NULL, 'p'},
{"join-blank-lines", required_argument, NULL, 'l'},
{"number-separator", required_argument, NULL, 's'},
{"number-width", required_argument, NULL, 'w'},
{"number-format", required_argument, NULL, 'n'},
{"section-delimiter", required_argument, NULL, 'd'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
/* Print a usage message and quit. */
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Write each FILE to standard output, with line numbers added.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-b, --body-numbering=STYLE use STYLE for numbering body lines\n\
-d, --section-delimiter=CC use CC for separating logical pages\n\
-f, --footer-numbering=STYLE use STYLE for numbering footer lines\n\
"), stdout);
fputs (_("\
-h, --header-numbering=STYLE use STYLE for numbering header lines\n\
-i, --page-increment=NUMBER line number increment at each line\n\
-l, --join-blank-lines=NUMBER group of NUMBER empty lines counted as one\n\
-n, --number-format=FORMAT insert line numbers according to FORMAT\n\
-p, --no-renumber do not reset line numbers at logical pages\n\
-s, --number-separator=STRING add STRING after (possible) line number\n\
"), stdout);
fputs (_("\
-v, --first-page=NUMBER first line number on each logical page\n\
-w, --number-width=NUMBER use NUMBER columns for line numbers\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn. CC are\n\
two delimiter characters for separating logical pages, a missing\n\
second character implies :. Type \\\\ for \\. STYLE is one of:\n\
"), stdout);
fputs (_("\
\n\
a number all lines\n\
t number only nonempty lines\n\
n number no lines\n\
pREGEXP number only lines that contain a match for REGEXP\n\
\n\
FORMAT is one of:\n\
\n\
ln left justified, no leading zeros\n\
rn right justified, no leading zeros\n\
rz right justified, leading zeros\n\
\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Build the printf format string, based on `lineno_format'. */
static void
build_print_fmt (void)
{
print_fmt = xmalloc ( 1 /* for `%' */
+ 1 /* for `-' or `0' */
+ INT_STRLEN_BOUND (lineno_width)
+ 1 /* for `d' */
+ 1 /* for trailing NUL byte */ );
switch (lineno_format)
{
case FORMAT_RIGHT_NOLZ:
sprintf (print_fmt, "%%%dd", lineno_width);
break;
case FORMAT_RIGHT_LZ:
sprintf (print_fmt, "%%0%dd", lineno_width);
break;
case FORMAT_LEFT:
sprintf (print_fmt, "%%-%dd", lineno_width);
break;
}
}
/* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
according to `optarg'. */
static int
build_type_arg (char **typep, struct re_pattern_buffer *regexp)
{
const char *errmsg;
int rval = TRUE;
int optlen;
switch (*optarg)
{
case 'a':
case 't':
case 'n':
*typep = optarg;
break;
case 'p':
*typep = optarg++;
optlen = strlen (optarg);
regexp->allocated = optlen * 2;
regexp->buffer = (unsigned char *) xmalloc (regexp->allocated);
regexp->translate = NULL;
regexp->fastmap = xmalloc (256);
regexp->fastmap_accurate = 0;
errmsg = re_compile_pattern (optarg, optlen, regexp);
if (errmsg)
error (EXIT_FAILURE, 0, "%s", errmsg);
break;
default:
rval = FALSE;
break;
}
return rval;
}
/* Print the line number and separator; increment the line number. */
static void
print_lineno (void)
{
printf (print_fmt, line_no);
fputs (separator_str, stdout);
line_no += page_incr;
}
/* Switch to a header section. */
static void
proc_header (void)
{
current_type = header_type;
current_regex = &header_regex;
if (reset_numbers)
line_no = starting_line_number;
putchar ('\n');
}
/* Switch to a body section. */
static void
proc_body (void)
{
current_type = body_type;
current_regex = &body_regex;
putchar ('\n');
}
/* Switch to a footer section. */
static void
proc_footer (void)
{
current_type = footer_type;
current_regex = &footer_regex;
putchar ('\n');
}
/* Process a regular text line in `line_buf'. */
static void
proc_text (void)
{
static int blank_lines = 0; /* Consecutive blank lines so far. */
switch (*current_type)
{
case 'a':
if (blank_join > 1)
{
if (1 < line_buf.length || ++blank_lines == blank_join)
{
print_lineno ();
blank_lines = 0;
}
else
puts (print_no_line_fmt);
}
else
print_lineno ();
break;
case 't':
if (1 < line_buf.length)
print_lineno ();
else
puts (print_no_line_fmt);
break;
case 'n':
puts (print_no_line_fmt);
break;
case 'p':
if (re_search (current_regex, line_buf.buffer, line_buf.length - 1,
0, line_buf.length - 1, (struct re_registers *) 0) < 0)
puts (print_no_line_fmt);
else
print_lineno ();
break;
}
fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
}
/* Return the type of line in `line_buf'. */
static enum section
check_section (void)
{
size_t len = line_buf.length - 1;
if (len < 2 || memcmp (line_buf.buffer, section_del, 2))
return Text;
if (len == header_del_len
&& !memcmp (line_buf.buffer, header_del, header_del_len))
return Header;
if (len == body_del_len
&& !memcmp (line_buf.buffer, body_del, body_del_len))
return Body;
if (len == footer_del_len
&& !memcmp (line_buf.buffer, footer_del, footer_del_len))
return Footer;
return Text;
}
/* Read and process the file pointed to by FP. */
static void
process_file (FILE *fp)
{
while (readline (&line_buf, fp))
{
switch ((int) check_section ())
{
case Header:
proc_header ();
break;
case Body:
proc_body ();
break;
case Footer:
proc_footer ();
break;
case Text:
proc_text ();
break;
}
}
}
/* Process file FILE to standard output.
Return 0 if successful, 1 if not. */
static int
nl_file (const char *file)
{
FILE *stream;
if (STREQ (file, "-"))
{
have_read_stdin = 1;
stream = stdin;
}
else
{
stream = fopen (file, "r");
if (stream == NULL)
{
error (0, errno, "%s", file);
return 1;
}
}
process_file (stream);
if (ferror (stream))
{
error (0, errno, "%s", file);
return 1;
}
if (STREQ (file, "-"))
clearerr (stream); /* Also clear EOF. */
else if (fclose (stream) == EOF)
{
error (0, errno, "%s", file);
return 1;
}
return 0;
}
int
main (int argc, char **argv)
{
int c, exit_status = 0;
size_t len;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
have_read_stdin = 0;
while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts,
NULL)) != -1)
{
switch (c)
{
case 0:
break;
case 'h':
if (build_type_arg (&header_type, &header_regex) != TRUE)
usage (2);
break;
case 'b':
if (build_type_arg (&body_type, &body_regex) != TRUE)
usage (2);
break;
case 'f':
if (build_type_arg (&footer_type, &footer_regex) != TRUE)
usage (2);
break;
case 'v':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
/* Allow it to be negative. */
|| tmp_long > INT_MAX)
error (EXIT_FAILURE, 0, _("invalid starting line number: `%s'"),
optarg);
starting_line_number = (int) tmp_long;
}
break;
case 'i':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0, _("invalid line number increment: `%s'"),
optarg);
page_incr = (int) tmp_long;
}
break;
case 'p':
reset_numbers = FALSE;
break;
case 'l':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0, _("invalid number of blank lines: `%s'"),
optarg);
blank_join = (int) tmp_long;
}
break;
case 's':
separator_str = optarg;
break;
case 'w':
{
long int tmp_long;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long <= 0 || tmp_long > INT_MAX)
error (EXIT_FAILURE, 0,
_("invalid line number field width: `%s'"),
optarg);
lineno_width = (int) tmp_long;
}
break;
case 'n':
switch (*optarg)
{
case 'l':
if (optarg[1] == 'n')
lineno_format = FORMAT_LEFT;
else
usage (2);
break;
case 'r':
switch (optarg[1])
{
case 'n':
lineno_format = FORMAT_RIGHT_NOLZ;
break;
case 'z':
lineno_format = FORMAT_RIGHT_LZ;
break;
default:
usage (2);
break;
}
break;
default:
usage (2);
break;
}
break;
case 'd':
section_del = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (2);
break;
}
}
/* Initialize the section delimiters. */
len = strlen (section_del);
header_del_len = len * 3;
header_del = xmalloc (header_del_len + 1);
strcat (strcat (strcpy (header_del, section_del), section_del), section_del);
body_del_len = len * 2;
body_del = xmalloc (body_del_len + 1);
strcat (strcpy (body_del, section_del), section_del);
footer_del_len = len;
footer_del = xmalloc (footer_del_len + 1);
strcpy (footer_del, section_del);
/* Initialize the input buffer. */
initbuffer (&line_buf);
/* Initialize the printf format for unnumbered lines. */
len = strlen (separator_str);
print_no_line_fmt = xmalloc (lineno_width + len + 1);
memset (print_no_line_fmt, ' ', lineno_width + len);
print_no_line_fmt[lineno_width + len] = '\0';
line_no = starting_line_number;
current_type = body_type;
current_regex = &body_regex;
build_print_fmt ();
/* Main processing. */
if (optind == argc)
exit_status |= nl_file ("-");
else
for (; optind < argc; optind++)
exit_status |= nl_file (argv[optind]);
if (have_read_stdin && fclose (stdin) == EOF)
{
error (0, errno, "-");
exit_status = 1;
}
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+79
View File
@@ -0,0 +1,79 @@
#!/bin/sh
# nohup -- run a command immume to hangups, with output to a non-tty
# Copyright (C) 1991, 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
# 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, 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. */
# Written by David MacKenzie <[email protected]>.
usage="Usage: $0 COMMAND [ARG]...
or: $0 OPTION"
usage_try="
Try \`$0 --help' for more information."
usage_help="Run COMMAND, ignoring hangup signals.
--help display this help and exit
--version output version information and exit
Report bugs to <@PACKAGE_BUGREPORT@>."
if [ $# -eq 0 ]; then
echo >&2 "$usage"
echo >&2 "$usage_try"
exit 127
fi
fail=0
case $# in
1 )
case "z${1}" in
z--help )
echo "$usage" || fail=127; echo "$usage_help" || fail=127
exit $fail;;
z--version )
echo "nohup (@GNU_PACKAGE@) @VERSION@" || fail=127
exit $fail;;
* ) ;;
esac
;;
* ) ;;
esac
trap "" 1
# Redirect stdout if the user didn't already do it.
if [ -t 1 ]; then
oldmask=`umask`; umask 077
# If we cannot write to the current directory, use the home directory.
if exec >> nohup.out; then
echo "nohup: appending output to \`nohup.out'" >&2
elif exec >> "$HOME/nohup.out"; then
echo "nohup: appending output to \`$HOME/nohup.out'" >&2
else
echo "nohup: cannot append to either \`nohup.out' or \`$HOME/nohup.out'" \
>&2
exit 127
fi
umask $oldmask
fi
# Redirect stderr if the user didn't already do it.
if [ -t 2 ]; then
exec 2>&1
fi
exec "$@"
File diff suppressed because it is too large Load Diff
+486
View File
@@ -0,0 +1,486 @@
/* paste - merge lines of files
Copyright (C) 1984, 1997-2002 by David M. Ihnat
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, 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. */
/* Written by David Ihnat. */
/* The list of valid escape sequences has been expanded over the Unix
version, to include \b, \f, \r, and \v.
POSIX changes, bug fixes, long-named options, and cleanup
by David MacKenzie <djm@gnu.ai.mit.edu>.
Options:
--serial
-s Paste one file at a time rather than
one line from each file.
--delimiters=delim-list
-d delim-list Consecutively use the characters in
DELIM-LIST instead of tab to separate
merged lines. When DELIM-LIST is exhausted,
start again at its beginning.
A FILE of `-' means standard input.
If no FILEs are given, standard input is used. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "paste"
#define AUTHORS N_ ("David M. Ihnat and David MacKenzie")
/* Indicates that no delimiter should be added in the current position. */
#define EMPTY_DELIM '\0'
static FILE dummy_closed;
/* Element marking a file that has reached EOF and been closed. */
#define CLOSED (&dummy_closed)
static FILE dummy_endlist;
/* Element marking end of list of open files. */
#define ENDLIST (&dummy_endlist)
/* Name this program was run with. */
char *program_name;
/* If nonzero, we have read standard input at some point. */
static int have_read_stdin;
/* If nonzero, merge subsequent lines of each file rather than
corresponding lines from each file in parallel. */
static int serial_merge;
/* The delimeters between lines of input files (used cyclically). */
static char *delims;
/* A pointer to the character after the end of `delims'. */
static char *delim_end;
static struct option const longopts[] =
{
{"serial", no_argument, 0, 's'},
{"delimiters", required_argument, 0, 'd'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
/* Replace backslash representations of special characters in
STRPTR with their actual values.
The set of possible backslash characters has been expanded beyond
that recognized by the Unix version.
Return a pointer to the character after the new end of STRPTR. */
static char *
collapse_escapes (char *strptr)
{
register char *strout;
strout = strptr; /* Start at the same place, anyway. */
while (*strptr)
{
if (*strptr != '\\') /* Is it an escape character? */
*strout++ = *strptr++; /* No, just transfer it. */
else
{
switch (*++strptr)
{
case '0':
*strout++ = EMPTY_DELIM;
break;
case 'b':
*strout++ = '\b';
break;
case 'f':
*strout++ = '\f';
break;
case 'n':
*strout++ = '\n';
break;
case 'r':
*strout++ = '\r';
break;
case 't':
*strout++ = '\t';
break;
case 'v':
*strout++ = '\v';
break;
default:
*strout++ = *strptr;
break;
}
strptr++;
}
}
return strout;
}
/* Perform column paste on the NFILES files named in FNAMPTR.
Return 0 if no errors, 1 if one or more files could not be
opened or read. */
static int
paste_parallel (int nfiles, char **fnamptr)
{
int errors = 0; /* 1 if open or read errors occur. */
/* Number of files for which space is allocated in `delbuf' and `fileptr'.
Enlarged as necessary. */
int file_list_size = 12;
int chr IF_LINT (= 0); /* Input character. */
int line_length; /* Number of chars in line. */
int somedone; /* 0 if all files empty for this line. */
/* If all files are just ready to be closed, or will be on this
round, the string of delimiters must be preserved.
delbuf[0] through delbuf[file_list_size]
store the delimiters for closed files. */
char *delbuf;
size_t delims_saved; /* Number of delims saved in `delbuf'. */
register char *delimptr; /* Cycling pointer into `delims'. */
FILE **fileptr; /* Streams open to the files to process. */
int files_open; /* Number of files still open to process. */
int i; /* Loop index. */
int opened_stdin = 0; /* Nonzero if any fopen got fd 0. */
delbuf = (char *) xmalloc (file_list_size + 2);
fileptr = (FILE **) xmalloc ((file_list_size + 1) * sizeof (FILE *));
/* Attempt to open all files. This could be expanded to an infinite
number of files, but at the (considerable) expense of remembering
each file and its current offset, then opening/reading/closing. */
for (files_open = 0; files_open < nfiles; ++files_open)
{
if (files_open == file_list_size - 2)
{
file_list_size += 12;
delbuf = (char *) xrealloc (delbuf, file_list_size + 2);
fileptr = (FILE **) xrealloc ((char *) fileptr, (file_list_size + 1)
* sizeof (FILE *));
}
if (STREQ (fnamptr[files_open], "-"))
{
have_read_stdin = 1;
fileptr[files_open] = stdin;
}
else
{
fileptr[files_open] = fopen (fnamptr[files_open], "r");
if (fileptr[files_open] == NULL)
error (EXIT_FAILURE, errno, "%s", fnamptr[files_open]);
else if (fileno (fileptr[files_open]) == 0)
opened_stdin = 1;
}
}
fileptr[files_open] = ENDLIST;
if (opened_stdin && have_read_stdin)
error (EXIT_FAILURE, 0, _("standard input is closed"));
/* Read a line from each file and output it to stdout separated by a
delimiter, until we go through the loop without successfully
reading from any of the files. */
while (files_open)
{
/* Set up for the next line. */
somedone = 0;
delimptr = delims;
delims_saved = 0;
for (i = 0; fileptr[i] != ENDLIST && files_open; i++)
{
line_length = 0; /* Clear so we can easily detect EOF. */
if (fileptr[i] != CLOSED)
{
chr = getc (fileptr[i]);
if (chr != EOF && delims_saved)
{
fwrite (delbuf, sizeof (char), delims_saved, stdout);
delims_saved = 0;
}
while (chr != EOF)
{
line_length++;
if (chr == '\n')
break;
putc (chr, stdout);
chr = getc (fileptr[i]);
}
}
if (line_length == 0)
{
/* EOF, read error, or closed file.
If an EOF or error, close the file and mark it in the list. */
if (fileptr[i] != CLOSED)
{
if (ferror (fileptr[i]))
{
error (0, errno, "%s", fnamptr[i]);
errors = 1;
}
if (fileptr[i] == stdin)
clearerr (fileptr[i]); /* Also clear EOF. */
else if (fclose (fileptr[i]) == EOF)
{
error (0, errno, "%s", fnamptr[i]);
errors = 1;
}
fileptr[i] = CLOSED;
files_open--;
}
if (fileptr[i + 1] == ENDLIST)
{
/* End of this output line.
Is this the end of the whole thing? */
if (somedone)
{
/* No. Some files were not closed for this line. */
if (delims_saved)
{
fwrite (delbuf, sizeof (char), delims_saved, stdout);
delims_saved = 0;
}
putc ('\n', stdout);
}
continue; /* Next read of files, or exit. */
}
else
{
/* Closed file; add delimiter to `delbuf'. */
if (*delimptr != EMPTY_DELIM)
delbuf[delims_saved++] = *delimptr;
if (++delimptr == delim_end)
delimptr = delims;
}
}
else
{
/* Some data read. */
somedone++;
/* Except for last file, replace last newline with delim. */
if (fileptr[i + 1] != ENDLIST)
{
if (chr != '\n')
putc (chr, stdout);
if (*delimptr != EMPTY_DELIM)
putc (*delimptr, stdout);
if (++delimptr == delim_end)
delimptr = delims;
}
else
putc (chr, stdout);
}
}
}
return errors;
}
/* Perform serial paste on the NFILES files named in FNAMPTR.
Return 0 if no errors, 1 if one or more files could not be
opened or read. */
static int
paste_serial (int nfiles, char **fnamptr)
{
int errors = 0; /* 1 if open or read errors occur. */
register int charnew, charold; /* Current and previous char read. */
register char *delimptr; /* Current delimiter char. */
register FILE *fileptr; /* Open for reading current file. */
for (; nfiles; nfiles--, fnamptr++)
{
if (STREQ (*fnamptr, "-"))
{
have_read_stdin = 1;
fileptr = stdin;
}
else
{
fileptr = fopen (*fnamptr, "r");
if (fileptr == NULL)
{
error (0, errno, "%s", *fnamptr);
errors = 1;
continue;
}
}
delimptr = delims; /* Set up for delimiter string. */
charold = getc (fileptr);
if (charold != EOF)
{
/* `charold' is set up. Hit it!
Keep reading characters, stashing them in `charnew';
output `charold', converting to the appropriate delimiter
character if needed. After the EOF, output `charold'
if it's a newline; otherwise, output it and then a newline. */
while ((charnew = getc (fileptr)) != EOF)
{
/* Process the old character. */
if (charold == '\n')
{
if (*delimptr != EMPTY_DELIM)
putc (*delimptr, stdout);
if (++delimptr == delim_end)
delimptr = delims;
}
else
putc (charold, stdout);
charold = charnew;
}
/* Hit EOF. Process that last character. */
putc (charold, stdout);
}
if (charold != '\n')
putc ('\n', stdout);
if (ferror (fileptr))
{
error (0, errno, "%s", *fnamptr);
errors = 1;
}
if (fileptr == stdin)
clearerr (fileptr); /* Also clear EOF. */
else if (fclose (fileptr) == EOF)
{
error (0, errno, "%s", *fnamptr);
errors = 1;
}
}
return errors;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Write lines consisting of the sequentially corresponding lines from\n\
each FILE, separated by TABs, to standard output.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-d, --delimiters=LIST reuse characters from LIST instead of TABs\n\
-s, --serial paste one file at a time instead of in parallel\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
/* FIXME: add a couple of examples. */
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
int
main (int argc, char **argv)
{
int optc, exit_status;
char default_delims[2], zero_delims[3];
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
have_read_stdin = 0;
serial_merge = 0;
delims = default_delims;
strcpy (delims, "\t");
strcpy (zero_delims, "\\0");
while ((optc = getopt_long (argc, argv, "d:s", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'd':
/* Delimiter character(s). */
if (optarg[0] == '\0')
optarg = zero_delims;
delims = optarg;
break;
case 's':
serial_merge++;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
argv[argc++] = "-";
delim_end = collapse_escapes (delims);
if (!serial_merge)
exit_status = paste_parallel (argc - optind, &argv[optind]);
else
exit_status = paste_serial (argc - optind, &argv[optind]);
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, "-");
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+387
View File
@@ -0,0 +1,387 @@
/* pathchk -- check whether pathnames are valid or portable
Copyright (C) 1991-2003 Free Software Foundation, Inc.
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, 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. */
/* Usage: pathchk [-p] [--portability] path...
For each PATH, print a message if any of these conditions are false:
* all existing leading directories in PATH have search (execute) permission
* strlen (PATH) <= PATH_MAX
* strlen (each_directory_in_PATH) <= NAME_MAX
Exit status:
0 All PATH names passed all of the tests.
1 An error occurred.
Options:
-p, --portability Instead of performing length checks on the
underlying filesystem, test the length of the
pathname and its components against the POSIX
minimum limits for portability, _POSIX_NAME_MAX
and _POSIX_PATH_MAX in 2.9.2. Also check that
the pathname contains no character not in the
portable filename character set.
David MacKenzie <djm@gnu.ai.mit.edu>
and Jim Meyering <meyering@cs.utexas.edu> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#include "system.h"
#include "error.h"
#include "long-options.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "pathchk"
#define AUTHORS N_ ("David MacKenzie and Jim Meyering")
#define NEED_PATHCONF_WRAPPER 0
#if HAVE_PATHCONF
# ifndef PATH_MAX
# define PATH_MAX_FOR(p) pathconf_wrapper ((p), _PC_PATH_MAX)
# define NEED_PATHCONF_WRAPPER 1
# endif /* not PATH_MAX */
# ifndef NAME_MAX
# define NAME_MAX_FOR(p) pathconf_wrapper ((p), _PC_NAME_MAX);
# undef NEED_PATHCONF_WRAPPER
# define NEED_PATHCONF_WRAPPER 1
# endif /* not NAME_MAX */
#else
# include <sys/param.h>
# ifndef PATH_MAX
# ifdef MAXPATHLEN
# define PATH_MAX MAXPATHLEN
# else /* not MAXPATHLEN */
# define PATH_MAX _POSIX_PATH_MAX
# endif /* not MAXPATHLEN */
# endif /* not PATH_MAX */
# ifndef NAME_MAX
# ifdef MAXNAMLEN
# define NAME_MAX MAXNAMLEN
# else /* not MAXNAMLEN */
# define NAME_MAX _POSIX_NAME_MAX
# endif /* not MAXNAMLEN */
# endif /* not NAME_MAX */
#endif
#ifndef _POSIX_PATH_MAX
# define _POSIX_PATH_MAX 255
#endif
#ifndef _POSIX_NAME_MAX
# define _POSIX_NAME_MAX 14
#endif
#ifndef PATH_MAX_FOR
# define PATH_MAX_FOR(p) PATH_MAX
#endif
#ifndef NAME_MAX_FOR
# define NAME_MAX_FOR(p) NAME_MAX
#endif
static int validate_path (char *path, int portability);
/* The name this program was run with. */
char *program_name;
static struct option const longopts[] =
{
{"portability", no_argument, NULL, 'p'},
{NULL, 0, NULL, 0}
};
#if NEED_PATHCONF_WRAPPER
/* Distinguish between the cases when pathconf fails and when it reports there
is no limit (the latter is the case for PATH_MAX on the Hurd). When there
is no limit, return LONG_MAX. Otherwise, return pathconf's return value. */
static long int
pathconf_wrapper (const char *filename, int param)
{
long int ret;
errno = 0;
ret = pathconf (filename, param);
if (ret < 0 && errno == 0)
return LONG_MAX;
return ret;
}
#endif
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... NAME...\n"), program_name);
fputs (_("\
Diagnose unportable constructs in NAME.\n\
\n\
-p, --portability check for all POSIX systems, not only this one\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int exit_status = 0;
int check_portability = 0;
int optc;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
while ((optc = getopt_long (argc, argv, "p", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'p':
check_portability = 1;
break;
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
for (; optind < argc; ++optind)
exit_status |= validate_path (argv[optind], check_portability);
exit (exit_status);
}
/* Each element is nonzero if the corresponding ASCII character is
in the POSIX portable character set, and zero if it is not.
In addition, the entry for `/' is nonzero to simplify checking. */
static char const portable_chars[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* If PATH contains only portable characters, return 1, else 0. */
static int
portable_chars_only (const char *path)
{
const char *p;
for (p = path; *p; ++p)
if (portable_chars[(unsigned char) *p] == 0)
{
error (0, 0, _("path `%s' contains nonportable character `%c'"),
path, *p);
return 0;
}
return 1;
}
/* Return 1 if PATH is a usable leading directory, 0 if not,
2 if it doesn't exist. */
static int
dir_ok (const char *path)
{
struct stat stats;
if (stat (path, &stats))
return 2;
if (!S_ISDIR (stats.st_mode))
{
error (0, 0, _("`%s' is not a directory"), path);
return 0;
}
/* Use access to test for search permission because
testing permission bits of st_mode can lose with new
access control mechanisms. Of course, access loses if you're
running setuid. */
if (access (path, X_OK) != 0)
{
if (errno == EACCES)
error (0, 0, _("directory `%s' is not searchable"), path);
else
error (0, errno, "%s", path);
return 0;
}
return 1;
}
/* Make sure that
strlen (PATH) <= PATH_MAX
&& strlen (each-existing-directory-in-PATH) <= NAME_MAX
If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
_POSIX_NAME_MAX instead, and make sure that PATH contains no
characters not in the POSIX portable filename character set, which
consists of A-Z, a-z, 0-9, ., _, -.
Make sure that all leading directories along PATH that exist have
`x' permission.
Return 0 if all of these tests are successful, 1 if any fail. */
static int
validate_path (char *path, int portability)
{
long int path_max;
int last_elem; /* Nonzero if checking last element of path. */
int exists IF_LINT (= 0); /* 2 if the path element exists. */
char *slash;
char *parent; /* Last existing leading directory so far. */
if (portability && !portable_chars_only (path))
return 1;
if (*path == '\0')
return 0;
/* Figure out the parent of the first element in PATH. */
parent = xstrdup (*path == '/' ? "/" : ".");
slash = path;
last_elem = 0;
while (1)
{
long int name_max;
long int length; /* Length of partial path being checked. */
char *start; /* Start of path element being checked. */
/* Find the end of this element of the path.
Then chop off the rest of the path after this element. */
while (*slash == '/')
slash++;
start = slash;
slash = strchr (slash, '/');
if (slash != NULL)
*slash = '\0';
else
{
last_elem = 1;
slash = strchr (start, '\0');
}
if (!last_elem)
{
exists = dir_ok (path);
if (exists == 0)
{
free (parent);
return 1;
}
}
length = slash - start;
/* Since we know that `parent' is a directory, it's ok to call
pathconf with it as the argument. (If `parent' isn't a directory
or doesn't exist, the behavior of pathconf is undefined.)
But if `parent' is a directory and is on a remote file system,
it's likely that pathconf can't give us a reasonable value
and will return -1. (NFS and tempfs are not POSIX . . .)
In that case, we have no choice but to assume the pessimal
POSIX minimums. */
name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
if (name_max < 0)
name_max = _POSIX_NAME_MAX;
if (length > name_max)
{
error (0, 0, _("name `%s' has length %ld; exceeds limit of %ld"),
start, length, name_max);
free (parent);
return 1;
}
if (last_elem)
break;
if (exists == 1)
{
free (parent);
parent = xstrdup (path);
}
*slash++ = '/';
}
/* `parent' is now the last existing leading directory in the whole path,
so it's ok to call pathconf with it as the argument. */
path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
if (path_max < 0)
path_max = _POSIX_PATH_MAX;
free (parent);
if (strlen (path) > (size_t) path_max)
{
error (0, 0, _("path `%s' has length %d; exceeds limit of %ld"),
path, strlen (path), path_max);
return 1;
}
return 0;
}
+585
View File
@@ -0,0 +1,585 @@
/* GNU's pinky.
Copyright (C) 1992-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Created by hacking who.c by Kaveh Ghazi [email protected] */
#include <config.h>
#include <getopt.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "error.h"
#include "readutmp.h"
#include "closeout.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "pinky"
#define AUTHORS N_ ("Joseph Arceneaux, David MacKenzie, and Kaveh Ghazi")
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 64
#endif
#ifndef S_IWGRP
# define S_IWGRP 020
#endif
int gethostname ();
char *ttyname ();
/* The name this program was run with. */
const char *program_name;
/* If nonzero, display the hours:minutes since each user has touched
the keyboard, or blank if within the last minute, or days followed
by a 'd' if not within the last day. */
static int include_idle = 1;
/* If nonzero, display a line at the top describing each field. */
static int include_heading = 1;
/* if nonzero, display the user's full name from pw_gecos. */
static int include_fullname = 1;
/* if nonzero, display the user's ~/.project file when doing long format. */
static int include_project = 1;
/* if nonzero, display the user's ~/.plan file when doing long format. */
static int include_plan = 1;
/* if nonzero, display the user's home directory and shell
when doing long format. */
static int include_home_and_shell = 1;
/* if nonzero, use the "short" output format. */
static int do_short_format = 1;
/* if nonzero, display the ut_host field. */
#ifdef HAVE_UT_HOST
static int include_where = 1;
#endif
static struct option const longopts[] =
{
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
/* Count and return the number of ampersands in STR. */
static int
count_ampersands (const char *str)
{
int count = 0;
do
{
if (*str == '&')
count++;
} while (*str++);
return count;
}
/* Create a string (via xmalloc) which contains a full name by substituting
for each ampersand in GECOS_NAME the USER_NAME string with its first
character capitalized. The caller must ensure that GECOS_NAME contains
no `,'s. The caller also is responsible for free'ing the return value of
this function. */
static char *
create_fullname (const char *gecos_name, const char *user_name)
{
const int result_len = strlen (gecos_name)
+ count_ampersands (gecos_name) * (strlen (user_name) - 1) + 1;
char *const result = xmalloc (result_len);
char *r = result;
while (*gecos_name)
{
if (*gecos_name == '&')
{
const char *uname = user_name;
if (ISLOWER (*uname))
*r++ = TOUPPER (*uname++);
while (*uname)
*r++ = *uname++;
}
else
{
*r++ = *gecos_name;
}
gecos_name++;
}
*r = 0;
return result;
}
/* Return a string representing the time between WHEN and the time
that this function is first run. */
static const char *
idle_string (time_t when)
{
static time_t now = 0;
static char idle_hhmm[10];
time_t seconds_idle;
if (now == 0)
time (&now);
seconds_idle = now - when;
if (seconds_idle < 60) /* One minute. */
return " ";
if (seconds_idle < (24 * 60 * 60)) /* One day. */
{
sprintf (idle_hhmm, "%02d:%02d",
(int) (seconds_idle / (60 * 60)),
(int) ((seconds_idle % (60 * 60)) / 60));
return (const char *) idle_hhmm;
}
sprintf (idle_hhmm, "%dd", (int) (seconds_idle / (24 * 60 * 60)));
return (const char *) idle_hhmm;
}
/* Display a line of information about UTMP_ENT. */
static void
print_entry (const STRUCT_UTMP *utmp_ent)
{
struct stat stats;
time_t last_change;
char mesg;
#define DEV_DIR_WITH_TRAILING_SLASH "/dev/"
#define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1)
char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1];
time_t tm;
/* Copy ut_line into LINE, prepending `/dev/' if ut_line is not
already an absolute pathname. Some system may put the full,
absolute pathname in ut_line. */
if (utmp_ent->ut_line[0] == '/')
{
strncpy (line, utmp_ent->ut_line, sizeof (utmp_ent->ut_line));
line[sizeof (utmp_ent->ut_line)] = '\0';
}
else
{
strcpy (line, DEV_DIR_WITH_TRAILING_SLASH);
strncpy (line + DEV_DIR_LEN, utmp_ent->ut_line, sizeof (utmp_ent->ut_line));
line[DEV_DIR_LEN + sizeof (utmp_ent->ut_line)] = '\0';
}
if (stat (line, &stats) == 0)
{
mesg = (stats.st_mode & S_IWGRP) ? ' ' : '*';
last_change = stats.st_atime;
}
else
{
mesg = '?';
last_change = 0;
}
printf ("%-8.*s", (int) sizeof (UT_USER (utmp_ent)), UT_USER (utmp_ent));
if (include_fullname)
{
struct passwd *pw;
char name[sizeof (UT_USER (utmp_ent)) + 1];
strncpy (name, UT_USER (utmp_ent), sizeof (UT_USER (utmp_ent)));
name[sizeof (UT_USER (utmp_ent))] = '\0';
pw = getpwnam (name);
if (pw == NULL)
printf (" %19s", " ???");
else
{
char *const comma = strchr (pw->pw_gecos, ',');
char *result;
if (comma)
*comma = '\0';
result = create_fullname (pw->pw_gecos, pw->pw_name);
printf (" %-19.19s", result);
free (result);
}
}
printf (" %c%-8.*s",
mesg, (int) sizeof (utmp_ent->ut_line), utmp_ent->ut_line);
if (include_idle)
{
if (last_change)
printf (" %-6s", idle_string (last_change));
else
printf (" %-6s", "???");
}
/* Don't take the address of UT_TIME_MEMBER directly.
Ulrich Drepper wrote:
``... GNU libc (and perhaps other libcs as well) have extended
utmp file formats which do not use a simple time_t ut_time field.
In glibc, ut_time is a macro which selects for backward compatibility
the tv_sec member of a struct timeval value.'' */
tm = UT_TIME_MEMBER (utmp_ent);
printf (" %-12.12s", ctime (&tm) + 4);
#ifdef HAVE_UT_HOST
if (include_where && utmp_ent->ut_host[0])
{
extern char *canon_host ();
char ut_host[sizeof (utmp_ent->ut_host) + 1];
char *host = 0, *display = 0;
/* Copy the host name into UT_HOST, and ensure it's nul terminated. */
strncpy (ut_host, utmp_ent->ut_host, (int) sizeof (utmp_ent->ut_host));
ut_host[sizeof (utmp_ent->ut_host)] = '\0';
/* Look for an X display. */
display = strrchr (ut_host, ':');
if (display)
*display++ = '\0';
if (*ut_host)
/* See if we can canonicalize it. */
host = canon_host (ut_host);
if ( ! host)
host = ut_host;
if (display)
printf (" %s:%s", host, display);
else
printf (" %s", host);
}
#endif
putchar ('\n');
}
/* Display a verbose line of information about UTMP_ENT. */
static void
print_long_entry (const char name[])
{
struct passwd *pw;
pw = getpwnam (name);
printf (_("Login name: "));
printf ("%-28s", name);
printf (_("In real life: "));
if (pw == NULL)
{
printf (" %s", _("???\n"));
return;
}
else
{
char *const comma = strchr (pw->pw_gecos, ',');
char *result;
if (comma)
*comma = '\0';
result = create_fullname (pw->pw_gecos, pw->pw_name);
printf (" %s", result);
free (result);
}
putchar ('\n');
if (include_home_and_shell)
{
printf (_("Directory: "));
printf ("%-29s", pw->pw_dir);
printf (_("Shell: "));
printf (" %s", pw->pw_shell);
putchar ('\n');
}
if (include_project)
{
FILE *stream;
char buf[1024];
const char *const baseproject = "/.project";
char *const project =
xmalloc (strlen (pw->pw_dir) + strlen (baseproject) + 1);
strcpy (project, pw->pw_dir);
strcat (project, baseproject);
stream = fopen (project, "r");
if (stream)
{
size_t bytes;
printf (_("Project: "));
while ((bytes = fread (buf, 1, sizeof (buf), stream)) > 0)
fwrite (buf, 1, bytes, stdout);
fclose (stream);
}
free (project);
}
if (include_plan)
{
FILE *stream;
char buf[1024];
const char *const baseplan = "/.plan";
char *const plan =
xmalloc (strlen (pw->pw_dir) + strlen (baseplan) + 1);
strcpy (plan, pw->pw_dir);
strcat (plan, baseplan);
stream = fopen (plan, "r");
if (stream)
{
size_t bytes;
printf (_("Plan:\n"));
while ((bytes = fread (buf, 1, sizeof (buf), stream)) > 0)
fwrite (buf, 1, bytes, stdout);
fclose (stream);
}
free (plan);
}
putchar ('\n');
}
/* Print the username of each valid entry and the number of valid entries
in UTMP_BUF, which should have N elements. */
static void
print_heading (void)
{
printf ("%-8s", _("Login"));
if (include_fullname)
printf (" %-19s", _("Name"));
printf (" %-9s", _(" TTY"));
if (include_idle)
printf (" %-6s", _("Idle"));
printf (" %-12s", _("When"));
#ifdef HAVE_UT_HOST
if (include_where)
printf (" %s", _("Where"));
#endif
putchar ('\n');
}
/* Display UTMP_BUF, which should have N entries. */
static void
scan_entries (int n, const STRUCT_UTMP *utmp_buf,
const int argc_names, char *const argv_names[])
{
if (include_heading)
print_heading ();
while (n--)
{
if (UT_USER (utmp_buf)[0]
#ifdef USER_PROCESS
&& utmp_buf->ut_type == USER_PROCESS
#endif
)
{
if (argc_names)
{
int i;
for (i = 0; i < argc_names; i++)
if (strncmp (UT_USER (utmp_buf), argv_names[i],
sizeof (UT_USER (utmp_buf))) == 0)
{
print_entry (utmp_buf);
break;
}
}
else
print_entry (utmp_buf);
}
utmp_buf++;
}
}
/* Display a list of who is on the system, according to utmp file FILENAME. */
static void
short_pinky (const char *filename,
const int argc_names, char *const argv_names[])
{
int n_users;
STRUCT_UTMP *utmp_buf;
int fail = read_utmp (filename, &n_users, &utmp_buf);
if (fail)
error (EXIT_FAILURE, errno, "%s", filename);
scan_entries (n_users, utmp_buf, argc_names, argv_names);
}
static void
long_pinky (const int argc_names, char *const argv_names[])
{
int i;
for (i = 0; i < argc_names; i++)
print_long_entry (argv_names[i]);
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [USER]...\n"), program_name);
fputs (_("\
\n\
-l produce long format output for the specified USERs\n\
-b omit the user's home directory and shell in long format\n\
-h omit the user's project file in long format\n\
-p omit the user's plan file in long format\n\
-s do short format output, this is the default\n\
"), stdout);
fputs (_("\
-f omit the line of column headings in short format\n\
-w omit the user's full name in short format\n\
-i omit the user's full name and remote host in short format\n\
-q omit the user's full name, remote host and idle time\n\
in short format\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\
\n\
A lightweight `finger' program; print user information.\n\
The utmp file will be %s.\n\
"), UTMP_FILE);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int optc, longind;
int n_users;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((optc = getopt_long (argc, argv, "sfwiqbhlp", longopts, &longind))
!= -1)
{
switch (optc)
{
case 0:
break;
case 's':
do_short_format = 1;
break;
case 'l':
do_short_format = 0;
break;
case 'f':
include_heading = 0;
break;
case 'w':
include_fullname = 0;
break;
case 'i':
include_fullname = 0;
#ifdef HAVE_UT_HOST
include_where = 0;
#endif
break;
case 'q':
include_fullname = 0;
#ifdef HAVE_UT_HOST
include_where = 0;
#endif
include_idle = 0;
break;
case 'h':
include_project = 0;
break;
case 'p':
include_plan = 0;
break;
case 'b':
include_home_and_shell = 0;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
n_users = argc - optind;
if (do_short_format == 0 && n_users == 0)
{
error (0, 0, _("no username specified; at least one must be\
specified when using -l"));
usage (EXIT_FAILURE);
}
if (do_short_format)
short_pinky (UTMP_FILE, n_users, argv + optind);
else
long_pinky (n_users, argv + optind);
exit (EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
+139
View File
@@ -0,0 +1,139 @@
/* printenv -- print all or part of environment
Copyright (C) 1989-1997, 1999-2002 Free Software Foundation, Inc.
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, 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. */
/* Usage: printenv [variable...]
If no arguments are given, print the entire environment.
If one or more variable names are given, print the value of
each one that is set, and nothing for ones that are not set.
Exit status:
0 if all variables specified were found
1 if not
David MacKenzie and Richard Mlynarik */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "long-options.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "printenv"
#define AUTHORS N_ ("David MacKenzie and Richard Mlynarik")
/* The name this program was run with. */
char *program_name;
static struct option const long_options[] =
{
{0, 0, 0, 0}
};
extern char **environ;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [VARIABLE]...\n\
or: %s OPTION\n\
If no environment VARIABLE specified, print them all.\n\
\n\
"),
program_name, program_name);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
char **env;
char *ep, *ap;
int i;
int matches = 0;
int c;
int exit_status;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
close_stdout_set_status (2);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
{
for (env = environ; *env != NULL; ++env)
puts (*env);
exit_status = 0;
}
else
{
for (i = optind; i < argc; ++i)
{
for (env = environ; *env; ++env)
{
ep = *env;
ap = argv[i];
while (*ep != '\0' && *ap != '\0' && *ep++ == *ap++)
{
if (*ep == '=' && *ap == '\0')
{
puts (ep + 1);
++matches;
break;
}
}
}
}
exit_status = (matches != argc - optind);
}
exit (exit_status);
}
+598
View File
@@ -0,0 +1,598 @@
/* printf - format and print data
Copyright (C) 1990-2003, Free Software Foundation, Inc.
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, 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. */
/* Usage: printf format [argument...]
A front end to the printf function that lets it be used from the shell.
Backslash escapes:
\" = double quote
\\ = backslash
\a = alert (bell)
\b = backspace
\c = produce no further output
\f = form feed
\n = new line
\r = carriage return
\t = horizontal tab
\v = vertical tab
\0ooo = octal number (ooo is 0 to 3 digits)
\xhh = hexadecimal number (hhh is 1 to 2 digits)
\uhhhh = 16-bit Unicode character (hhhh is 4 digits)
\Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits)
Additional directive:
%b = print an argument string, interpreting backslash escapes
The `format' argument is re-used as many times as necessary
to convert all of the given arguments.
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "long-options.h"
#include "error.h"
#include "closeout.h"
#include "unicodeio.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "printf"
#define AUTHORS "David MacKenzie"
#ifndef STDC_HEADERS
double strtod ();
long int strtol ();
unsigned long int strtoul ();
#endif
#define isodigit(c) ((c) >= '0' && (c) <= '7')
#define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
(c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
#define octtobin(c) ((c) - '0')
/* A value for field_width or precision that indicates it was not specified. */
#define UNSPECIFIED INT_MIN
/* The value to return to the calling program. */
static int exit_status;
/* Non-zero if the POSIXLY_CORRECT environment variable is set. */
static int posixly_correct;
/* This message appears in N_() here rather than just in _() below because
the sole use would have been in a #define. */
static char *const cfcc_msg =
N_("warning: %s: character(s) following character constant have been ignored");
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s FORMAT [ARGUMENT]...\n\
or: %s OPTION\n\
"),
program_name, program_name);
fputs (_("\
Print ARGUMENT(s) according to FORMAT.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
FORMAT controls the output as in C printf. Interpreted sequences are:\n\
\n\
\\\" double quote\n\
\\0NNN character with octal value NNN (0 to 3 digits)\n\
\\\\ backslash\n\
"), stdout);
fputs (_("\
\\a alert (BEL)\n\
\\b backspace\n\
\\c produce no further output\n\
\\f form feed\n\
"), stdout);
fputs (_("\
\\n new line\n\
\\r carriage return\n\
\\t horizontal tab\n\
\\v vertical tab\n\
"), stdout);
fputs (_("\
\\xNN byte with hexadecimal value NN (1 to 2 digits)\n\
\n\
\\uNNNN character with hexadecimal value NNNN (4 digits)\n\
\\UNNNNNNNN character with hexadecimal value NNNNNNNN (8 digits)\n\
"), stdout);
fputs (_("\
%% a single %\n\
%b ARGUMENT as a string with `\\' escapes interpreted\n\
\n\
and all C format specifications ending with one of diouxXfeEgGcs, with\n\
ARGUMENTs converted to proper type first. Variable widths are handled.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
static void
verify (const char *s, const char *end)
{
if (errno)
{
error (0, errno, "%s", s);
exit_status = 1;
}
else if (*end)
{
if (s == end)
error (0, 0, _("%s: expected a numeric value"), s);
else
error (0, 0, _("%s: value not completely converted"), s);
exit_status = 1;
}
}
#define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \
static TYPE \
FUNC_NAME (s) \
const char *s; \
{ \
char *end; \
TYPE val; \
\
if (*s == '\"' || *s == '\'') \
{ \
val = *(unsigned char *) ++s; \
/* If POSIXLY_CORRECT is not set, then give a warning that there \
are characters following the character constant and that GNU \
printf is ignoring those characters. If POSIXLY_CORRECT *is* \
set, then don't give the warning. */ \
if (*++s != 0 && !posixly_correct) \
error (0, 0, _(cfcc_msg), s); \
} \
else \
{ \
errno = 0; \
val = LIB_FUNC_EXPR; \
verify (s, end); \
} \
return val; \
} \
STRTOX (unsigned long int, xstrtoul, (strtoul (s, &end, 0)))
STRTOX (long int, xstrtol, (strtol (s, &end, 0)))
STRTOX (double, xstrtod, (strtod (s, &end)))
/* Output a single-character \ escape. */
static void
print_esc_char (int c)
{
switch (c)
{
case 'a': /* Alert. */
putchar (7);
break;
case 'b': /* Backspace. */
putchar (8);
break;
case 'c': /* Cancel the rest of the output. */
exit (EXIT_SUCCESS);
break;
case 'f': /* Form feed. */
putchar (12);
break;
case 'n': /* New line. */
putchar (10);
break;
case 'r': /* Carriage return. */
putchar (13);
break;
case 't': /* Horizontal tab. */
putchar (9);
break;
case 'v': /* Vertical tab. */
putchar (11);
break;
default:
putchar (c);
break;
}
}
/* Print a \ escape sequence starting at ESCSTART.
Return the number of characters in the escape sequence
besides the backslash. */
static int
print_esc (const char *escstart)
{
register const char *p = escstart + 1;
int esc_value = 0; /* Value of \nnn escape. */
int esc_length; /* Length of \nnn escape. */
if (!posixly_correct && *p == 'x')
{
/* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */
for (esc_length = 0, ++p;
esc_length < 2 && ISXDIGIT (*p);
++esc_length, ++p)
esc_value = esc_value * 16 + hextobin (*p);
if (esc_length == 0)
error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
putchar (esc_value);
}
else if (*p == '0')
{
/* An octal \0ooo escape sequence has 0 to 3 octal digits
after the leading \0. */
for (esc_length = 0, ++p;
esc_length < 3 && isodigit (*p);
++esc_length, ++p)
esc_value = esc_value * 8 + octtobin (*p);
putchar (esc_value);
}
else if (*p && strchr ("\"\\abcfnrtv", *p))
print_esc_char (*p++);
else if (!posixly_correct && (*p == 'u' || *p == 'U'))
{
char esc_char = *p;
unsigned int uni_value;
uni_value = 0;
for (esc_length = (esc_char == 'u' ? 4 : 8), ++p;
esc_length > 0;
--esc_length, ++p)
{
if (!ISXDIGIT (*p))
error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
uni_value = uni_value * 16 + hextobin (*p);
}
/* A universal character name shall not specify a character short
identifier in the range 00000000 through 00000020, 0000007F through
0000009F, or 0000D800 through 0000DFFF inclusive. A universal
character name shall not designate a character in the required
character set. */
if ((uni_value <= 0x9f
&& uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60)
|| (uni_value >= 0xd800 && uni_value <= 0xdfff))
error (EXIT_FAILURE, 0, _("invalid universal character name \\%c%0*x"),
esc_char, (esc_char == 'u' ? 4 : 8), uni_value);
print_unicode_char (stdout, uni_value, 0);
}
else
{
putchar ('\\');
if (*p)
{
putchar (*p);
p++;
}
}
return p - escstart - 1;
}
/* Print string STR, evaluating \ escapes. */
static void
print_esc_string (const char *str)
{
for (; *str; str++)
if (*str == '\\')
str += print_esc (str);
else
putchar (*str);
}
/* Output a % directive. START is the start of the directive,
LENGTH is its length, and ARGUMENT is its argument.
If FIELD_WIDTH or PRECISION is UNSPECIFIED, they are args for
'*' values in those fields. */
static void
print_direc (const char *start, size_t length, int field_width,
int precision, const char *argument)
{
char *p; /* Null-terminated copy of % directive. */
p = xmalloc ((unsigned) (length + 1));
strncpy (p, start, length);
p[length] = 0;
switch (p[length - 1])
{
case 'd':
case 'i':
if (field_width == UNSPECIFIED)
{
if (precision == UNSPECIFIED)
printf (p, xstrtol (argument));
else
printf (p, precision, xstrtol (argument));
}
else
{
if (precision == UNSPECIFIED)
printf (p, field_width, xstrtol (argument));
else
printf (p, field_width, precision, xstrtol (argument));
}
break;
case 'o':
case 'u':
case 'x':
case 'X':
if (field_width == UNSPECIFIED)
{
if (precision == UNSPECIFIED)
printf (p, xstrtoul (argument));
else
printf (p, precision, xstrtoul (argument));
}
else
{
if (precision == UNSPECIFIED)
printf (p, field_width, xstrtoul (argument));
else
printf (p, field_width, precision, xstrtoul (argument));
}
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
if (field_width == UNSPECIFIED)
{
if (precision == UNSPECIFIED)
printf (p, xstrtod (argument));
else
printf (p, precision, xstrtod (argument));
}
else
{
if (precision == UNSPECIFIED)
printf (p, field_width, xstrtod (argument));
else
printf (p, field_width, precision, xstrtod (argument));
}
break;
case 'c':
printf (p, *argument);
break;
case 's':
if (field_width == UNSPECIFIED)
{
if (precision == UNSPECIFIED)
printf (p, argument);
else
printf (p, precision, argument);
}
else
{
if (precision == UNSPECIFIED)
printf (p, field_width, argument);
else
printf (p, field_width, precision, argument);
}
break;
}
free (p);
}
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
arguments to any `%' directives.
Return the number of elements of ARGV used. */
static int
print_formatted (const char *format, int argc, char **argv)
{
int save_argc = argc; /* Preserve original value. */
const char *f; /* Pointer into `format'. */
const char *direc_start; /* Start of % directive. */
size_t direc_length; /* Length of % directive. */
int field_width; /* Arg to first '*', or UNSPECIFIED if none. */
int precision; /* Arg to second '*', or UNSPECIFIED if none. */
for (f = format; *f; ++f)
{
switch (*f)
{
case '%':
direc_start = f++;
direc_length = 1;
field_width = precision = UNSPECIFIED;
if (*f == '%')
{
putchar ('%');
break;
}
if (*f == 'b')
{
if (argc > 0)
{
print_esc_string (*argv);
++argv;
--argc;
}
break;
}
while (*f == ' ' || *f == '#' || *f == '+' || *f == '-')
{
++f;
++direc_length;
}
if (*f == '*')
{
++f;
++direc_length;
if (argc > 0)
{
field_width = xstrtoul (*argv);
if (field_width == UNSPECIFIED)
error (EXIT_FAILURE, 0, _("invalid field width: %s"),
*argv);
++argv;
--argc;
}
else
field_width = 0;
}
else
while (ISDIGIT (*f))
{
++f;
++direc_length;
}
if (*f == '.')
{
++f;
++direc_length;
if (*f == '*')
{
++f;
++direc_length;
if (argc > 0)
{
precision = xstrtoul (*argv);
if (precision == UNSPECIFIED)
error (EXIT_FAILURE, 0, _("invalid precision: %s"),
*argv);
++argv;
--argc;
}
else
precision = 0;
}
else
while (ISDIGIT (*f))
{
++f;
++direc_length;
}
}
if (*f == 'l' || *f == 'L' || *f == 'h')
{
++f;
++direc_length;
}
if (! (*f && strchr ("diouxXfeEgGcs", *f)))
error (EXIT_FAILURE, 0, _("%%%c: invalid directive"), *f);
++direc_length;
if (argc > 0)
{
print_direc (direc_start, direc_length, field_width,
precision, *argv);
++argv;
--argc;
}
else
print_direc (direc_start, direc_length, field_width,
precision, "");
break;
case '\\':
f += print_esc (f);
break;
default:
putchar (*f);
}
}
return save_argc - argc;
}
int
main (int argc, char **argv)
{
char *format;
int args_used;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
exit_status = 0;
/* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
if (!posixly_correct)
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
/* The above handles --help and --version.
Since there is no other invocation of getopt, handle `--' here. */
if (1 < argc && STREQ (argv[1], "--"))
{
--argc;
++argv;
}
if (argc == 1)
{
fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
exit (EXIT_FAILURE);
}
format = argv[1];
argc -= 2;
argv += 2;
do
{
args_used = print_formatted (format, argc, argv);
argc -= args_used;
argv += args_used;
}
while (args_used > 0 && argc > 0);
if (argc > 0)
error (0, 0,
_("warning: ignoring excess arguments, starting with `%s'"),
argv[0]);
exit (exit_status);
}
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
/* pwd - print current directory
Copyright (C) 1994-1997, 1999-2003 Free Software Foundation, Inc.
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, 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. */
/* Jim Meyering <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "long-options.h"
#include "error.h"
#include "xgetcwd.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "pwd"
#define AUTHORS "Jim Meyering"
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]\n"), program_name);
fputs (_("\
Print the full filename of the current working directory.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
char *wd;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
if (argc != 1)
error (0, 0, _("ignoring non-option arguments"));
wd = xgetcwd ();
if (wd == NULL)
error (EXIT_FAILURE, errno, _("cannot get current directory"));
printf ("%s\n", wd);
exit (EXIT_SUCCESS);
}
+157
View File
@@ -0,0 +1,157 @@
/* readlink -- display value of a symbolic link.
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
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, 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. */
/* Written by Dmitry V. Levin */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <getopt.h>
#include "system.h"
#include "canonicalize.h"
#include "error.h"
#include "xreadlink.h"
#include "long-options.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "readlink"
#define AUTHORS "Dmitry V. Levin"
/* Name this program was run with. */
char *program_name;
/* If nonzero, canonicalize file name. */
static int canonicalize;
/* If nonzero, do not output the trailing newline. */
static int no_newline;
/* If nonzero, report error messages. */
static int verbose;
static struct option const longopts[] =
{
{"canonicalize", no_argument, 0, 'f'},
{"no-newline", no_argument, 0, 'n'},
{"quiet", no_argument, 0, 'q'},
{"silent", no_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... FILE\n"), program_name);
fputs (_("Display value of a symbolic link on standard output.\n\n"),
stdout);
fputs (_("\
-f, --canonicalize canonicalize by following every symlink in every\n\
component of the given path recursively\n\
-n, --no-newline do not output the trailing newline\n\
-q, --quiet,\n\
-s, --silent suppress most error messages\n\
-v, --verbose report error messages\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char *const argv[])
{
const char *fname;
char *value;
int optc;
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
if (argc < 1)
error (EXIT_FAILURE, 0, _("too few arguments"));
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "fnqsv", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'f':
canonicalize = 1;
break;
case 'n':
no_newline = 1;
break;
case 'q':
case 's':
verbose = 0;
break;
case 'v':
verbose = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind >= argc)
{
error (EXIT_SUCCESS, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
fname = argv[optind++];
if (optind < argc)
{
error (EXIT_SUCCESS, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
value = (canonicalize ? canonicalize_file_name : xreadlink) (fname);
if (value)
{
printf ("%s%s", value, (no_newline ? "" : "\n"));
free (value);
return EXIT_SUCCESS;
}
if (verbose)
error (EXIT_SUCCESS, errno, "%s", fname);
return EXIT_FAILURE;
}
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
#ifndef REMOVE_H
# define REMOVE_H
struct rm_options
{
/* If nonzero, ignore nonexistent files. */
int ignore_missing_files;
/* If nonzero, query the user about whether to remove each file. */
int interactive;
/* If nonzero, recursively remove directories. */
int recursive;
/* If nonzero, stdin is a tty. */
int stdin_tty;
/* If nonzero, remove directories with unlink instead of rmdir, and don't
require a directory to be empty before trying to unlink it.
Only works for the super-user. */
int unlink_dirs;
/* If nonzero, display the name of each file removed. */
int verbose;
};
enum RM_status
{
/* These must be listed in order of increasing seriousness. */
RM_OK = 2,
RM_USER_DECLINED,
RM_ERROR,
RM_NONEMPTY_DIR
};
# define VALID_STATUS(S) \
((S) == RM_OK || (S) == RM_USER_DECLINED || (S) == RM_ERROR)
# define UPDATE_STATUS(S, New_value) \
do \
{ \
if ((New_value) == RM_ERROR \
|| ((New_value) == RM_USER_DECLINED && (S) == RM_OK)) \
(S) = (New_value); \
} \
while (0)
enum RM_status rm (size_t n_files, char const *const *file,
struct rm_options const *x);
#endif
+215
View File
@@ -0,0 +1,215 @@
/* `rm' file deletion utility for GNU.
Copyright (C) 88, 90, 91, 1994-2003 Free Software Foundation, Inc.
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, 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. */
/* Written by Paul Rubin, David MacKenzie, and Richard Stallman.
Reworked to use chdir and avoid recursion by Jim Meyering. */
/* Implementation overview:
In the `usual' case, RM saves no state for directories it is processing.
When a removal fails (either due to an error or to an interactive `no'
reply), the failure is noted (see description of `ht' in remove.c's
remove_cwd_entries function) so that when/if the containing directory
is reopened, RM doesn't try to remove the entry again.
RM may delete arbitrarily deep hierarchies -- even ones in which file
names (from root to leaf) are longer than the system-imposed maximum.
It does this by using chdir to change to each directory in turn before
removing the entries in that directory.
RM detects directory cycles lazily. See lib/cycle-check.c.
RM is careful to avoid forming full file names whenever possible.
A full file name is formed only when it is about to be used -- e.g.
in a diagnostic or in an interactive-mode prompt.
RM minimizes the number of lstat system calls it makes. On systems
that have valid d_type data in directory entries, RM makes only one
lstat call per command line argument -- regardless of the depth of
the hierarchy. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#include "system.h"
#include "error.h"
#include "remove.h"
#include "save-cwd.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "rm"
#define AUTHORS \
N_ ("Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering")
/* Name this program was run with. */
char *program_name;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1
};
static struct option const long_opts[] =
{
{"directory", no_argument, NULL, 'd'},
{"force", no_argument, NULL, 'f'},
{"interactive", no_argument, NULL, 'i'},
/* This is solely for testing. Do not document. */
/* It is relatively difficult to ensure that there is a tty on stdin.
Since rm acts differently depending on that, without this option,
it'd be harder to test the parts of rm that depend on that setting. */
{"presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
{"recursive", no_argument, NULL, 'r'},
{"verbose", no_argument, NULL, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
fputs (_("\
Remove (unlink) the FILE(s).\n\
\n\
-d, --directory unlink FILE, even if it is a non-empty directory\n\
(super-user only)\n\
-f, --force ignore nonexistent files, never prompt\n\
-i, --interactive prompt before any removal\n\
-r, -R, --recursive remove the contents of directories recursively\n\
-v, --verbose explain what is being done\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\
\n\
To remove a file whose name starts with a `-', for example `-foo',\n\
use one of these commands:\n\
%s -- -foo\n\
\n\
%s ./-foo\n\
"),
program_name, program_name);
fputs (_("\
\n\
Note that if you use rm to remove a file, it is usually possible to recover\n\
the contents of that file. If you want more assurance that the contents are\n\
truly unrecoverable, consider using shred.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
static void
rm_option_init (struct rm_options *x)
{
x->unlink_dirs = 0;
x->ignore_missing_files = 0;
x->interactive = 0;
x->recursive = 0;
x->stdin_tty = isatty (STDIN_FILENO);
x->verbose = 0;
}
int
main (int argc, char **argv)
{
struct rm_options x;
int fail = 0;
int c;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
rm_option_init (&x);
while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1)
{
switch (c)
{
case 0: /* Long option. */
break;
case 'd':
x.unlink_dirs = 1;
break;
case 'f':
x.interactive = 0;
x.ignore_missing_files = 1;
break;
case 'i':
x.interactive = 1;
x.ignore_missing_files = 0;
break;
case 'r':
case 'R':
x.recursive = 1;
break;
case PRESUME_INPUT_TTY_OPTION:
x.stdin_tty = 1;
break;
case 'v':
x.verbose = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
{
if (x.ignore_missing_files)
exit (EXIT_SUCCESS);
else
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
}
{
size_t n_files = argc - optind;
char const *const *file = (char const *const *) argv + optind;
enum RM_status status = rm (n_files, file, &x);
assert (VALID_STATUS (status));
if (status == RM_ERROR)
fail = 1;
}
exit (fail);
}
+237
View File
@@ -0,0 +1,237 @@
/* rmdir -- remove directories
Copyright (C) 90, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Options:
-p, --parent Remove any parent dirs that are explicitly mentioned
in an argument, if they become empty after the
argument file is removed.
David MacKenzie <djm@ai.mit.edu> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "dirname.h"
#include "error.h"
#include "quote.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "rmdir"
#define AUTHORS "David MacKenzie"
#ifndef EEXIST
# define EEXIST 0
#endif
#ifndef ENOTEMPTY
# define ENOTEMPTY 0
#endif
/* The name this program was run with. */
char *program_name;
/* If nonzero, remove empty parent directories. */
static int empty_paths;
/* If nonzero, don't treat failure to remove a nonempty directory
as an error. */
static int ignore_fail_on_non_empty;
/* If nonzero, output a diagnostic for every directory processed. */
static int verbose;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
IGNORE_FAIL_ON_NON_EMPTY_OPTION = CHAR_MAX + 1
};
static struct option const longopts[] =
{
/* Don't name this `--force' because it's not close enough in meaning
to e.g. rm's -f option. */
{"ignore-fail-on-non-empty", no_argument, NULL,
IGNORE_FAIL_ON_NON_EMPTY_OPTION},
{"path", no_argument, NULL, 'p'},
{"parents", no_argument, NULL, 'p'},
{"verbose", no_argument, NULL, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
/* Return nonzero if ERROR_NUMBER is one of the values associated
with a failed rmdir due to non-empty target directory. */
static int
errno_rmdir_non_empty (int error_number)
{
return (error_number == RMDIR_ERRNO_NOT_EMPTY);
}
/* Remove any empty parent directories of PATH.
If PATH contains slash characters, at least one of them
(beginning with the rightmost) is replaced with a NUL byte. */
static int
remove_parents (char *path)
{
char *slash;
int fail = 0;
strip_trailing_slashes (path);
while (1)
{
slash = strrchr (path, '/');
if (slash == NULL)
break;
/* Remove any characters after the slash, skipping any extra
slashes in a row. */
while (slash > path && *slash == '/')
--slash;
slash[1] = 0;
/* Give a diagnostic for each attempted removal if --verbose. */
if (verbose)
error (0, 0, _("removing directory, %s"), path);
fail = rmdir (path);
if (fail)
{
/* Stop quietly if --ignore-fail-on-non-empty. */
if (ignore_fail_on_non_empty
&& errno_rmdir_non_empty (errno))
{
fail = 0;
}
else
{
error (0, errno, "%s", quote (path));
}
break;
}
}
return fail;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name);
fputs (_("\
Remove the DIRECTORY(ies), if they are empty.\n\
\n\
--ignore-fail-on-non-empty\n\
ignore each failure that is solely because a directory\n\
is non-empty\n\
"), stdout);
fputs (_("\
-p, --parents remove DIRECTORY, then try to remove each directory\n\
component of that path name. E.g., `rmdir -p a/b/c' is\n\
similar to `rmdir a/b/c a/b a'.\n\
-v, --verbose output a diagnostic for every directory processed\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int errors = 0;
int optc;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
empty_paths = 0;
while ((optc = getopt_long (argc, argv, "pv", longopts, NULL)) != -1)
{
switch (optc)
{
case 0: /* Long option. */
break;
case 'p':
empty_paths = 1;
break;
case IGNORE_FAIL_ON_NON_EMPTY_OPTION:
ignore_fail_on_non_empty = 1;
break;
case 'v':
verbose = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind == argc)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
for (; optind < argc; ++optind)
{
int fail;
char *dir = argv[optind];
/* Give a diagnostic for each attempted removal if --verbose. */
if (verbose)
error (0, 0, _("removing directory, %s"), dir);
fail = rmdir (dir);
if (fail)
{
if (ignore_fail_on_non_empty
&& errno_rmdir_non_empty (errno))
continue;
error (0, errno, "%s", quote (dir));
errors = 1;
}
else if (empty_paths)
{
errors += remove_parents (dir);
}
}
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+466
View File
@@ -0,0 +1,466 @@
/* seq - print sequence of numbers to standard output.
Copyright (C) 1994-2003 Free Software Foundation, Inc.
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, 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. */
/* Written by Ulrich Drepper. */
#include <config.h>
#include <getopt.h>
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "xstrtol.h"
#include "xstrtod.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "seq"
#define AUTHORS "Ulrich Drepper"
/* If nonzero print all number with equal width. */
static int equal_width;
/* The name that this program was run with. */
char *program_name;
/* The string used to separate two numbers. */
static char *separator;
/* The string output after all numbers have been output.
Usually "\n" or "\0". */
/* FIXME: make this an option. */
static char *terminator = "\n";
/* The representation of the decimal point in the current locale.
Always "." if the localeconv function is not supported. */
static char *decimal_point = ".";
/* The starting number. */
static double first;
/* The increment. */
static double step;
/* The last number. */
static double last;
static struct option const long_options[] =
{
{ "equal-width", no_argument, NULL, 'w'},
{ "format", required_argument, NULL, 'f'},
{ "separator", required_argument, NULL, 's'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{ NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... LAST\n\
or: %s [OPTION]... FIRST LAST\n\
or: %s [OPTION]... FIRST INCREMENT LAST\n\
"), program_name, program_name, program_name);
fputs (_("\
Print numbers from FIRST to LAST, in steps of INCREMENT.\n\
\n\
-f, --format=FORMAT use printf style floating-point FORMAT (default: %g)\n\
-s, --separator=STRING use STRING to separate numbers (default: \\n)\n\
-w, --equal-width equalize width by padding with leading zeroes\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
If FIRST or INCREMENT is omitted, it defaults to 1.\n\
FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\
INCREMENT should be positive if FIRST is smaller than LAST, and negative\n\
otherwise. When given, the FORMAT argument must contain exactly one of\n\
the printf-style, floating point output formats %e, %f, %g\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Read a double value from the command line.
Return if the string is correct else signal error. */
static double
scan_double_arg (const char *arg)
{
double ret_val;
if (xstrtod (arg, NULL, &ret_val))
{
error (0, 0, _("invalid floating point argument: %s"), arg);
usage (EXIT_FAILURE);
}
return ret_val;
}
/* Check whether the format string is valid for a single `double'
argument. Return 0 if not, 1 if correct. */
static int
valid_format (const char *fmt)
{
while (*fmt != '\0')
{
if (*fmt == '%')
{
fmt++;
if (*fmt != '%')
break;
}
fmt++;
}
if (*fmt == '\0')
return 0;
fmt += strspn (fmt, "-+#0 '");
if (ISDIGIT (*fmt) || *fmt == '.')
{
fmt += strspn (fmt, "0123456789");
if (*fmt == '.')
{
++fmt;
fmt += strspn (fmt, "0123456789");
}
}
if (!(*fmt == 'e' || *fmt == 'f' || *fmt == 'g'))
return 0;
fmt++;
while (*fmt != '\0')
{
if (*fmt == '%')
{
fmt++;
if (*fmt != '%')
return 0;
}
fmt++;
}
return 1;
}
/* Actually print the sequence of numbers in the specified range, with the
given or default stepping and format. */
static int
print_numbers (const char *fmt)
{
if (first > last)
{
int i;
if (step >= 0)
{
error (0, 0,
_("when the starting value is larger than the limit,\n\
the increment must be negative"));
usage (EXIT_FAILURE);
}
printf (fmt, first);
for (i = 1; /* empty */; i++)
{
double x = first + i * step;
if (x < last)
break;
fputs (separator, stdout);
printf (fmt, x);
}
}
else
{
int i;
if (step <= 0)
{
error (0, 0,
_("when the starting value is smaller than the limit,\n\
the increment must be positive"));
usage (EXIT_FAILURE);
}
printf (fmt, first);
for (i = 1; /* empty */; i++)
{
double x = first + i * step;
if (x > last)
break;
fputs (separator, stdout);
printf (fmt, x);
}
}
fputs (terminator, stdout);
return 0;
}
#if HAVE_RINT && HAVE_MODF && HAVE_FLOOR
/* Return a printf-style format string with which all selected numbers
will format to strings of the same width. */
static char *
get_width_format ()
{
static char buffer[256];
int full_width;
int frac_width;
int width1, width2;
double max_val;
double min_val;
double temp;
if (first > last)
{
min_val = first - step * floor ((first - last) / step);
max_val = first;
}
else
{
min_val = first;
max_val = first + step * floor ((last - first) / step);
}
sprintf (buffer, "%g", rint (max_val));
if (buffer[strspn (buffer, "0123456789")] != '\0')
return "%g";
width1 = strlen (buffer);
if (min_val < 0.0)
{
double int_min_val = rint (min_val);
sprintf (buffer, "%g", int_min_val);
if (buffer[strspn (buffer, "-0123456789")] != '\0')
return "%g";
/* On some systems, `seq -w -.1 .1 .1' results in buffer being `-0'.
On others, it is just `0'. The former results in better output. */
width2 = (int_min_val == 0 ? 2 : strlen (buffer));
width1 = width1 > width2 ? width1 : width2;
}
full_width = width1;
sprintf (buffer, "%g", 1.0 + modf (fabs (min_val), &temp));
width1 = strlen (buffer);
if (width1 == 1)
width1 = 0;
else
{
if (buffer[0] != '1'
/* FIXME: assumes that decimal_point is a single character
string. */
|| buffer[1] != decimal_point[0]
|| buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
return "%g";
width1 -= 2;
}
sprintf (buffer, "%g", 1.0 + modf (fabs (step), &temp));
width2 = strlen (buffer);
if (width2 == 1)
width2 = 0;
else
{
if (buffer[0] != '1'
/* FIXME: assumes that decimal_point is a single character
string. */
|| buffer[1] != decimal_point[0]
|| buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
return "%g";
width2 -= 2;
}
frac_width = width1 > width2 ? width1 : width2;
if (frac_width)
sprintf (buffer, "%%0%d.%df", full_width + 1 + frac_width, frac_width);
else
sprintf (buffer, "%%0%dg", full_width);
return buffer;
}
#else /* one of the math functions rint, modf, floor is missing. */
static char *
get_width_format (void)
{
/* We cannot compute the needed information to determine the correct
answer. So we simply return a value that works for all cases. */
return "%g";
}
#endif
int
main (int argc, char **argv)
{
int errs;
int optc;
int step_is_set;
/* The printf(3) format used for output. */
char *format_str = NULL;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
equal_width = 0;
separator = "\n";
first = 1.0;
step_is_set = 0;
/* Figure out the locale's idea of a decimal point. */
#if HAVE_LOCALECONV
{
struct lconv *locale;
locale = localeconv ();
/* Paranoia. */
if (locale && locale->decimal_point && locale->decimal_point[0] != '\0')
decimal_point = locale->decimal_point;
}
#endif
/* We have to handle negative numbers in the command line but this
conflicts with the command line arguments. So explicitly check first
whether the next argument looks like a negative number. */
while (optind < argc)
{
if (argv[optind][0] == '-'
&& ((optc = argv[optind][1]) == decimal_point[0]
|| ISDIGIT (optc)))
{
/* means negative number */
break;
}
optc = getopt_long (argc, argv, "+f:s:w", long_options, NULL);
if (optc == -1)
break;
switch (optc)
{
case 0:
break;
case 'f':
format_str = optarg;
break;
case 's':
separator = optarg;
break;
case 'w':
equal_width = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc - optind < 1)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
if (3 < argc - optind)
{
error (0, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
if (format_str && !valid_format (format_str))
{
error (0, 0, _("invalid format string: `%s'"), format_str);
usage (EXIT_FAILURE);
}
last = scan_double_arg (argv[optind++]);
if (optind < argc)
{
first = last;
last = scan_double_arg (argv[optind++]);
if (optind < argc)
{
step = last;
step_is_set = 1;
last = scan_double_arg (argv[optind++]);
}
}
if (format_str != NULL && equal_width)
{
error (0, 0, _("\
format string may not be specified when printing equal width strings"));
usage (EXIT_FAILURE);
}
if (!step_is_set)
{
step = first <= last ? 1.0 : -1.0;
}
if (format_str == NULL)
{
if (equal_width)
format_str = get_width_format ();
else
format_str = "%g";
}
errs = print_numbers (format_str);
exit (errs);
}
+7
View File
@@ -0,0 +1,7 @@
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "checksum.h"
int algorithm = ALG_SHA1;
File diff suppressed because it is too large Load Diff
+169
View File
@@ -0,0 +1,169 @@
/* sleep - delay for a specified amount of time.
Copyright (C) 84, 1991-1997, 1999-2003 Free Software Foundation, Inc.
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, 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. */
#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "long-options.h"
#include "xnanosleep.h"
#include "xstrtod.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "sleep"
#define AUTHORS N_ ("Jim Meyering and Paul Eggert")
/* The name by which this program was run. */
char *program_name;
static struct option const long_options[] =
{
{0, 0, 0, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s NUMBER[SUFFIX]...\n\
or: %s OPTION\n\
Pause for NUMBER seconds. SUFFIX may be `s' for seconds (the default),\n\
`m' for minutes, `h' for hours or `d' for days. Unlike most implementations\n\
that require NUMBER be an integer, here NUMBER may be an arbitrary floating\n\
point number.\n\
\n\
"),
program_name, program_name);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
/* Given a floating point value *X, and a suffix character, SUFFIX_CHAR,
scale *X by the multiplier implied by SUFFIX_CHAR. SUFFIX_CHAR may
be the NUL byte or `s' to denote seconds, `m' for minutes, `h' for
hours, or `d' for days. If SUFFIX_CHAR is invalid, don't modify *X
and return nonzero. Otherwise return zero. */
static int
apply_suffix (double *x, char suffix_char)
{
unsigned int multiplier;
switch (suffix_char)
{
case 0:
case 's':
multiplier = 1;
break;
case 'm':
multiplier = 60;
break;
case 'h':
multiplier = 60 * 60;
break;
case 'd':
multiplier = 60 * 60 * 24;
break;
default:
multiplier = 0;
}
if (multiplier == 0)
return 1;
*x *= multiplier;
return 0;
}
int
main (int argc, char **argv)
{
int i;
double seconds = 0.0;
int c;
int fail = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
AUTHORS, usage);
while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
{
switch (c)
{
case 0:
break;
default:
usage (EXIT_FAILURE);
}
}
if (argc == 1)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
for (i = optind; i < argc; i++)
{
double s;
const char *p;
if (xstrtod (argv[i], &p, &s)
/* Nonnegative interval. */
|| ! (0 <= s)
/* No extra chars after the number and an optional s,m,h,d char. */
|| (*p && *(p+1))
/* Check any suffix char and update S based on the suffix. */
|| apply_suffix (&s, *p))
{
error (0, 0, _("invalid time interval `%s'"), argv[i]);
fail = 1;
}
seconds += s;
}
if (fail)
usage (EXIT_FAILURE);
if (xnanosleep (seconds))
error (EXIT_FAILURE, errno, _("cannot read realtime clock"));
exit (EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
+550
View File
@@ -0,0 +1,550 @@
/* split.c -- split a file into pieces.
Copyright (C) 88, 91, 1995-2003 Free Software Foundation, Inc.
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, 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. */
/* By [email protected], with rms.
To do:
* Implement -t CHAR or -t REGEX to specify break characters other
than newline. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include "dirname.h"
#include "error.h"
#include "full-read.h"
#include "full-write.h"
#include "posixver.h"
#include "safe-read.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "split"
#define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman")
#define DEFAULT_SUFFIX_LENGTH 2
/* The name this program was run with. */
char *program_name;
/* Base name of output files. */
static char const *outbase;
/* Name of output files. */
static char *outfile;
/* Pointer to the end of the prefix in OUTFILE.
Suffixes are inserted here. */
static char *outfile_mid;
/* Length of OUTFILE's suffix. */
static size_t suffix_length = DEFAULT_SUFFIX_LENGTH;
/* Name of input file. May be "-". */
static char *infile;
/* Descriptor on which input file is open. */
static int input_desc;
/* Descriptor on which output file is open. */
static int output_desc;
/* If nonzero, print a diagnostic on standard error just before each
output file is opened. */
static int verbose;
static struct option const longopts[] =
{
{"bytes", required_argument, NULL, 'b'},
{"lines", required_argument, NULL, 'l'},
{"line-bytes", required_argument, NULL, 'C'},
{"suffix-length", required_argument, NULL, 'a'},
{"verbose", no_argument, &verbose, 0},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION] [INPUT [PREFIX]]\n\
"),
program_name);
fputs (_("\
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fprintf (stdout, _("\
-a, --suffix-length=N use suffixes of length N (default %d)\n\
-b, --bytes=SIZE put SIZE bytes per output file\n\
-C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\
-l, --lines=NUMBER put NUMBER lines per output file\n\
"), DEFAULT_SUFFIX_LENGTH);
fputs (_("\
--verbose print a diagnostic to standard error just\n\
before each output file is opened\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Compute the next sequential output file name and store it into the
string `outfile'. */
static void
next_file_name (void)
{
if (! outfile)
{
/* Allocate and initialize the first file name. */
size_t outbase_length = strlen (outbase);
size_t outfile_length = outbase_length + suffix_length;
if (outfile_length + 1 < outbase_length)
xalloc_die ();
outfile = xmalloc (outfile_length + 1);
outfile_mid = outfile + outbase_length;
memcpy (outfile, outbase, outbase_length);
memset (outfile_mid, 'a', suffix_length);
outfile[outfile_length] = 0;
#if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
/* POSIX requires that if the output file name is too long for
its directory, `split' must fail without creating any files.
This must be checked for explicitly on operating systems that
silently truncate file names. */
{
char *dir = dir_name (outfile);
long name_max = pathconf (dir, _PC_NAME_MAX);
if (0 <= name_max && name_max < base_len (base_name (outfile)))
error (EXIT_FAILURE, ENAMETOOLONG, "%s", outfile);
free (dir);
}
#endif
}
else
{
/* Increment the suffix in place, if possible. */
char *p;
for (p = outfile_mid + suffix_length; outfile_mid < p; *--p = 'a')
if (p[-1]++ != 'z')
return;
error (EXIT_FAILURE, 0, _("Output file suffixes exhausted"));
}
}
/* Write BYTES bytes at BP to an output file.
If NEW_FILE_FLAG is nonzero, open the next output file.
Otherwise add to the same output file already in use. */
static void
cwrite (int new_file_flag, const char *bp, size_t bytes)
{
if (new_file_flag)
{
if (output_desc >= 0 && close (output_desc) < 0)
error (EXIT_FAILURE, errno, "%s", outfile);
next_file_name ();
if (verbose)
fprintf (stderr, _("creating file `%s'\n"), outfile);
output_desc = open (outfile,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (output_desc < 0)
error (EXIT_FAILURE, errno, "%s", outfile);
}
if (full_write (output_desc, bp, bytes) != bytes)
error (EXIT_FAILURE, errno, "%s", outfile);
}
/* Split into pieces of exactly NCHARS bytes.
Use buffer BUF, whose size is BUFSIZE. */
static void
bytes_split (size_t nchars, char *buf, size_t bufsize)
{
size_t n_read;
int new_file_flag = 1;
size_t to_read;
size_t to_write = nchars;
char *bp_out;
do
{
n_read = full_read (input_desc, buf, bufsize);
if (n_read == SAFE_READ_ERROR)
error (EXIT_FAILURE, errno, "%s", infile);
bp_out = buf;
to_read = n_read;
for (;;)
{
if (to_read < to_write)
{
if (to_read) /* do not write 0 bytes! */
{
cwrite (new_file_flag, bp_out, to_read);
to_write -= to_read;
new_file_flag = 0;
}
break;
}
cwrite (new_file_flag, bp_out, to_write);
bp_out += to_write;
to_read -= to_write;
new_file_flag = 1;
to_write = nchars;
}
}
while (n_read == bufsize);
}
/* Split into pieces of exactly NLINES lines.
Use buffer BUF, whose size is BUFSIZE. */
static void
lines_split (size_t nlines, char *buf, size_t bufsize)
{
size_t n_read;
char *bp, *bp_out, *eob;
int new_file_flag = 1;
size_t n = 0;
do
{
n_read = full_read (input_desc, buf, bufsize);
if (n_read == SAFE_READ_ERROR)
error (EXIT_FAILURE, errno, "%s", infile);
bp = bp_out = buf;
eob = bp + n_read;
*eob = '\n';
for (;;)
{
bp = memchr (bp, '\n', eob - bp + 1);
if (bp == eob)
{
if (eob != bp_out) /* do not write 0 bytes! */
{
size_t len = eob - bp_out;
cwrite (new_file_flag, bp_out, len);
new_file_flag = 0;
}
break;
}
++bp;
if (++n >= nlines)
{
cwrite (new_file_flag, bp_out, bp - bp_out);
bp_out = bp;
new_file_flag = 1;
n = 0;
}
}
}
while (n_read == bufsize);
}
/* Split into pieces that are as large as possible while still not more
than NCHARS bytes, and are split on line boundaries except
where lines longer than NCHARS bytes occur. */
static void
line_bytes_split (size_t nchars)
{
size_t n_read;
char *bp;
int eof = 0;
size_t n_buffered = 0;
char *buf = (char *) xmalloc (nchars);
do
{
/* Fill up the full buffer size from the input file. */
n_read = full_read (input_desc, buf + n_buffered, nchars - n_buffered);
if (n_read == SAFE_READ_ERROR)
error (EXIT_FAILURE, errno, "%s", infile);
n_buffered += n_read;
if (n_buffered != nchars)
eof = 1;
/* Find where to end this chunk. */
bp = buf + n_buffered;
if (n_buffered == nchars)
{
while (bp > buf && bp[-1] != '\n')
bp--;
}
/* If chunk has no newlines, use all the chunk. */
if (bp == buf)
bp = buf + n_buffered;
/* Output the chars as one output file. */
cwrite (1, buf, bp - buf);
/* Discard the chars we just output; move rest of chunk
down to be the start of the next chunk. Source and
destination probably overlap. */
n_buffered -= bp - buf;
if (n_buffered > 0)
memmove (buf, bp, n_buffered);
}
while (!eof);
free (buf);
}
#define FAIL_ONLY_ONE_WAY() \
do \
{ \
error (0, 0, _("cannot split in more than one way")); \
usage (EXIT_FAILURE); \
} \
while (0)
int
main (int argc, char **argv)
{
struct stat stat_buf;
size_t num; /* numeric argument from command line */
enum
{
type_undef, type_bytes, type_byteslines, type_lines, type_digits
} split_type = type_undef;
size_t in_blk_size; /* optimal block size of input file device */
char *buf; /* file i/o buffer */
size_t accum = 0;
int c;
int digits_optind = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
/* Parse command line options. */
infile = "-";
outbase = "x";
while (1)
{
/* This is the argv-index of the option we will read next. */
int this_optind = optind ? optind : 1;
long int tmp_long;
c = getopt_long (argc, argv, "0123456789C:a:b:l:", longopts, NULL);
if (c == -1)
break;
switch (c)
{
case 0:
break;
case 'a':
{
unsigned long tmp;
if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
|| SIZE_MAX < tmp)
{
error (0, 0, _("%s: invalid suffix length"), optarg);
usage (EXIT_FAILURE);
}
suffix_length = tmp;
}
break;
case 'b':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_bytes;
if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
{
error (0, 0, _("%s: invalid number of bytes"), optarg);
usage (EXIT_FAILURE);
}
accum = /* FIXME: */ (int) tmp_long;
break;
case 'l':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_lines;
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
{
error (0, 0, _("%s: invalid number of lines"), optarg);
usage (EXIT_FAILURE);
}
accum = /* FIXME */ (int) tmp_long;
break;
case 'C':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_byteslines;
if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
|| tmp_long < 0 || tmp_long > INT_MAX)
{
error (0, 0, _("%s: invalid number of bytes"), optarg);
usage (EXIT_FAILURE);
}
accum = /* FIXME */ (int) tmp_long;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (split_type != type_undef && split_type != type_digits)
FAIL_ONLY_ONE_WAY ();
if (digits_optind != 0 && digits_optind != this_optind)
accum = 0; /* More than one number given; ignore other. */
digits_optind = this_optind;
split_type = type_digits;
accum = accum * 10 + c - '0';
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (digits_optind && 200112 <= posix2_version ())
{
error (0, 0, _("`-%d' option is obsolete; use `-l %d'"), accum, accum);
usage (EXIT_FAILURE);
}
/* Handle default case. */
if (split_type == type_undef)
{
split_type = type_lines;
accum = 1000;
}
if (accum < 1)
{
error (0, 0, _("invalid number"));
usage (EXIT_FAILURE);
}
num = accum;
/* Get out the filename arguments. */
if (optind < argc)
infile = argv[optind++];
if (optind < argc)
outbase = argv[optind++];
if (optind < argc)
{
error (0, 0, _("too many arguments"));
usage (EXIT_FAILURE);
}
/* Open the input file. */
if (STREQ (infile, "-"))
input_desc = 0;
else
{
input_desc = open (infile, O_RDONLY);
if (input_desc < 0)
error (EXIT_FAILURE, errno, "%s", infile);
}
/* Binary I/O is safer when bytecounts are used. */
SET_BINARY (input_desc);
/* No output file is open now. */
output_desc = -1;
/* Get the optimal block size of input device and make a buffer. */
if (fstat (input_desc, &stat_buf) < 0)
error (EXIT_FAILURE, errno, "%s", infile);
in_blk_size = ST_BLKSIZE (stat_buf);
buf = xmalloc (in_blk_size + 1);
switch (split_type)
{
case type_digits:
case type_lines:
lines_split (num, buf, in_blk_size);
break;
case type_bytes:
bytes_split (num, buf, in_blk_size);
break;
case type_byteslines:
line_bytes_split (num);
break;
default:
abort ();
}
if (close (input_desc) < 0)
error (EXIT_FAILURE, errno, "%s", infile);
if (output_desc >= 0 && close (output_desc) < 0)
error (EXIT_FAILURE, errno, "%s", outfile);
exit (EXIT_SUCCESS);
}
+815
View File
@@ -0,0 +1,815 @@
/* stat.c -- display file or filesystem status
Copyright (C) 2001, 2002, 2003 Free Software Foundation.
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, 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.
Written by Michael Meskes. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <time.h>
#if HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#if HAVE_SYS_VFS_H
# include <sys/vfs.h>
#endif
/* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
#if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H
# if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
# include <sys/param.h>
# include <sys/mount.h>
# endif
#endif
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "filemode.h"
#include "file-type.h"
#include "fs.h"
#include "getopt.h"
#include "quote.h"
#include "quotearg.h"
#include "strftime.h"
#include "xreadlink.h"
#define NAMEMAX_FORMAT PRIuMAX
#if HAVE_STRUCT_STATVFS_F_BASETYPE
# define STRUCT_STATVFS struct statvfs
# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
# if HAVE_STRUCT_STATVFS_F_NAMEMAX
# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
# endif
#else
# define STRUCT_STATVFS struct statfs
# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
# if HAVE_STRUCT_STATFS_F_NAMELEN
# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
# endif
#endif
#ifndef SB_F_NAMEMAX
/* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
# define SB_F_NAMEMAX(S) "*"
# undef NAMEMAX_FORMAT
# define NAMEMAX_FORMAT "s"
#endif
#if HAVE_STRUCT_STATVFS_F_BASETYPE
# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
#else
# if HAVE_STRUCT_STATFS_F_FSTYPENAME
# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
# endif
#endif
#define PROGRAM_NAME "stat"
#define AUTHORS "Michael Meskes"
static struct option const long_options[] = {
{"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
{"dereference", no_argument, 0, 'L'},
{"format", required_argument, 0, 'c'},
{"filesystem", no_argument, 0, 'f'},
{"terse", no_argument, 0, 't'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
/* Nonzero means we should exit with EXIT_FAILURE upon completion. */
static int G_fail;
char *program_name;
/* Return the type of the specified file system.
Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
Still others have neither and have to get by with f_type (Linux). */
static char *
human_fstype (STRUCT_STATVFS const *statfsbuf)
{
#ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
/* Cast away the `const' attribute. */
return (char *) statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
#else
char const *type;
switch (statfsbuf->f_type)
{
# if defined __linux__
case S_MAGIC_AFFS:
type = "affs";
break;
case S_MAGIC_EXT:
type = "ext";
break;
case S_MAGIC_EXT2_OLD:
type = "ext2";
break;
case S_MAGIC_EXT2:
type = "ext2/ext3";
break;
case S_MAGIC_HPFS:
type = "hpfs";
break;
case S_MAGIC_ISOFS:
type = "isofs";
break;
case S_MAGIC_ISOFS_WIN:
type = "isofs";
break;
case S_MAGIC_ISOFS_R_WIN:
type = "isofs";
break;
case S_MAGIC_MINIX:
type = "minix";
break;
case S_MAGIC_MINIX_30:
type = "minix (30 char.)";
break;
case S_MAGIC_MINIX_V2:
type = "minix v2";
break;
case S_MAGIC_MINIX_V2_30:
type = "minix v2 (30 char.)";
break;
case S_MAGIC_MSDOS:
type = "msdos";
break;
case S_MAGIC_FAT:
type = "fat";
break;
case S_MAGIC_NCP:
type = "novell";
break;
case S_MAGIC_NFS:
type = "nfs";
break;
case S_MAGIC_PROC:
type = "proc";
break;
case S_MAGIC_SMB:
type = "smb";
break;
case S_MAGIC_XENIX:
type = "xenix";
break;
case S_MAGIC_SYSV4:
type = "sysv4";
break;
case S_MAGIC_SYSV2:
type = "sysv2";
break;
case S_MAGIC_COH:
type = "coh";
break;
case S_MAGIC_UFS:
type = "ufs";
break;
case S_MAGIC_XIAFS:
type = "xia";
break;
case S_MAGIC_NTFS:
type = "ntfs";
break;
case S_MAGIC_TMPFS:
type = "tmpfs";
break;
case S_MAGIC_REISERFS:
type = "reiserfs";
break;
case S_MAGIC_CRAMFS:
type = "cramfs";
break;
case S_MAGIC_ROMFS:
type = "romfs";
break;
# elif __GNU__
case FSTYPE_UFS:
type = "ufs";
break;
case FSTYPE_NFS:
type = "nfs";
break;
case FSTYPE_GFS:
type = "gfs";
break;
case FSTYPE_LFS:
type = "lfs";
break;
case FSTYPE_SYSV:
type = "sysv";
break;
case FSTYPE_FTP:
type = "ftp";
break;
case FSTYPE_TAR:
type = "tar";
break;
case FSTYPE_AR:
type = "ar";
break;
case FSTYPE_CPIO:
type = "cpio";
break;
case FSTYPE_MSLOSS:
type = "msloss";
break;
case FSTYPE_CPM:
type = "cpm";
break;
case FSTYPE_HFS:
type = "hfs";
break;
case FSTYPE_DTFS:
type = "dtfs";
break;
case FSTYPE_GRFS:
type = "grfs";
break;
case FSTYPE_TERM:
type = "term";
break;
case FSTYPE_DEV:
type = "dev";
break;
case FSTYPE_PROC:
type = "proc";
break;
case FSTYPE_IFSOCK:
type = "ifsock";
break;
case FSTYPE_AFS:
type = "afs";
break;
case FSTYPE_DFS:
type = "dfs";
break;
case FSTYPE_PROC9:
type = "proc9";
break;
case FSTYPE_SOCKET:
type = "socket";
break;
case FSTYPE_MISC:
type = "misc";
break;
case FSTYPE_EXT2FS:
type = "ext2/ext3";
break;
case FSTYPE_HTTP:
type = "http";
break;
case FSTYPE_MEMFS:
type = "memfs";
break;
case FSTYPE_ISO9660:
type = "iso9660";
break;
# endif
default:
type = NULL;
break;
}
if (type)
return (char *) type;
{
static char buf[sizeof "UNKNOWN (0x%x)" - 2
+ 2 * sizeof (statfsbuf->f_type)];
sprintf (buf, "UNKNOWN (0x%x)", statfsbuf->f_type);
return buf;
}
#endif
}
static char *
human_access (struct stat const *statbuf)
{
static char modebuf[11];
mode_string (statbuf->st_mode, modebuf);
modebuf[10] = 0;
return modebuf;
}
static char *
human_time (time_t const *t)
{
static char str[80];
struct tm *tm = localtime (t);
if (tm == NULL)
{
G_fail = 1;
return (char *) _("*** invalid date/time ***");
}
nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, 0);
return str;
}
/* print statfs info */
static void
print_statfs (char *pformat, char m, char const *filename,
void const *data)
{
STRUCT_STATVFS const *statfsbuf = data;
switch (m)
{
case 'n':
strcat (pformat, "s");
printf (pformat, filename);
break;
case 'i':
#if HAVE_STRUCT_STATXFS_F_FSID___VAL
strcat (pformat, "x %-8x");
printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
statfsbuf->f_fsid.__val[1]);
#else
strcat (pformat, "Lx");
printf (pformat, statfsbuf->f_fsid);
#endif
break;
case 'l':
strcat (pformat, NAMEMAX_FORMAT);
printf (pformat, SB_F_NAMEMAX (statfsbuf));
break;
case 't':
#if HAVE_STRUCT_STATXFS_F_TYPE
strcat (pformat, "lx");
printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */
#else
fputc ('*', stdout);
#endif
break;
case 'T':
strcat (pformat, "s");
printf (pformat, human_fstype (statfsbuf));
break;
case 'b':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_blocks));
break;
case 'f':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_bfree));
break;
case 'a':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_bavail));
break;
case 's':
strcat (pformat, "ld");
printf (pformat, (long int) (statfsbuf->f_bsize));
break;
case 'c':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_files));
break;
case 'd':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_ffree));
break;
default:
strcat (pformat, "c");
printf (pformat, m);
break;
}
}
/* print stat info */
static void
print_stat (char *pformat, char m, char const *filename, void const *data)
{
struct stat *statbuf = (struct stat *) data;
struct passwd *pw_ent;
struct group *gw_ent;
switch (m)
{
case 'n':
strcat (pformat, "s");
printf (pformat, filename);
break;
case 'N':
strcat (pformat, "s");
if (S_ISLNK (statbuf->st_mode))
{
char *linkname = xreadlink (filename);
if (linkname == NULL)
{
error (0, errno, _("cannot read symbolic link %s"),
quote (filename));
return;
}
/*printf("\"%s\" -> \"%s\"", filename, linkname); */
printf (pformat, quote (filename));
printf (" -> ");
printf (pformat, quote (linkname));
}
else
{
printf (pformat, quote (filename));
}
break;
case 'd':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_dev);
break;
case 'D':
strcat (pformat, "x");
printf (pformat, (int) statbuf->st_dev);
break;
case 'i':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_ino);
break;
case 'a':
strcat (pformat, "o");
printf (pformat, statbuf->st_mode & 07777);
break;
case 'A':
strcat (pformat, "s");
printf (pformat, human_access (statbuf));
break;
case 'f':
strcat (pformat, "x");
printf (pformat, statbuf->st_mode);
break;
case 'F':
strcat (pformat, "s");
printf (pformat, file_type (statbuf));
break;
case 'h':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_nlink);
break;
case 'u':
strcat (pformat, "d");
printf (pformat, statbuf->st_uid);
break;
case 'U':
strcat (pformat, "s");
setpwent ();
pw_ent = getpwuid (statbuf->st_uid);
printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
break;
case 'g':
strcat (pformat, "d");
printf (pformat, statbuf->st_gid);
break;
case 'G':
strcat (pformat, "s");
setgrent ();
gw_ent = getgrgid (statbuf->st_gid);
printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
break;
case 't':
strcat (pformat, "x");
printf (pformat, major (statbuf->st_rdev));
break;
case 'T':
strcat (pformat, "x");
printf (pformat, minor (statbuf->st_rdev));
break;
case 's':
strcat (pformat, PRIuMAX);
printf (pformat, (uintmax_t) (statbuf->st_size));
break;
case 'B':
strcat (pformat, "u");
printf (pformat, (unsigned int) ST_NBLOCKSIZE);
break;
case 'b':
strcat (pformat, "u");
printf (pformat, (unsigned int) ST_NBLOCKS (*statbuf));
break;
case 'o':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_blksize);
break;
case 'x':
strcat (pformat, "s");
printf (pformat, human_time (&(statbuf->st_atime)));
break;
case 'X':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_atime);
break;
case 'y':
strcat (pformat, "s");
printf (pformat, human_time (&(statbuf->st_mtime)));
break;
case 'Y':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_mtime);
break;
case 'z':
strcat (pformat, "s");
printf (pformat, human_time (&(statbuf->st_ctime)));
break;
case 'Z':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_ctime);
break;
default:
strcat (pformat, "c");
printf (pformat, m);
break;
}
}
static void
print_it (char const *masterformat, char const *filename,
void (*print_func) (char *, char, char const *, void const *),
void const *data)
{
char *b;
/* create a working copy of the format string */
char *format = xstrdup (masterformat);
char *dest = xmalloc (strlen (format) + 1);
b = format;
while (b)
{
char *p = strchr (b, '%');
if (p != NULL)
{
size_t len;
*p++ = '\0';
fputs (b, stdout);
len = strspn (p, "#-+.I 0123456789");
dest[0] = '%';
memcpy (dest + 1, p, len);
dest[1 + len] = 0;
p += len;
switch (*p)
{
case '\0':
case '%':
putchar ('%');
break;
default:
print_func (dest, *p, filename, data);
break;
}
b = p + 1;
}
else
{
fputs (b, stdout);
b = NULL;
}
}
free (format);
free (dest);
fputc ('\n', stdout);
}
/* stat the filesystem and print what we find */
static void
do_statfs (char const *filename, int terse, char const *format)
{
STRUCT_STATVFS statfsbuf;
int i = statfs (filename, &statfsbuf);
if (i == -1)
{
error (0, errno, _("cannot read file system information for %s"),
quote (filename));
return;
}
if (format == NULL)
{
format = (terse
? "%n %i %l %t %b %f %a %s %c %d"
: " File: \"%n\"\n"
" ID: %-8i Namelen: %-7l Type: %T\n"
"Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
"Inodes: Total: %-10c Free: %-10d");
}
print_it (format, filename, print_statfs, &statfsbuf);
}
/* stat the file and print what we find */
static void
do_stat (char const *filename, int follow_links, int terse,
char const *format)
{
struct stat statbuf;
int i = ((follow_links == 1)
? stat (filename, &statbuf)
: lstat (filename, &statbuf));
if (i == -1)
{
error (0, errno, _("cannot stat %s"), quote (filename));
return;
}
if (format == NULL)
{
if (terse != 0)
{
format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
}
else
{
/* tmp hack to match orignal output until conditional implemented */
i = statbuf.st_mode & S_IFMT;
if (i == S_IFCHR || i == S_IFBLK)
{
format =
" File: %N\n"
" Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
"Device: %Dh/%dd\tInode: %-10i Links: %-5h"
" Device type: %t,%T\n"
"Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
"Access: %x\n" "Modify: %y\n" "Change: %z\n";
}
else
{
format =
" File: %N\n"
" Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
"Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
"Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
"Access: %x\n" "Modify: %y\n" "Change: %z\n";
}
}
}
print_it (format, filename, print_stat, &statbuf);
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
fputs (_("\
Display file or filesystem status.\n\
\n\
-f, --filesystem display filesystem status instead of file status\n\
-c --format=FORMAT use the specified FORMAT instead of the default\n\
-L, --dereference follow links\n\
-t, --terse print the information in terse form\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
The valid format sequences for files (without --filesystem):\n\
\n\
%A Access rights in human readable form\n\
%a Access rights in octal\n\
%B The size in bytes of each block reported by `%b'\n\
%b Number of blocks allocated (see %B)\n\
"), stdout);
fputs (_("\
%D Device number in hex\n\
%d Device number in decimal\n\
%F File type\n\
%f Raw mode in hex\n\
%G Group name of owner\n\
%g Group ID of owner\n\
"), stdout);
fputs (_("\
%h Number of hard links\n\
%i Inode number\n\
%N Quoted File name with dereference if symbolic link\n\
%n File name\n\
%o IO block size\n\
%s Total size, in bytes\n\
%T Minor device type in hex\n\
%t Major device type in hex\n\
"), stdout);
fputs (_("\
%U User name of owner\n\
%u User ID of owner\n\
%X Time of last access as seconds since Epoch\n\
%x Time of last access\n\
%Y Time of last modification as seconds since Epoch\n\
%y Time of last modification\n\
%Z Time of last change as seconds since Epoch\n\
%z Time of last change\n\
\n\
"), stdout);
fputs (_("\
Valid format sequences for file systems:\n\
\n\
%a Free blocks available to non-superuser\n\
%b Total data blocks in file system\n\
%c Total file nodes in file system\n\
%d Free file nodes in file system\n\
%f Free blocks in file system\n\
"), stdout);
fputs (_("\
%i File System id in hex\n\
%l Maximum length of filenames\n\
%n File name\n\
%s Optimal transfer block size\n\
%T Type in human readable form\n\
%t Type in hex\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char *argv[])
{
int c;
int i;
int follow_links = 0;
int fs = 0;
int terse = 0;
char *format = NULL;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
{
switch (c)
{
case 'c':
format = optarg;
break;
case 'l': /* deprecated */
case 'L':
follow_links = 1;
break;
case 'f':
fs = 1;
break;
case 't':
terse = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc == optind)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
for (i = optind; i < argc; i++)
{
if (fs == 0)
do_stat (argv[i], follow_links, terse, format);
else
do_statfs (argv[i], terse, format);
}
exit (G_fail ? EXIT_FAILURE : EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
+583
View File
@@ -0,0 +1,583 @@
/* su for GNU. Run a shell with substitute user and group IDs.
Copyright (C) 1992-2002 Free Software Foundation, Inc.
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, 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. */
/* Run a shell with the real and effective UID and GID and groups
of USER, default `root'.
The shell run is taken from USER's password entry, /bin/sh if
none is specified there. If the account has a password, su
prompts for a password unless run by a user with real UID 0.
Does not change the current directory.
Sets `HOME' and `SHELL' from the password entry for USER, and if
USER is not root, sets `USER' and `LOGNAME' to USER.
The subshell is not a login shell.
If one or more ARGs are given, they are passed as additional
arguments to the subshell.
Does not handle /bin/sh or other shells specially
(setting argv[0] to "-su", passing -c only to certain shells, etc.).
I don't see the point in doing that, and it's ugly.
This program intentionally does not support a "wheel group" that
restricts who can su to UID 0 accounts. RMS considers that to
be fascist.
Options:
-, -l, --login Make the subshell a login shell.
Unset all environment variables except
TERM, HOME and SHELL (set as above), and USER
and LOGNAME (set unconditionally as above), and
set PATH to a default value.
Change to USER's home directory.
Prepend "-" to the shell's name.
-c, --commmand=COMMAND
Pass COMMAND to the subshell with a -c option
instead of starting an interactive shell.
-f, --fast Pass the -f option to the subshell.
-m, -p, --preserve-environment
Do not change HOME, USER, LOGNAME, SHELL.
Run $SHELL instead of USER's shell from /etc/passwd
unless not the superuser and USER's shell is
restricted.
Overridden by --login and --shell.
-s, --shell=shell Run SHELL instead of USER's shell from /etc/passwd
unless not the superuser and USER's shell is
restricted.
Compile-time options:
-DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
-DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
-DSYSLOG_NON_ROOT Log all su's, not just those to root (UID 0).
Never logs attempted su's to nonexistent accounts.
Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
/* Hide any system prototype for getusershell.
This is necessary because some Cray systems have a conflicting
prototype (returning `int') in <unistd.h>. */
#define getusershell _getusershell_sys_proto_
#include "system.h"
#include "closeout.h"
#include "dirname.h"
#undef getusershell
#if HAVE_SYSLOG_H && HAVE_SYSLOG
# include <syslog.h>
#else
# undef SYSLOG_SUCCESS
# undef SYSLOG_FAILURE
# undef SYSLOG_NON_ROOT
#endif
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifndef HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
#ifndef HAVE_ENDPWENT
# define endpwent() ((void) 0)
#endif
#if HAVE_SHADOW_H
# include <shadow.h>
#endif
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "su"
#define AUTHORS "David MacKenzie"
#if HAVE_PATHS_H
# include <paths.h>
#endif
/* The default PATH for simulated logins to non-superuser accounts. */
#ifdef _PATH_DEFPATH
# define DEFAULT_LOGIN_PATH _PATH_DEFPATH
#else
# define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin"
#endif
/* The default PATH for simulated logins to superuser accounts. */
#ifdef _PATH_DEFPATH_ROOT
# define DEFAULT_ROOT_LOGIN_PATH _PATH_DEFPATH_ROOT
#else
# define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc"
#endif
/* The shell to run if none is given in the user's passwd entry. */
#define DEFAULT_SHELL "/bin/sh"
/* The user to become if none is specified. */
#define DEFAULT_USER "root"
char *crypt ();
char *getpass ();
char *getusershell ();
void endusershell ();
void setusershell ();
extern char **environ;
static void run_shell (const char *, const char *, char **)
ATTRIBUTE_NORETURN;
/* The name this program was run with. */
char *program_name;
/* If nonzero, pass the `-f' option to the subshell. */
static int fast_startup;
/* If nonzero, simulate a login instead of just starting a shell. */
static int simulate_login;
/* If nonzero, change some environment vars to indicate the user su'd to. */
static int change_environment;
static struct option const longopts[] =
{
{"command", required_argument, 0, 'c'},
{"fast", no_argument, NULL, 'f'},
{"login", no_argument, NULL, 'l'},
{"preserve-environment", no_argument, &change_environment, 0},
{"shell", required_argument, 0, 's'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
/* Add VAL to the environment, checking for out of memory errors. */
static void
xputenv (char *val)
{
if (putenv (val))
xalloc_die ();
}
/* Return a newly-allocated string whose contents concatenate
those of S1, S2, S3. */
static char *
concat (const char *s1, const char *s2, const char *s3)
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
result[len1 + len2 + len3] = 0;
return result;
}
/* Return the number of elements in ARR, a null-terminated array. */
static int
elements (char **arr)
{
int n = 0;
for (n = 0; *arr; ++arr)
++n;
return n;
}
#if defined (SYSLOG_SUCCESS) || defined (SYSLOG_FAILURE)
/* Log the fact that someone has run su to the user given by PW;
if SUCCESSFUL is nonzero, they gave the correct password, etc. */
static void
log_su (const struct passwd *pw, int successful)
{
const char *new_user, *old_user, *tty;
# ifndef SYSLOG_NON_ROOT
if (pw->pw_uid)
return;
# endif
new_user = pw->pw_name;
/* The utmp entry (via getlogin) is probably the best way to identify
the user, especially if someone su's from a su-shell. */
old_user = getlogin ();
if (old_user == NULL)
{
/* getlogin can fail -- usually due to lack of utmp entry.
Resort to getpwuid. */
struct passwd *pwd = getpwuid (getuid ());
old_user = (pwd ? pwd->pw_name : "");
}
tty = ttyname (2);
if (tty == NULL)
tty = "none";
/* 4.2BSD openlog doesn't have the third parameter. */
openlog (base_name (program_name), 0
# ifdef LOG_AUTH
, LOG_AUTH
# endif
);
syslog (LOG_NOTICE,
# ifdef SYSLOG_NON_ROOT
"%s(to %s) %s on %s",
# else
"%s%s on %s",
# endif
successful ? "" : "FAILED SU ",
# ifdef SYSLOG_NON_ROOT
new_user,
# endif
old_user, tty);
closelog ();
}
#endif
/* Ask the user for a password.
Return 1 if the user gives the correct password for entry PW,
0 if not. Return 1 without asking for a password if run by UID 0
or if PW has an empty password. */
static int
correct_password (const struct passwd *pw)
{
char *unencrypted, *encrypted, *correct;
#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
/* Shadow passwd stuff for SVR3 and maybe other systems. */
struct spwd *sp = getspnam (pw->pw_name);
endspent ();
if (sp)
correct = sp->sp_pwdp;
else
#endif
correct = pw->pw_passwd;
if (getuid () == 0 || correct == 0 || correct[0] == '\0')
return 1;
unencrypted = getpass (_("Password:"));
if (unencrypted == NULL)
{
error (0, 0, _("getpass: cannot open /dev/tty"));
return 0;
}
encrypted = crypt (unencrypted, correct);
memset (unencrypted, 0, strlen (unencrypted));
return strcmp (encrypted, correct) == 0;
}
/* Update `environ' for the new shell based on PW, with SHELL being
the value for the SHELL environment variable. */
static void
modify_environment (const struct passwd *pw, const char *shell)
{
char *term;
if (simulate_login)
{
/* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
Unset all other environment variables. */
term = getenv ("TERM");
environ = (char **) xmalloc (2 * sizeof (char *));
environ[0] = 0;
if (term)
xputenv (concat ("TERM", "=", term));
xputenv (concat ("HOME", "=", pw->pw_dir));
xputenv (concat ("SHELL", "=", shell));
xputenv (concat ("USER", "=", pw->pw_name));
xputenv (concat ("LOGNAME", "=", pw->pw_name));
xputenv (concat ("PATH", "=", (pw->pw_uid
? DEFAULT_LOGIN_PATH
: DEFAULT_ROOT_LOGIN_PATH)));
}
else
{
/* Set HOME, SHELL, and if not becoming a super-user,
USER and LOGNAME. */
if (change_environment)
{
xputenv (concat ("HOME", "=", pw->pw_dir));
xputenv (concat ("SHELL", "=", shell));
if (pw->pw_uid)
{
xputenv (concat ("USER", "=", pw->pw_name));
xputenv (concat ("LOGNAME", "=", pw->pw_name));
}
}
}
}
/* Become the user and group(s) specified by PW. */
static void
change_identity (const struct passwd *pw)
{
#ifdef HAVE_INITGROUPS
errno = 0;
if (initgroups (pw->pw_name, pw->pw_gid) == -1)
error (EXIT_FAILURE, errno, _("cannot set groups"));
endgrent ();
#endif
if (setgid (pw->pw_gid))
error (EXIT_FAILURE, errno, _("cannot set group id"));
if (setuid (pw->pw_uid))
error (EXIT_FAILURE, errno, _("cannot set user id"));
}
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
If COMMAND is nonzero, pass it to the shell with the -c option.
If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
arguments. */
static void
run_shell (const char *shell, const char *command, char **additional_args)
{
const char **args;
int argno = 1;
if (additional_args)
args = (const char **) xmalloc (sizeof (char *)
* (10 + elements (additional_args)));
else
args = (const char **) xmalloc (sizeof (char *) * 10);
if (simulate_login)
{
char *arg0;
char *shell_basename;
shell_basename = base_name (shell);
arg0 = xmalloc (strlen (shell_basename) + 2);
arg0[0] = '-';
strcpy (arg0 + 1, shell_basename);
args[0] = arg0;
}
else
args[0] = base_name (shell);
if (fast_startup)
args[argno++] = "-f";
if (command)
{
args[argno++] = "-c";
args[argno++] = command;
}
if (additional_args)
for (; *additional_args; ++additional_args)
args[argno++] = *additional_args;
args[argno] = NULL;
execv (shell, (char **) args);
{
int exit_status = (errno == ENOENT ? 127 : 126);
error (0, errno, "%s", shell);
exit (exit_status);
}
}
/* Return 1 if SHELL is a restricted shell (one not returned by
getusershell), else 0, meaning it is a standard shell. */
static int
restricted_shell (const char *shell)
{
char *line;
setusershell ();
while ((line = getusershell ()) != NULL)
{
if (*line != '#' && strcmp (line, shell) == 0)
{
endusershell ();
return 0;
}
}
endusershell ();
return 1;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [-] [USER [ARG]...]\n"), program_name);
fputs (_("\
Change the effective user id and group id to that of USER.\n\
\n\
-, -l, --login make the shell a login shell\n\
-c, --commmand=COMMAND pass a single COMMAND to the shell with -c\n\
-f, --fast pass -f to the shell (for csh or tcsh)\n\
-m, --preserve-environment do not reset environment variables\n\
-p same as -m\n\
-s, --shell=SHELL run SHELL if /etc/shells allows it\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
A mere - implies -l. If USER not given, assume root.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
close_stdout ();
}
exit (status);
}
int
main (int argc, char **argv)
{
int optc;
const char *new_user = DEFAULT_USER;
char *command = 0;
char **additional_args = 0;
char *shell = 0;
struct passwd *pw;
struct passwd pw_copy;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
fast_startup = 0;
simulate_login = 0;
change_environment = 1;
while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'c':
command = optarg;
break;
case 'f':
fast_startup = 1;
break;
case 'l':
simulate_login = 1;
break;
case 'm':
case 'p':
change_environment = 0;
break;
case 's':
shell = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind < argc && !strcmp (argv[optind], "-"))
{
simulate_login = 1;
++optind;
}
if (optind < argc)
new_user = argv[optind++];
if (optind < argc)
additional_args = argv + optind;
pw = getpwnam (new_user);
if (pw == 0)
error (EXIT_FAILURE, 0, _("user %s does not exist"), new_user);
endpwent ();
/* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER
is a username that is retrieved via NIS (YP), but that doesn't have
a default shell listed. */
if (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
pw->pw_shell = (char *) DEFAULT_SHELL;
/* Make a copy of the password information and point pw at the local
copy instead. Otherwise, some systems (e.g. Linux) would clobber
the static data through the getlogin call from log_su. */
pw_copy = *pw;
pw = &pw_copy;
pw->pw_name = xstrdup (pw->pw_name);
pw->pw_dir = xstrdup (pw->pw_dir);
pw->pw_shell = xstrdup (pw->pw_shell);
if (!correct_password (pw))
{
#ifdef SYSLOG_FAILURE
log_su (pw, 0);
#endif
error (EXIT_FAILURE, 0, _("incorrect password"));
}
#ifdef SYSLOG_SUCCESS
else
{
log_su (pw, 1);
}
#endif
if (shell == 0 && change_environment == 0)
shell = getenv ("SHELL");
if (shell != 0 && getuid () && restricted_shell (pw->pw_shell))
{
/* The user being su'd to has a nonstandard shell, and so is
probably a uucp account or has restricted access. Don't
compromise the account by allowing access with a standard
shell. */
error (0, 0, _("using restricted shell %s"), pw->pw_shell);
shell = 0;
}
if (shell == 0)
{
shell = xstrdup (pw->pw_shell);
}
modify_environment (pw, shell);
change_identity (pw);
if (simulate_login && chdir (pw->pw_dir))
error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
run_shell (shell, command, additional_args);
}
+273
View File
@@ -0,0 +1,273 @@
/* sum -- checksum and count the blocks in a file
Copyright (C) 86, 89, 91, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */
/* Written by Kayvan Aghaiepour and David MacKenzie. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "human.h"
#include "safe-read.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "sum"
#define AUTHORS N_ ("Kayvan Aghaiepour and David MacKenzie")
/* The name this program was run with. */
char *program_name;
/* Nonzero if any of the files read were the standard input. */
static int have_read_stdin;
static struct option const longopts[] =
{
{"sysv", no_argument, NULL, 's'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Print checksum and block counts for each FILE.\n\
\n\
-r defeat -s, use BSD sum algorithm, use 1K blocks\n\
-s, --sysv use System V sum algorithm, use 512 bytes blocks\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
With no FILE, or when FILE is -, read standard input.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Calculate and print the rotated checksum and the size in 1K blocks
of file FILE, or of the standard input if FILE is "-".
If PRINT_NAME is >1, print FILE next to the checksum and size.
The checksum varies depending on sizeof(int).
Return 0 if successful, -1 if an error occurs. */
static int
bsd_sum_file (const char *file, int print_name)
{
register FILE *fp;
register int checksum = 0; /* The checksum mod 2^16. */
register uintmax_t total_bytes = 0; /* The number of bytes. */
register int ch; /* Each character read. */
char hbuf[LONGEST_HUMAN_READABLE + 1];
if (STREQ (file, "-"))
{
fp = stdin;
have_read_stdin = 1;
}
else
{
fp = fopen (file, "r");
if (fp == NULL)
{
error (0, errno, "%s", file);
return -1;
}
}
/* Need binary I/O, or else byte counts and checksums are incorrect. */
SET_BINARY (fileno(fp));
while ((ch = getc (fp)) != EOF)
{
total_bytes++;
checksum = (checksum >> 1) + ((checksum & 1) << 15);
checksum += ch;
checksum &= 0xffff; /* Keep it within bounds. */
}
if (ferror (fp))
{
error (0, errno, "%s", file);
if (!STREQ (file, "-"))
fclose (fp);
return -1;
}
if (!STREQ (file, "-") && fclose (fp) == EOF)
{
error (0, errno, "%s", file);
return -1;
}
printf ("%05d %5s", checksum,
human_readable (total_bytes, hbuf, human_ceiling, 1, 1024));
if (print_name > 1)
printf (" %s", file);
putchar ('\n');
return 0;
}
/* Calculate and print the checksum and the size in 512-byte blocks
of file FILE, or of the standard input if FILE is "-".
If PRINT_NAME is >0, print FILE next to the checksum and size.
Return 0 if successful, -1 if an error occurs. */
static int
sysv_sum_file (const char *file, int print_name)
{
int fd;
unsigned char buf[8192];
uintmax_t total_bytes = 0;
char hbuf[LONGEST_HUMAN_READABLE + 1];
int r;
int checksum;
/* The sum of all the input bytes, modulo (UINT_MAX + 1). */
unsigned int s = 0;
if (STREQ (file, "-"))
{
fd = 0;
have_read_stdin = 1;
}
else
{
fd = open (file, O_RDONLY);
if (fd == -1)
{
error (0, errno, "%s", file);
return -1;
}
}
/* Need binary I/O, or else byte counts and checksums are incorrect. */
SET_BINARY (fd);
while (1)
{
size_t i;
size_t bytes_read = safe_read (fd, buf, sizeof buf);
if (bytes_read == 0)
break;
if (bytes_read == SAFE_READ_ERROR)
{
error (0, errno, "%s", file);
if (!STREQ (file, "-"))
close (fd);
return -1;
}
for (i = 0; i < bytes_read; i++)
s += buf[i];
total_bytes += bytes_read;
}
if (!STREQ (file, "-") && close (fd) == -1)
{
error (0, errno, "%s", file);
return -1;
}
r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
checksum = (r & 0xffff) + (r >> 16);
printf ("%d %s", checksum,
human_readable (total_bytes, hbuf, human_ceiling, 1, 512));
if (print_name)
printf (" %s", file);
putchar ('\n');
return 0;
}
int
main (int argc, char **argv)
{
int errors = 0;
int optc;
int files_given;
int (*sum_func) (const char *, int) = bsd_sum_file;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
have_read_stdin = 0;
while ((optc = getopt_long (argc, argv, "rs", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'r': /* For SysV compatibility. */
sum_func = bsd_sum_file;
break;
case 's':
sum_func = sysv_sum_file;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
files_given = argc - optind;
if (files_given == 0)
{
if ((*sum_func) ("-", files_given) < 0)
errors = 1;
}
else
for (; optind < argc; optind++)
if ((*sum_func) (argv[optind], files_given) < 0)
errors = 1;
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, "-");
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
+74
View File
@@ -0,0 +1,74 @@
/* sync - update the super block
Copyright (C) 1994-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Jim Meyering */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "error.h"
#include "long-options.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "sync"
#define AUTHORS "Jim Meyering"
/* The name this program was run with. */
char *program_name;
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]\n"), program_name);
fputs (_("\
Force changed blocks to disk, update the super block.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION,
AUTHORS, usage);
if (argc != 1)
error (0, 0, _("ignoring all arguments"));
sync ();
exit (EXIT_SUCCESS);
}
+658
View File
@@ -0,0 +1,658 @@
/* WARNING -- this file is temporary. It is shared between the
sh-utils, fileutils, and textutils packages. Once I find a little
more time, I'll merge the remaining things in system.h and everything
in this file will go back there. */
#ifndef S_IFMT
# define S_IFMT 0170000
#endif
#if STAT_MACROS_BROKEN
# undef S_ISBLK
# undef S_ISCHR
# undef S_ISDIR
# undef S_ISDOOR
# undef S_ISFIFO
# undef S_ISLNK
# undef S_ISNAM
# undef S_ISMPB
# undef S_ISMPC
# undef S_ISNWK
# undef S_ISREG
# undef S_ISSOCK
#endif
#ifndef S_ISBLK
# ifdef S_IFBLK
# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
# else
# define S_ISBLK(m) 0
# endif
#endif
#ifndef S_ISCHR
# ifdef S_IFCHR
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
# else
# define S_ISCHR(m) 0
# endif
#endif
#ifndef S_ISDIR
# ifdef S_IFDIR
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
# else
# define S_ISDIR(m) 0
# endif
#endif
#ifndef S_ISDOOR /* Solaris 2.5 and up */
# ifdef S_IFDOOR
# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR)
# else
# define S_ISDOOR(m) 0
# endif
#endif
#ifndef S_ISFIFO
# ifdef S_IFIFO
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
# else
# define S_ISFIFO(m) 0
# endif
#endif
#ifndef S_ISLNK
# ifdef S_IFLNK
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
# else
# define S_ISLNK(m) 0
# endif
#endif
#ifndef S_ISMPB /* V7 */
# ifdef S_IFMPB
# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
# else
# define S_ISMPB(m) 0
# define S_ISMPC(m) 0
# endif
#endif
#ifndef S_ISNAM /* Xenix */
# ifdef S_IFNAM
# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM)
# else
# define S_ISNAM(m) 0
# endif
#endif
#ifndef S_ISNWK /* HP/UX */
# ifdef S_IFNWK
# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
# else
# define S_ISNWK(m) 0
# endif
#endif
#ifndef S_ISREG
# ifdef S_IFREG
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
# else
# define S_ISREG(m) 0
# endif
#endif
#ifndef S_ISSOCK
# ifdef S_IFSOCK
# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
# else
# define S_ISSOCK(m) 0
# endif
#endif
#ifndef S_TYPEISSEM
# ifdef S_INSEM
# define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM)
# else
# define S_TYPEISSEM(p) 0
# endif
#endif
#ifndef S_TYPEISSHM
# ifdef S_INSHD
# define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD)
# else
# define S_TYPEISSHM(p) 0
# endif
#endif
#ifndef S_TYPEISMQ
# define S_TYPEISMQ(p) 0
#endif
/* If any of the following are undefined,
define them to their de facto standard values. */
#if !S_ISUID
# define S_ISUID 04000
#endif
#if !S_ISGID
# define S_ISGID 02000
#endif
/* S_ISVTX is a common extension to POSIX. */
#ifndef S_ISVTX
# define S_ISVTX 01000
#endif
#if !S_IRUSR && S_IREAD
# define S_IRUSR S_IREAD
#endif
#if !S_IRUSR
# define S_IRUSR 00400
#endif
#if !S_IRGRP
# define S_IRGRP (S_IRUSR >> 3)
#endif
#if !S_IROTH
# define S_IROTH (S_IRUSR >> 6)
#endif
#if !S_IWUSR && S_IWRITE
# define S_IWUSR S_IWRITE
#endif
#if !S_IWUSR
# define S_IWUSR 00200
#endif
#if !S_IWGRP
# define S_IWGRP (S_IWUSR >> 3)
#endif
#if !S_IWOTH
# define S_IWOTH (S_IWUSR >> 6)
#endif
#if !S_IXUSR && S_IEXEC
# define S_IXUSR S_IEXEC
#endif
#if !S_IXUSR
# define S_IXUSR 00100
#endif
#if !S_IXGRP
# define S_IXGRP (S_IXUSR >> 3)
#endif
#if !S_IXOTH
# define S_IXOTH (S_IXUSR >> 6)
#endif
#if !S_IRWXU
# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
#endif
#if !S_IRWXG
# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
#endif
#if !S_IRWXO
# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
#endif
/* S_IXUGO is a common extension to POSIX. */
#if !S_IXUGO
# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
#endif
#ifndef S_IRWXUGO
# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
#endif
/* All the mode bits that can be affected by chmod. */
#define CHMOD_MODE_BITS \
(S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
#ifdef ST_MTIM_NSEC
# define ST_TIME_CMP_NS(a, b, ns) ((a).ns < (b).ns ? -1 : (a).ns > (b).ns)
#else
# define ST_TIME_CMP_NS(a, b, ns) 0
#endif
#define ST_TIME_CMP(a, b, s, ns) \
((a).s < (b).s ? -1 : (a).s > (b).s ? 1 : ST_TIME_CMP_NS(a, b, ns))
#define ATIME_CMP(a, b) ST_TIME_CMP (a, b, st_atime, st_atim.ST_MTIM_NSEC)
#define CTIME_CMP(a, b) ST_TIME_CMP (a, b, st_ctime, st_ctim.ST_MTIM_NSEC)
#define MTIME_CMP(a, b) ST_TIME_CMP (a, b, st_mtime, st_mtim.ST_MTIM_NSEC)
#ifndef RETSIGTYPE
# define RETSIGTYPE void
#endif
#if __GNUC__
# ifndef alloca
# define alloca __builtin_alloca
# endif
#else
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
# pragma alloca
# else
# ifdef _WIN32
# include <malloc.h>
# include <io.h>
# else
# ifndef alloca
char *alloca ();
# endif
# endif
# endif
# endif
#endif
#ifdef __DJGPP__
/* We need the declaration of setmode. */
# include <io.h>
/* We need the declaration of __djgpp_set_ctrl_c. */
# include <sys/exceptn.h>
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h> /* for the definition of UINTMAX_MAX */
#endif
#if !defined PRIdMAX || PRI_MACROS_BROKEN
# undef PRIdMAX
# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
#endif
#if !defined PRIoMAX || PRI_MACROS_BROKEN
# undef PRIoMAX
# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
#endif
#if !defined PRIuMAX || PRI_MACROS_BROKEN
# undef PRIuMAX
# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
#endif
#if !defined PRIxMAX || PRI_MACROS_BROKEN
# undef PRIxMAX
# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
#endif
#include <ctype.h>
/* Jim Meyering writes:
"... Some ctype macros are valid only for character codes that
isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
using /bin/cc or gcc but without giving an ansi option). So, all
ctype uses should be through macros like ISPRINT... If
STDC_HEADERS is defined, then autoconf has verified that the ctype
macros don't need to be guarded with references to isascii. ...
Defining isascii to 1 should let any compiler worth its salt
eliminate the && through constant folding."
Bruno Haible adds:
"... Furthermore, isupper(c) etc. have an undefined result if c is
outside the range -1 <= c <= 255. One is tempted to write isupper(c)
with c being of type `char', but this is wrong if c is an 8-bit
character >= 128 which gets sign-extended to a negative value.
The macro ISUPPER protects against this as well." */
#if STDC_HEADERS || (!defined (isascii) && !HAVE_ISASCII)
# define IN_CTYPE_DOMAIN(c) 1
#else
# define IN_CTYPE_DOMAIN(c) isascii(c)
#endif
#ifdef isblank
# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c))
#else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
#endif
#ifdef isgraph
# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c))
#else
# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c))
#endif
/* This is defined in <sys/euc.h> on at least Solaris2.6 systems. */
#undef ISPRINT
#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c))
#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c))
#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
#if STDC_HEADERS
# define TOLOWER(Ch) tolower (Ch)
# define TOUPPER(Ch) toupper (Ch)
#else
# define TOLOWER(Ch) (ISUPPER (Ch) ? tolower (Ch) : (Ch))
# define TOUPPER(Ch) (ISLOWER (Ch) ? toupper (Ch) : (Ch))
#endif
/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
- Its arg may be any int or unsigned int; it need not be an unsigned char.
- It's guaranteed to evaluate its argument exactly once.
- It's typically faster.
POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
ISDIGIT_LOCALE unless it's important to use the locale's definition
of `digit' even when the host does not conform to POSIX. */
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
/* Take care of NLS matters. */
#if HAVE_LOCALE_H
# include <locale.h>
#else
# define setlocale(Category, Locale) /* empty */
#endif
#include "gettext.h"
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
#ifndef HAVE_SETLOCALE
# define HAVE_SETLOCALE 0
#endif
#define STREQ(a, b) (strcmp ((a), (b)) == 0)
#if !HAVE_DECL_FREE
void free ();
#endif
#if !HAVE_DECL_MALLOC
char *malloc ();
#endif
#if !HAVE_DECL_MEMCHR
char *memchr ();
#endif
#if !HAVE_DECL_REALLOC
char *realloc ();
#endif
#if !HAVE_DECL_STPCPY
# ifndef stpcpy
char *stpcpy ();
# endif
#endif
#if !HAVE_DECL_STRNDUP
char *strndup ();
#endif
#if !HAVE_DECL_STRSTR
char *strstr ();
#endif
#if !HAVE_DECL_GETENV
char *getenv ();
#endif
#if !HAVE_DECL_LSEEK
off_t lseek ();
#endif
/* This is needed on some AIX systems. */
#if !HAVE_DECL_STRTOUL
unsigned long strtoul ();
#endif
/* This is needed on some AIX systems. */
#if !HAVE_DECL_STRTOULL && HAVE_UNSIGNED_LONG_LONG
unsigned long long strtoull ();
#endif
#if !HAVE_DECL_GETLOGIN
char *getlogin ();
#endif
#if !HAVE_DECL_TTYNAME
char *ttyname ();
#endif
#if !HAVE_DECL_GETEUID
uid_t geteuid ();
#endif
#if !HAVE_DECL_GETPWUID
struct passwd *getpwuid ();
#endif
#if !HAVE_DECL_GETGRGID
struct group *getgrgid ();
#endif
#if !HAVE_DECL_GETUID
uid_t getuid ();
#endif
#include "xalloc.h"
#if ! defined HAVE_MEMPCPY && ! defined mempcpy
/* Be CAREFUL that there are no side effects in N. */
# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
#endif
/* Include automatically-generated macros for unlocked I/O. */
#include "unlocked-io.h"
#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
&& (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
#define DOT_OR_DOTDOT(Basename) \
(Basename[0] == '.' && (Basename[1] == '\0' \
|| (Basename[1] == '.' && Basename[2] == '\0')))
#if SETVBUF_REVERSED
# define SETVBUF(Stream, Buffer, Type, Size) \
setvbuf (Stream, Type, Buffer, Size)
#else
# define SETVBUF(Stream, Buffer, Type, Size) \
setvbuf (Stream, Buffer, Type, Size)
#endif
/* Factor out some of the common --help and --version processing code. */
/* These enum values cannot possibly conflict with the option values
ordinarily used by commands, including CHAR_MAX + 1, etc. Avoid
CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value. */
enum
{
GETOPT_HELP_CHAR = (CHAR_MIN - 2),
GETOPT_VERSION_CHAR = (CHAR_MIN - 3)
};
#define GETOPT_HELP_OPTION_DECL \
"help", no_argument, 0, GETOPT_HELP_CHAR
#define GETOPT_VERSION_OPTION_DECL \
"version", no_argument, 0, GETOPT_VERSION_CHAR
#define case_GETOPT_HELP_CHAR \
case GETOPT_HELP_CHAR: \
usage (EXIT_SUCCESS); \
break;
#define HELP_OPTION_DESCRIPTION \
_(" --help display this help and exit\n")
#define VERSION_OPTION_DESCRIPTION \
_(" --version output version information and exit\n")
#include "closeout.h"
#include "version-etc.h"
#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \
case GETOPT_VERSION_CHAR: \
version_etc (stdout, Program_name, PACKAGE, VERSION, Authors); \
exit (EXIT_SUCCESS); \
break;
#ifndef MAX
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* The extra casts work around common compiler bugs. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
It is necessary at least when t == time_t. */
#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
/* Upper bound on the string length of an integer converted to string.
302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit;
add 1 for integer division truncation; add 1 more for a minus sign. */
#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
#ifndef CHAR_MIN
# define CHAR_MIN TYPE_MINIMUM (char)
#endif
#ifndef CHAR_MAX
# define CHAR_MAX TYPE_MAXIMUM (char)
#endif
#ifndef SCHAR_MIN
# define SCHAR_MIN (-1 - SCHAR_MAX)
#endif
#ifndef SCHAR_MAX
# define SCHAR_MAX (CHAR_MAX == UCHAR_MAX ? CHAR_MAX / 2 : CHAR_MAX)
#endif
#ifndef UCHAR_MAX
# define UCHAR_MAX TYPE_MAXIMUM (unsigned char)
#endif
#ifndef SHRT_MIN
# define SHRT_MIN TYPE_MINIMUM (short int)
#endif
#ifndef SHRT_MAX
# define SHRT_MAX TYPE_MAXIMUM (short int)
#endif
#ifndef INT_MAX
# define INT_MAX TYPE_MAXIMUM (int)
#endif
#ifndef INT_MIN
# define INT_MIN TYPE_MINIMUM (int)
#endif
#ifndef UINT_MAX
# define UINT_MAX TYPE_MAXIMUM (unsigned int)
#endif
#ifndef LONG_MAX
# define LONG_MAX TYPE_MAXIMUM (long)
#endif
#ifndef ULONG_MAX
# define ULONG_MAX TYPE_MAXIMUM (unsigned long)
#endif
#ifndef SIZE_MAX
# define SIZE_MAX TYPE_MAXIMUM (size_t)
#endif
#ifndef SSIZE_MAX
# define SSIZE_MAX TYPE_MAXIMUM (ssize_t)
#endif
#ifndef UINTMAX_MAX
# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t)
#endif
#ifndef OFF_T_MIN
# define OFF_T_MIN TYPE_MINIMUM (off_t)
#endif
#ifndef OFF_T_MAX
# define OFF_T_MAX TYPE_MAXIMUM (off_t)
#endif
#ifndef UID_T_MAX
# define UID_T_MAX TYPE_MAXIMUM (uid_t)
#endif
#ifndef GID_T_MAX
# define GID_T_MAX TYPE_MAXIMUM (gid_t)
#endif
#ifndef PID_T_MAX
# define PID_T_MAX TYPE_MAXIMUM (pid_t)
#endif
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* Use this to suppress gcc's `...may be used before initialized' warnings. */
#ifdef lint
# define IF_LINT(Code) Code
#else
# define IF_LINT(Code) /* empty */
#endif
#ifndef __attribute__
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
# define __attribute__(x)
# endif
#endif
#ifndef ATTRIBUTE_NORETURN
# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#endif
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
#if defined strdupa
# define ASSIGN_STRDUPA(DEST, S) \
do { DEST = strdupa(S); } while (0)
#else
# define ASSIGN_STRDUPA(DEST, S) \
do \
{ \
const char *s_ = (S); \
size_t len_ = strlen (s_) + 1; \
char *tmp_dest_ = (char *) alloca (len_); \
DEST = memcpy (tmp_dest_, (s_), len_); \
} \
while (0)
#endif
#ifndef EOVERFLOW
# define EOVERFLOW EINVAL
#endif
#if ! HAVE_FSEEKO && ! defined fseeko
# define fseeko(s, o, w) ((o) == (long) (o) \
? fseek (s, o, w) \
: (errno = EOVERFLOW, -1))
#endif
+298
View File
@@ -0,0 +1,298 @@
/* system-dependent definitions for fileutils, textutils, and sh-utils packages.
Copyright (C) 1989, 1991-2002 Free Software Foundation, Inc.
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, 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. */
/* Include sys/types.h before this file. */
#if 2 <= __GLIBC__ && 2 <= __GLIBC_MINOR__
# if ! defined _SYS_TYPES_H
you must include <sys/types.h> before including this file
# endif
#endif
#include <sys/stat.h>
#if !defined HAVE_MKFIFO
# define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
#endif
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
/* <unistd.h> should be included before any preprocessor test
of _POSIX_VERSION. */
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#if HAVE_LIMITS_H
/* limits.h must come before pathmax.h because limits.h on some systems
undefs PATH_MAX, whereas pathmax.h sets PATH_MAX. */
# include <limits.h>
#endif
#include "pathmax.h"
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
/* Since major is a function on SVR4, we can't use `ifndef major'. */
#if MAJOR_IN_MKDEV
# include <sys/mkdev.h>
# define HAVE_MAJOR
#endif
#if MAJOR_IN_SYSMACROS
# include <sys/sysmacros.h>
# define HAVE_MAJOR
#endif
#ifdef major /* Might be defined in sys/types.h. */
# define HAVE_MAJOR
#endif
#ifndef HAVE_MAJOR
# define major(dev) (((dev) >> 8) & 0xff)
# define minor(dev) ((dev) & 0xff)
# define makedev(maj, min) (((maj) << 8) | (min))
#endif
#undef HAVE_MAJOR
#if HAVE_UTIME_H
# include <utime.h>
#endif
/* Some systems (even some that do have <utime.h>) don't declare this
structure anywhere. */
#ifndef HAVE_STRUCT_UTIMBUF
struct utimbuf
{
long actime;
long modtime;
};
#endif
/* Don't use bcopy! Use memmove if source and destination may overlap,
memcpy otherwise. */
#if HAVE_STRING_H
# if !STDC_HEADERS && HAVE_MEMORY_H
# include <memory.h>
# endif
# include <string.h>
#else
# include <strings.h>
#endif
#if ! HAVE_DECL_MEMRCHR
void *memrchr (const void *, int, size_t);
#endif
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#if HAVE_STDBOOL_H
# include <stdbool.h>
#else
typedef enum {false = 0, true = 1} bool;
#endif
#if HAVE_STDLIB_H
# define getopt system_getopt
# include <stdlib.h>
# undef getopt
#endif
/* The following test is to work around the gross typo in
systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
is defined to 0, not 1. */
#if !EXIT_FAILURE
# undef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
#endif
#if HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
#if !defined SEEK_SET
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
#endif
#ifndef F_OK
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
#endif
/* For systems that distinguish between text and binary I/O.
O_BINARY is usually declared in fcntl.h */
#if !defined O_BINARY && defined _O_BINARY
/* For MSC-compatible compilers. */
# define O_BINARY _O_BINARY
# define O_TEXT _O_TEXT
#endif
#ifdef __BEOS__
/* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
# undef O_BINARY
# undef O_TEXT
#endif
#if O_BINARY
# ifndef __DJGPP__
# define setmode _setmode
# define fileno(_fp) _fileno (_fp)
# endif /* not DJGPP */
# define SET_MODE(_f, _m) setmode (_f, _m)
# define SET_BINARY(_f) do {if (!isatty(_f)) setmode (_f, O_BINARY);} while (0)
# define SET_BINARY2(_f1, _f2) \
do { \
if (!isatty (_f1)) \
{ \
setmode (_f1, O_BINARY); \
if (!isatty (_f2)) \
setmode (_f2, O_BINARY); \
} \
} while(0)
#else
# define SET_MODE(_f, _m) (void)0
# define SET_BINARY(f) (void)0
# define SET_BINARY2(f1,f2) (void)0
# define O_BINARY 0
# define O_TEXT 0
#endif /* O_BINARY */
#if HAVE_DIRENT_H
# include <dirent.h>
# define NLENGTH(direct) (strlen((direct)->d_name))
#else /* not HAVE_DIRENT_H */
# define dirent direct
# define NLENGTH(direct) ((direct)->d_namlen)
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYS_DIR_H */
# if HAVE_NDIR_H
# include <ndir.h>
# endif /* HAVE_NDIR_H */
#endif /* HAVE_DIRENT_H */
#if CLOSEDIR_VOID
/* Fake a return value. */
# define CLOSEDIR(d) (closedir (d), 0)
#else
# define CLOSEDIR(d) closedir (d)
#endif
/* Get or fake the disk device blocksize.
Usually defined by sys/param.h (if at all). */
#if !defined DEV_BSIZE && defined BSIZE
# define DEV_BSIZE BSIZE
#endif
#if !defined DEV_BSIZE && defined BBSIZE /* SGI */
# define DEV_BSIZE BBSIZE
#endif
#ifndef DEV_BSIZE
# define DEV_BSIZE 4096
#endif
/* Extract or fake data from a `struct stat'.
ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
#ifndef HAVE_STRUCT_STAT_ST_BLOCKS
# define ST_BLKSIZE(statbuf) DEV_BSIZE
# if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
# define ST_NBLOCKS(statbuf) \
((statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0))
# else /* !_POSIX_SOURCE && BSIZE */
# define ST_NBLOCKS(statbuf) \
(S_ISREG ((statbuf).st_mode) \
|| S_ISDIR ((statbuf).st_mode) \
? st_blocks ((statbuf).st_size) : 0)
# endif /* !_POSIX_SOURCE && BSIZE */
#else /* HAVE_STRUCT_STAT_ST_BLOCKS */
/* Some systems, like Sequents, return st_blksize of 0 on pipes.
Also, when running `rsh hpux11-system cat any-file', cat would
determine that the output stream had an st_blksize of 2147421096.
So here we arbitrarily limit the `optimal' block size to 4MB.
If anyone knows of a system for which the legitimate value for
st_blksize can exceed 4MB, please report it as a bug in this code. */
# define ST_BLKSIZE(statbuf) ((0 < (statbuf).st_blksize \
&& (statbuf).st_blksize <= (1 << 22)) /* 4MB */ \
? (statbuf).st_blksize : DEV_BSIZE)
# if defined hpux || defined __hpux__ || defined __hpux
/* HP-UX counts st_blocks in 1024-byte units.
This loses when mixing HP-UX and BSD filesystems with NFS. */
# define ST_NBLOCKSIZE 1024
# else /* !hpux */
# if defined _AIX && defined _I386
/* AIX PS/2 counts st_blocks in 4K units. */
# define ST_NBLOCKSIZE (4 * 1024)
# else /* not AIX PS/2 */
# if defined _CRAY
# define ST_NBLOCKS(statbuf) \
(S_ISREG ((statbuf).st_mode) \
|| S_ISDIR ((statbuf).st_mode) \
? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
# endif /* _CRAY */
# endif /* not AIX PS/2 */
# endif /* !hpux */
#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
#ifndef ST_NBLOCKS
# define ST_NBLOCKS(statbuf) ((statbuf).st_blocks)
#endif
#ifndef ST_NBLOCKSIZE
# define ST_NBLOCKSIZE 512
#endif
#include "sys2.h"
+248
View File
@@ -0,0 +1,248 @@
/* FIXME */
#include <assert.h>
/* FIXME: this is small for testing */
#define BUFFER_SIZE (8)
#define LEN(X, I) ((X)->p[(I)].one_past_end - (X)->p[(I)].start)
#define EMPTY(X) ((X)->n_bufs == 1 && LEN (X, 0) == 0)
#define ONE_PAST_END(X, I) ((X)->p[(I)].one_past_end)
struct Line_ptr
{
size_t i;
char *ptr;
};
typedef struct Line_ptr Line_ptr;
struct B_pair
{
char *start;
char *one_past_end;
};
struct Buf
{
size_t n_bufs;
struct obstack obs;
struct B_pair *p;
};
typedef struct Buf Buf;
static int
buf_init_from_stdin (Buf *x, int eol_byte)
{
int last_byte_is_eol_byte = 1;
int fail = 0;
#define OBS (&(x->obs))
obstack_init (OBS);
while (1)
{
char *buf = (char *) malloc (BUFFER_SIZE);
int bytes_read;
if (buf == NULL)
{
/* Fall back on the code that relies on a temporary file.
Write all buffers to that file and free them. */
/* FIXME */
fail = 1;
break;
}
bytes_read = full_read (STDIN_FILENO, buf, BUFFER_SIZE);
if (bytes_read < 0)
error (EXIT_FAILURE, errno, _("read error"));
{
struct B_pair bp;
bp.start = buf;
bp.one_past_end = buf + bytes_read;
obstack_grow (OBS, &bp, sizeof (bp));
}
if (bytes_read > 0)
last_byte_is_eol_byte = (buf[bytes_read - 1] == eol_byte);
if (bytes_read < BUFFER_SIZE)
break;
}
if (!fail)
{
/* If the file was non-empty and lacked an EOL_BYTE at its end,
then add a buffer containing just that one byte. */
if (!last_byte_is_eol_byte)
{
char *buf = malloc (1);
if (buf == NULL)
{
/* FIXME: just like above */
fail = 1;
}
else
{
struct B_pair bp;
*buf = eol_byte;
bp.start = buf;
bp.one_past_end = buf + 1;
obstack_grow (OBS, &bp, sizeof (bp));
}
}
}
x->n_bufs = obstack_object_size (OBS) / sizeof (x->p[0]);
x->p = (struct B_pair *) obstack_finish (OBS);
/* If there are two or more buffers and the last buffer is empty,
then free the last one and decrement the buffer count. */
if (x->n_bufs >= 2
&& x->p[x->n_bufs - 1].start == x->p[x->n_bufs - 1].one_past_end)
free (x->p[--(x->n_bufs)].start);
return fail;
}
static void
buf_free (Buf *x)
{
int i;
for (i = 0; i < x->n_bufs; i++)
free (x->p[i].start);
obstack_free (OBS, NULL);
}
Line_ptr
line_ptr_decrement (const Buf *x, const Line_ptr *lp)
{
Line_ptr lp_new;
if (lp->ptr > x->p[lp->i].start)
{
lp_new.i = lp->i;
lp_new.ptr = lp->ptr - 1;
}
else
{
assert (lp->i > 0);
lp_new.i = lp->i - 1;
lp_new.ptr = ONE_PAST_END (x, lp->i - 1) - 1;
}
return lp_new;
}
Line_ptr
line_ptr_increment (const Buf *x, const Line_ptr *lp)
{
Line_ptr lp_new;
assert (lp->ptr <= ONE_PAST_END (x, lp->i) - 1);
if (lp->ptr < ONE_PAST_END (x, lp->i) - 1)
{
lp_new.i = lp->i;
lp_new.ptr = lp->ptr + 1;
}
else
{
assert (lp->i < x->n_bufs - 1);
lp_new.i = lp->i + 1;
lp_new.ptr = x->p[lp->i + 1].start;
}
return lp_new;
}
static int
find_bol (const Buf *x,
const Line_ptr *last_bol, Line_ptr *new_bol, char eol_byte)
{
int i;
Line_ptr tmp;
char *last_bol_ptr;
if (last_bol->ptr == x->p[0].start)
return 0;
tmp = line_ptr_decrement (x, last_bol);
last_bol_ptr = tmp.ptr;
i = tmp.i;
while (1)
{
char *nl = memrchr (x->p[i].start, last_bol_ptr, eol_byte);
if (nl)
{
Line_ptr nl_pos;
nl_pos.i = i;
nl_pos.ptr = nl;
*new_bol = line_ptr_increment (x, &nl_pos);
return 1;
}
if (i <= 0)
break;
--i;
last_bol_ptr = ONE_PAST_END (x, i);
}
/* If last_bol->ptr didn't point at the first byte of X, then reaching
this point means that we're about to return the line that is at the
beginning of X. */
if (last_bol->ptr != x->p[0].start)
{
new_bol->i = 0;
new_bol->ptr = x->p[0].start;
return 1;
}
return 0;
}
static void
print_line (FILE *out_stream, const Buf *x,
const Line_ptr *bol, const Line_ptr *bol_next)
{
int i;
for (i = bol->i; i <= bol_next->i; i++)
{
char *a = (i == bol->i ? bol->ptr : x->p[i].start);
char *b = (i == bol_next->i ? bol_next->ptr : ONE_PAST_END (x, i));
fwrite (a, 1, b - a, out_stream);
}
}
static int
tac_mem ()
{
Buf x;
Line_ptr bol;
char eol_byte = '\n';
int fail;
fail = buf_init_from_stdin (&x, eol_byte);
if (fail)
{
buf_free (&x);
return 1;
}
/* Special case the empty file. */
if (EMPTY (&x))
return 0;
/* Initially, point at one past the last byte of the file. */
bol.i = x.n_bufs - 1;
bol.ptr = ONE_PAST_END (&x, bol.i);
while (1)
{
Line_ptr new_bol;
int found = find_bol (&x, &bol, &new_bol, eol_byte);
if (!found)
break;
print_line (stdout, &x, &new_bol, &bol);
bol = new_bol;
}
return 0;
}
+715
View File
@@ -0,0 +1,715 @@
/* tac - concatenate and print files in reverse
Copyright (C) 1988-1991, 1995-2002 Free Software Foundation, Inc.
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, 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. */
/* Written by Jay Lepreau ([email protected]).
GNU enhancements by David MacKenzie (djm@gnu.ai.mit.edu). */
/* Copy each FILE, or the standard input if none are given or when a
FILE name of "-" is encountered, to the standard output with the
order of the records reversed. The records are separated by
instances of a string, or a newline if none is given. By default, the
separator string is attached to the end of the record that it
follows in the file.
Options:
-b, --before The separator is attached to the beginning
of the record that it precedes in the file.
-r, --regex The separator is a regular expression.
-s, --separator=separator Use SEPARATOR as the record separator.
To reverse a file byte by byte, use (in bash, ksh, or sh):
tac -r -s '.\|
' file */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#include "closeout.h"
#include <regex.h>
#include "error.h"
#include "safe-read.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "tac"
#define AUTHORS N_ ("Jay Lepreau and David MacKenzie")
#if defined __MSDOS__ || defined _WIN32
/* Define this to non-zero on systems for which the regular mechanism
(of unlinking an open file and expecting to be able to write, seek
back to the beginning, then reread it) doesn't work. E.g., on Windows
and DOS systems. */
# define DONT_UNLINK_WHILE_OPEN 1
#endif
#ifndef DEFAULT_TMPDIR
# define DEFAULT_TMPDIR "/tmp"
#endif
/* The number of bytes per atomic read. */
#define INITIAL_READSIZE 8192
/* The number of bytes per atomic write. */
#define WRITESIZE 8192
/* The name this program was run with. */
char *program_name;
/* The string that separates the records of the file. */
static char *separator;
/* If nonzero, print `separator' along with the record preceding it
in the file; otherwise with the record following it. */
static int separator_ends_record;
/* 0 if `separator' is to be matched as a regular expression;
otherwise, the length of `separator', used as a sentinel to
stop the search. */
static size_t sentinel_length;
/* The length of a match with `separator'. If `sentinel_length' is 0,
`match_length' is computed every time a match succeeds;
otherwise, it is simply the length of `separator'. */
static int match_length;
/* The input buffer. */
static char *G_buffer;
/* The number of bytes to read at once into `buffer'. */
static size_t read_size;
/* The size of `buffer'. This is read_size * 2 + sentinel_length + 2.
The extra 2 bytes allow `past_end' to have a value beyond the
end of `G_buffer' and `match_start' to run off the front of `G_buffer'. */
static unsigned G_buffer_size;
/* The compiled regular expression representing `separator'. */
static struct re_pattern_buffer compiled_separator;
static struct option const longopts[] =
{
{"before", no_argument, NULL, 'b'},
{"regex", no_argument, NULL, 'r'},
{"separator", required_argument, NULL, 's'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
"),
program_name);
fputs (_("\
Write each FILE to standard output, last line first.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-b, --before attach the separator before instead of after\n\
-r, --regex interpret the separator as a regular expression\n\
-s, --separator=STRING use STRING as the separator instead of newline\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* Print the characters from START to PAST_END - 1.
If START is NULL, just flush the buffer. */
static void
output (const char *start, const char *past_end)
{
static char buffer[WRITESIZE];
static size_t bytes_in_buffer = 0;
size_t bytes_to_add = past_end - start;
size_t bytes_available = WRITESIZE - bytes_in_buffer;
if (start == 0)
{
fwrite (buffer, 1, bytes_in_buffer, stdout);
bytes_in_buffer = 0;
return;
}
/* Write out as many full buffers as possible. */
while (bytes_to_add >= bytes_available)
{
memcpy (buffer + bytes_in_buffer, start, bytes_available);
bytes_to_add -= bytes_available;
start += bytes_available;
fwrite (buffer, 1, WRITESIZE, stdout);
bytes_in_buffer = 0;
bytes_available = WRITESIZE;
}
memcpy (buffer + bytes_in_buffer, start, bytes_to_add);
bytes_in_buffer += bytes_to_add;
}
/* Print in reverse the file open on descriptor FD for reading FILE.
Return 0 if ok, 1 if an error occurs. */
static int
tac_seekable (int input_fd, const char *file)
{
/* Pointer to the location in `G_buffer' where the search for
the next separator will begin. */
char *match_start;
/* Pointer to one past the rightmost character in `G_buffer' that
has not been printed yet. */
char *past_end;
/* Length of the record growing in `G_buffer'. */
size_t saved_record_size;
/* Offset in the file of the next read. */
off_t file_pos;
/* Nonzero if `output' has not been called yet for any file.
Only used when the separator is attached to the preceding record. */
int first_time = 1;
char first_char = *separator; /* Speed optimization, non-regexp. */
char *separator1 = separator + 1; /* Speed optimization, non-regexp. */
int match_length1 = match_length - 1; /* Speed optimization, non-regexp. */
struct re_registers regs;
/* Find the size of the input file. */
file_pos = lseek (input_fd, (off_t) 0, SEEK_END);
if (file_pos < 1)
return 0; /* It's an empty file. */
/* Arrange for the first read to lop off enough to leave the rest of the
file a multiple of `read_size'. Since `read_size' can change, this may
not always hold during the program run, but since it usually will, leave
it here for i/o efficiency (page/sector boundaries and all that).
Note: the efficiency gain has not been verified. */
saved_record_size = file_pos % read_size;
if (saved_record_size == 0)
saved_record_size = read_size;
file_pos -= saved_record_size;
/* `file_pos' now points to the start of the last (probably partial) block
in the input file. */
if (lseek (input_fd, file_pos, SEEK_SET) < 0)
error (0, errno, "%s: seek failed", file);
if (safe_read (input_fd, G_buffer, saved_record_size) != saved_record_size)
{
error (0, errno, "%s", file);
return 1;
}
match_start = past_end = G_buffer + saved_record_size;
/* For non-regexp search, move past impossible positions for a match. */
if (sentinel_length)
match_start -= match_length1;
for (;;)
{
/* Search backward from `match_start' - 1 to `G_buffer' for a match
with `separator'; for speed, use strncmp if `separator' contains no
metacharacters.
If the match succeeds, set `match_start' to point to the start of
the match and `match_length' to the length of the match.
Otherwise, make `match_start' < `G_buffer'. */
if (sentinel_length == 0)
{
int i = match_start - G_buffer;
int ret;
ret = re_search (&compiled_separator, G_buffer, i, i - 1, -i, &regs);
if (ret == -1)
match_start = G_buffer - 1;
else if (ret == -2)
{
error (EXIT_FAILURE, 0,
_("error in regular expression search"));
}
else
{
match_start = G_buffer + regs.start[0];
match_length = regs.end[0] - regs.start[0];
}
}
else
{
/* `match_length' is constant for non-regexp boundaries. */
while (*--match_start != first_char
|| (match_length1 && strncmp (match_start + 1, separator1,
match_length1)))
/* Do nothing. */ ;
}
/* Check whether we backed off the front of `G_buffer' without finding
a match for `separator'. */
if (match_start < G_buffer)
{
if (file_pos == 0)
{
/* Hit the beginning of the file; print the remaining record. */
output (G_buffer, past_end);
return 0;
}
saved_record_size = past_end - G_buffer;
if (saved_record_size > read_size)
{
/* `G_buffer_size' is about twice `read_size', so since
we want to read in another `read_size' bytes before
the data already in `G_buffer', we need to increase
`G_buffer_size'. */
char *newbuffer;
int offset = sentinel_length ? sentinel_length : 1;
read_size *= 2;
G_buffer_size = read_size * 2 + sentinel_length + 2;
newbuffer = xrealloc (G_buffer - offset, G_buffer_size);
newbuffer += offset;
/* Adjust the pointers for the new buffer location. */
match_start += newbuffer - G_buffer;
past_end += newbuffer - G_buffer;
G_buffer = newbuffer;
}
/* Back up to the start of the next bufferfull of the file. */
if (file_pos >= read_size)
file_pos -= read_size;
else
{
read_size = file_pos;
file_pos = 0;
}
lseek (input_fd, file_pos, SEEK_SET);
/* Shift the pending record data right to make room for the new.
The source and destination regions probably overlap. */
memmove (G_buffer + read_size, G_buffer, saved_record_size);
past_end = G_buffer + read_size + saved_record_size;
/* For non-regexp searches, avoid unneccessary scanning. */
if (sentinel_length)
match_start = G_buffer + read_size;
else
match_start = past_end;
if (safe_read (input_fd, G_buffer, read_size) != read_size)
{
error (0, errno, "%s", file);
return 1;
}
}
else
{
/* Found a match of `separator'. */
if (separator_ends_record)
{
char *match_end = match_start + match_length;
/* If this match of `separator' isn't at the end of the
file, print the record. */
if (first_time == 0 || match_end != past_end)
output (match_end, past_end);
past_end = match_end;
first_time = 0;
}
else
{
output (match_start, past_end);
past_end = match_start;
}
/* For non-regex matching, we can back up. */
if (sentinel_length > 0)
match_start -= match_length - 1;
}
}
}
/* Print FILE in reverse.
Return 0 if ok, 1 if an error occurs. */
static int
tac_file (const char *file)
{
int errors;
FILE *in;
in = fopen (file, "r");
if (in == NULL)
{
error (0, errno, "%s", file);
return 1;
}
SET_BINARY (fileno (in));
errors = tac_seekable (fileno (in), file);
if (ferror (in) || fclose (in) == EOF)
{
error (0, errno, "%s", file);
return 1;
}
return errors;
}
#if DONT_UNLINK_WHILE_OPEN
static const char *file_to_remove;
static FILE *fp_to_close;
static void
unlink_tempfile (void)
{
fclose (fp_to_close);
unlink (file_to_remove);
}
static void
record_tempfile (const char *fn, FILE *fp)
{
if (!file_to_remove)
{
file_to_remove = fn;
fp_to_close = fp;
atexit (unlink_tempfile);
}
}
#endif
/* Make a copy of the standard input in `FIXME'. */
static void
save_stdin (FILE **g_tmp, char **g_tempfile)
{
static char *template = NULL;
static char *tempdir;
char *tempfile;
FILE *tmp;
int fd;
if (template == NULL)
{
tempdir = getenv ("TMPDIR");
if (tempdir == NULL)
tempdir = DEFAULT_TMPDIR;
template = xmalloc (strlen (tempdir) + 11);
}
sprintf (template, "%s/tacXXXXXX", tempdir);
tempfile = template;
fd = mkstemp (template);
if (fd == -1)
error (EXIT_FAILURE, errno, "%s", tempfile);
tmp = fdopen (fd, "w+");
if (tmp == NULL)
error (EXIT_FAILURE, errno, "%s", tempfile);
#if DONT_UNLINK_WHILE_OPEN
record_tempfile (tempfile, tmp);
#else
unlink (tempfile);
#endif
while (1)
{
size_t bytes_read = safe_read (STDIN_FILENO, G_buffer, read_size);
if (bytes_read == 0)
break;
if (bytes_read == SAFE_READ_ERROR)
error (EXIT_FAILURE, errno, _("stdin: read error"));
if (fwrite (G_buffer, 1, bytes_read, tmp) != bytes_read)
break;
}
if (ferror (tmp) || fflush (tmp) == EOF)
error (EXIT_FAILURE, errno, "%s", tempfile);
SET_BINARY (fileno (tmp));
*g_tmp = tmp;
*g_tempfile = tempfile;
}
/* Print the standard input in reverse, saving it to temporary
file first if it is a pipe.
Return 0 if ok, 1 if an error occurs. */
static int
tac_stdin (void)
{
int errors;
struct stat stats;
/* No tempfile is needed for "tac < file".
Use fstat instead of checking for errno == ESPIPE because
lseek doesn't work on some special files but doesn't return an
error, either. */
if (fstat (STDIN_FILENO, &stats))
{
error (0, errno, _("standard input"));
return 1;
}
if (S_ISREG (stats.st_mode))
{
errors = tac_seekable (fileno (stdin), _("standard input"));
}
else
{
FILE *tmp_stream;
char *tmp_file;
save_stdin (&tmp_stream, &tmp_file);
errors = tac_seekable (fileno (tmp_stream), tmp_file);
}
return errors;
}
#if 0
/* BUF_END points one byte past the end of the buffer to be searched. */
static void *
memrchr (const char *buf_start, const char *buf_end, int c)
{
const char *p = buf_end;
while (buf_start <= --p)
{
if (*(const unsigned char *) p == c)
return (void *) p;
}
return NULL;
}
/* FIXME: describe */
static int
tac_mem (const char *buf, size_t n_bytes, FILE *out)
{
const char *nl;
const char *bol;
if (n_bytes == 0)
return 0;
nl = memrchr (buf, buf + n_bytes, '\n');
bol = (nl == NULL ? buf : nl + 1);
/* If the last line of the input file has no terminating newline,
treat it as a special case. */
if (bol < buf + n_bytes)
{
/* Print out the line from bol to end of input. */
fwrite (bol, 1, (buf + n_bytes) - bol, out);
/* Add a newline here. Otherwise, the first and second lines
of output would appear to have been joined. */
fputc ('\n', out);
}
while ((nl = memrchr (buf, bol - 1, '\n')) != NULL)
{
/* Output the line (which includes a trailing newline)
from NL+1 to BOL-1. */
fwrite (nl + 1, 1, bol - (nl + 1), out);
bol = nl + 1;
}
/* If there's anything left, output the last line: BUF .. BOL-1.
When the first byte of the input is a newline, there is nothing
left to do here. */
if (buf < bol)
fwrite (buf, 1, bol - buf, out);
/* FIXME: this is work in progress.... */
return ferror (out);
}
/* FIXME: describe */
static int
tac_stdin_to_mem (void)
{
char *buf = NULL;
size_t bufsiz = 8 * BUFSIZ;
size_t delta = 8 * BUFSIZ;
size_t n_bytes = 0;
while (1)
{
size_t bytes_read;
if (buf == NULL)
buf = (char *) malloc (bufsiz);
else
buf = (char *) realloc (buf, bufsiz);
if (buf == NULL)
{
/* Free the buffer and fall back on the code that relies on a
temporary file. */
free (buf);
/* FIXME */
abort ();
}
bytes_read = safe_read (STDIN_FILENO, buf + n_bytes, bufsiz - n_bytes);
if (bytes_read == 0)
break;
if (bytes_read == SAFE_READ_ERROR)
error (EXIT_FAILURE, errno, _("stdin: read error"));
n_bytes += bytes_read;
bufsiz += delta;
}
tac_mem (buf, n_bytes, stdout);
return 0;
}
#endif
int
main (int argc, char **argv)
{
const char *error_message; /* Return value from re_compile_pattern. */
int optc, errors;
int have_read_stdin = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
errors = 0;
separator = "\n";
sentinel_length = 1;
separator_ends_record = 1;
while ((optc = getopt_long (argc, argv, "brs:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'b':
separator_ends_record = 0;
break;
case 'r':
sentinel_length = 0;
break;
case 's':
separator = optarg;
if (*separator == 0)
error (EXIT_FAILURE, 0, _("separator cannot be empty"));
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (sentinel_length == 0)
{
compiled_separator.allocated = 100;
compiled_separator.buffer = (unsigned char *)
xmalloc (compiled_separator.allocated);
compiled_separator.fastmap = xmalloc (256);
compiled_separator.translate = 0;
error_message = re_compile_pattern (separator, strlen (separator),
&compiled_separator);
if (error_message)
error (EXIT_FAILURE, 0, "%s", error_message);
}
else
match_length = sentinel_length = strlen (separator);
read_size = INITIAL_READSIZE;
/* A precaution that will probably never be needed. */
while (sentinel_length * 2 >= read_size)
read_size *= 2;
G_buffer_size = read_size * 2 + sentinel_length + 2;
G_buffer = xmalloc (G_buffer_size);
if (sentinel_length)
{
strcpy (G_buffer, separator);
G_buffer += sentinel_length;
}
else
{
++G_buffer;
}
if (optind == argc)
{
have_read_stdin = 1;
/* We need binary I/O, since `tac' relies
on `lseek' and byte counts. */
SET_BINARY2 (STDIN_FILENO, STDOUT_FILENO);
errors = tac_stdin ();
}
else
{
for (; optind < argc; ++optind)
{
if (STREQ (argv[optind], "-"))
{
have_read_stdin = 1;
SET_BINARY2 (STDIN_FILENO, STDOUT_FILENO);
errors |= tac_stdin ();
}
else
{
/* Binary output will leave the lines' ends (NL or
CR/LF) intact when the output is a disk file.
Writing a file with CR/LF pairs at end of lines in
text mode has no visible effect on console output,
since two CRs in a row are just like one CR. */
SET_BINARY (STDOUT_FILENO);
errors |= tac_file (argv[optind]);
}
}
}
/* Flush the output buffer. */
output ((char *) NULL, (char *) NULL);
if (have_read_stdin && close (STDIN_FILENO) < 0)
error (EXIT_FAILURE, errno, "-");
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
File diff suppressed because it is too large Load Diff
+236
View File
@@ -0,0 +1,236 @@
/* tee - read from standard input and write to standard output and files.
Copyright (C) 85,1990-2002 Free Software Foundation, Inc.
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, 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. */
/* Mike Parker, Richard M. Stallman, and David MacKenzie */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <getopt.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "tee"
#define AUTHORS N_ ("Mike Parker, Richard M. Stallman, and David MacKenzie")
static int tee (int nfiles, const char **files);
/* If nonzero, append to output files rather than truncating them. */
static int append;
/* If nonzero, ignore interrupts. */
static int ignore_interrupts;
/* The name that this program was run with. */
char *program_name;
static struct option const long_options[] =
{
{"append", no_argument, NULL, 'a'},
{"ignore-interrupts", no_argument, NULL, 'i'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
fputs (_("\
Copy standard input to each FILE, and also to standard output.\n\
\n\
-a, --append append to the given FILEs, do not overwrite\n\
-i, --ignore-interrupts ignore interrupt signals\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int errs;
int optc;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
append = 0;
ignore_interrupts = 0;
while ((optc = getopt_long (argc, argv, "ai", long_options, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'a':
append = 1;
break;
case 'i':
ignore_interrupts = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (ignore_interrupts)
{
#ifdef _POSIX_SOURCE
struct sigaction sigact;
sigact.sa_handler = SIG_IGN;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction (SIGINT, &sigact, NULL);
#else /* !_POSIX_SOURCE */
signal (SIGINT, SIG_IGN);
#endif /* _POSIX_SOURCE */
}
/* Don't let us be killed if one of the output files is a pipe that
doesn't consume all its input. */
#ifdef _POSIX_SOURCE
{
struct sigaction sigact;
sigact.sa_handler = SIG_IGN;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction (SIGPIPE, &sigact, NULL);
}
#else
signal (SIGPIPE, SIG_IGN);
#endif
/* Do *not* warn if tee is given no file arguments.
POSIX requires that it work when given no arguments. */
errs = tee (argc - optind, (const char **) &argv[optind]);
if (close (STDIN_FILENO) != 0)
error (EXIT_FAILURE, errno, _("standard input"));
exit (errs);
}
/* Copy the standard input into each of the NFILES files in FILES
and into the standard output.
Return 0 if successful, 1 if any errors occur. */
static int
tee (int nfiles, const char **files)
{
FILE **descriptors;
char buffer[BUFSIZ];
int bytes_read, i;
int ret = 0;
const char *mode_string = (append ? "a" : "w");
descriptors = (FILE **) xmalloc ((nfiles + 1) * sizeof (descriptors[0]));
/* Move all the names `up' one in the argv array to make room for
the entry for standard output. This writes into argv[argc]. */
for (i = nfiles; i >= 1; i--)
files[i] = files[i - 1];
SET_BINARY2 (0, 1);
/* In the array of NFILES + 1 descriptors, make
the first one correspond to standard output. */
descriptors[0] = stdout;
files[0] = _("standard output");
SETVBUF (stdout, NULL, _IONBF, 0);
for (i = 1; i <= nfiles; i++)
{
descriptors[i] = fopen (files[i], mode_string);
if (descriptors[i] == NULL)
{
error (0, errno, "%s", files[i]);
ret = 1;
}
else
{
SETVBUF (descriptors[i], NULL, _IONBF, 0);
SET_BINARY (fileno (descriptors[i]));
}
}
while (1)
{
bytes_read = read (0, buffer, sizeof buffer);
#ifdef EINTR
if (bytes_read < 0 && errno == EINTR)
continue;
#endif
if (bytes_read <= 0)
break;
/* Write to all NFILES + 1 descriptors.
Standard output is the first one. */
for (i = 0; i <= nfiles; i++)
{
if (descriptors[i] != NULL)
fwrite (buffer, bytes_read, 1, descriptors[i]);
}
}
if (bytes_read == -1)
{
error (0, errno, _("read error"));
ret = 1;
}
/* Close the files, but not standard output. */
for (i = 1; i <= nfiles; i++)
if (descriptors[i] != NULL
&& (ferror (descriptors[i]) || fclose (descriptors[i]) == EOF))
{
error (0, errno, "%s", files[i]);
ret = 1;
}
free (descriptors);
return ret;
}
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More