mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9aee8e78ea | ||
|
|
ab511a2106 | ||
|
|
5e711ff948 | ||
|
|
6f5700ac8a | ||
|
|
8daf081cd2 | ||
|
|
3f619c59cf | ||
|
|
0db199df69 | ||
|
|
beb12e09f3 | ||
|
|
65ba507e17 | ||
|
|
795c052e33 | ||
|
|
09ef5a443f | ||
|
|
3765e5a26e | ||
|
|
b64a11dc76 | ||
|
|
82d98da743 | ||
|
|
ecf70125f9 | ||
|
|
1b569150c5 | ||
|
|
4269a52c1a | ||
|
|
b23de86834 | ||
|
|
7782da7bf5 | ||
|
|
2b5e4cb837 | ||
|
|
5f997760c9 | ||
|
|
10ca93af8f | ||
|
|
0278a4d7d3 | ||
|
|
2aab34d486 | ||
|
|
2912097e82 | ||
|
|
3238605998 | ||
|
|
1e9098dc83 | ||
|
|
27940f5d02 | ||
|
|
561c3a2b75 | ||
|
|
c1fb4bcb2a | ||
|
|
93ff956de7 | ||
|
|
553d347d3e | ||
|
|
b1d89070f6 | ||
|
|
20bc0790a7 | ||
|
|
7828d1b4e2 | ||
|
|
5b3313c120 | ||
|
|
0edae5eee6 | ||
|
|
11f43d2e22 | ||
|
|
87c54fa0ae | ||
|
|
3715c01f8e | ||
|
|
d2c7d7b58f | ||
|
|
d1e5a7af56 | ||
|
|
369aaf7e5d | ||
|
|
39e85b7258 | ||
|
|
487e5317be | ||
|
|
112b9537dd | ||
|
|
24045feb85 | ||
|
|
64f972e94b | ||
|
|
0c1e917d6c | ||
|
|
1e7a0f088b | ||
|
|
fd6fc97156 | ||
|
|
04131454e3 | ||
|
|
bc86cb44e3 | ||
|
|
0a538a2488 | ||
|
|
ca4f28bc83 | ||
|
|
36aeb30081 | ||
|
|
fe3fbf2f54 | ||
|
|
d9079b12e3 | ||
|
|
222b7c46bd | ||
|
|
4bf9fe82c0 | ||
|
|
fe068c60fb | ||
|
|
e3864a430e | ||
|
|
2639ed8208 | ||
|
|
09aab8cb41 | ||
|
|
9abd8baaaa | ||
|
|
551bed87fa | ||
|
|
b7a568ece8 | ||
|
|
2871ad3b45 | ||
|
|
f0537a71f1 | ||
|
|
1187f011d3 | ||
|
|
c872a5f7bb | ||
|
|
fe4f1227a5 | ||
|
|
13a4b23e79 | ||
|
|
b655a2154e | ||
|
|
272d99e7a3 | ||
|
|
262963212b | ||
|
|
ea42025c70 | ||
|
|
7daf29845b | ||
|
|
5703f662b7 | ||
|
|
b3b6f52fad | ||
|
|
f6f2846bd8 | ||
|
|
e5dbc71841 | ||
|
|
b2a48ec240 | ||
|
|
c62a7156c5 | ||
|
|
195108489b | ||
|
|
55bc95b4d3 | ||
|
|
d480544281 | ||
|
|
817d0261eb | ||
|
|
898d3df2f8 | ||
|
|
9317cccb8f | ||
|
|
6d8e33952a | ||
|
|
9f2adbf0be | ||
|
|
8fb6d7a9b9 | ||
|
|
cee06314e1 | ||
|
|
ebc2235bd7 | ||
|
|
cece28a8bc | ||
|
|
94986c1d0a | ||
|
|
c12e44d891 |
@@ -8,6 +8,7 @@ Makefile
|
||||
Makefile.in
|
||||
THANKS-to-translators
|
||||
aclocal.m4
|
||||
chcon
|
||||
config.status
|
||||
configure
|
||||
coreutils-*
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ Makefile.in
|
||||
THANKS-to-translators
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
chcon
|
||||
config.cache
|
||||
config.h
|
||||
config.hin
|
||||
|
||||
@@ -5,3 +5,4 @@ config-log
|
||||
po/
|
||||
src/df.c
|
||||
src/stat.c
|
||||
tests/misc/df-P
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
^configure$
|
||||
ChangeLog
|
||||
^TODO$
|
||||
^lib/mktime\.c$
|
||||
^lib/getloadavg\.c$
|
||||
^lib/euidaccess\.c$
|
||||
^lib/euidaccess-stat\.c$
|
||||
^lib/group-member\.c$
|
||||
^Makefile\.maint$
|
||||
^doc/coreutils.texi$
|
||||
^src/stty.c$
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -4,6 +4,7 @@ each followed by the name(s) of its author(s).
|
||||
base64: Simon Josefsson
|
||||
basename: FIXME unknown
|
||||
cat: Torbjorn Granlund, Richard M. Stallman
|
||||
chcon: Russell Coker, Jim Meyering
|
||||
chgrp: David MacKenzie, Jim Meyering
|
||||
chmod: David MacKenzie, Jim Meyering
|
||||
chown: David MacKenzie, Jim Meyering
|
||||
@@ -60,6 +61,7 @@ pwd: Jim Meyering
|
||||
readlink: Dmitry V. Levin
|
||||
rm: Paul Rubin, David MacKenzie, Richard Stallman, Jim Meyering
|
||||
rmdir: David MacKenzie
|
||||
runcon: Russell Coker
|
||||
seq: Ulrich Drepper
|
||||
sha1sum: Ulrich Drepper, Scott Miller, David Madore
|
||||
sha224sum: Ulrich Drepper, Scott Miller, David Madore
|
||||
|
||||
248
ChangeLog
248
ChangeLog
@@ -1,3 +1,234 @@
|
||||
2007-03-18 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Fix a bug in how pr -m -s works.
|
||||
* NEWS: Describe how the fix affects pr.
|
||||
* src/pr.c (init_parameters): The --merge (-m) option does
|
||||
not imply --expand-tabs (-e), so don't set "untabify_input".
|
||||
Reported by Wis Macomson.
|
||||
* tests/misc/pr: New file. Test for the above fix.
|
||||
* tests/misc/Makefile.am (TESTS): Add pr.
|
||||
* THANKS: Update.
|
||||
|
||||
2007-03-17 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Detect use of AC_CONFIG_AUX_DIR also when its argument is quoted.
|
||||
* bootstrap: Put ""s around use of $build_aux, in case
|
||||
someone uses a name containing shell meta-characters.
|
||||
Reported by Alfred M. Szmidt.
|
||||
* tests/misc/tty-eof: Add shuf to the list of tested commands.
|
||||
|
||||
Avoid test failure on NFS-mounted Solaris ZFS file system.
|
||||
* tests/du/basic: Skip a test if "." is on a non-local file system.
|
||||
|
||||
Avoid an obscure build failure, prefer waitpid over wait.
|
||||
* src/install.c (strip): Use waitpid, not wait. It's equivalent,
|
||||
but feels less obsolescent.
|
||||
|
||||
* bootstrap: Don't use \> in grep regexp. For HP-UX.
|
||||
|
||||
2007-03-16 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Begin adding support for Solaris ZFS (4 entries per trivial ACL)
|
||||
* gl/lib/acl.c (ACL_NOT_WELL_SUPPORTED): New macro.
|
||||
(file_has_acl, copy_acl): Use it, rather than enumerating errno values.
|
||||
(is_trivial_acl): New function. Incomplete, for now.
|
||||
(file_has_acl, copy_acl): Use the new function, rather than
|
||||
counting the number of entries in an ACL.
|
||||
|
||||
* bootstrap: Update from gnulib.
|
||||
|
||||
* .x-sc_prohibit_atoi_atof: Add TODO here, too.
|
||||
|
||||
2007-03-16 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* src/copy.c: Include filemode.h.
|
||||
(overwrite_prompt): Say "try to overwrite", not "overwrite", to
|
||||
make it clearer that the attempt may fail. Problem reported by
|
||||
Dan Jacobson in:
|
||||
http://lists.gnu.org/archive/html/bug-coreutils/2007-03/msg00130.html
|
||||
Output symbolic mode as well as numeric.
|
||||
* tests/mv/i-2 (fail): Adjust to new prompt format.
|
||||
|
||||
2007-03-15 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Enforce policy: don't use *scanf functions.
|
||||
* Makefile.maint (sc_prohibit_atoi_atof): Add to regexp and diagnostic.
|
||||
* .x-sc_prohibit_atoi_atof: Give stty a temporary pass.
|
||||
* TODO: note that stty.c needs this small clean-up.
|
||||
|
||||
2007-03-13 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Prepare to work on ACL-related failure when using Solaris ZFS.
|
||||
* gl/lib/acl.c: New file, copied from gnulib.
|
||||
|
||||
Work around a failing test due to an NFS-based race condition.
|
||||
* tests/cp/sparse: Accept a report that the copy is *smaller*.
|
||||
|
||||
2007-03-12 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Make bootstrap.conf a tiny bit more generic.
|
||||
* bootstrap.conf (XGETTEXT_OPTIONS): Exclude gettext-related .m4
|
||||
files when e.g., AM_GNU_GETTEXT([external] appears in configure.ac.
|
||||
|
||||
2007-03-10 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Try to fix today's NFS-related failure: Treat ESTALE like EACCES.
|
||||
* gl/lib/savewd.c: Copy this file from gnulib, then change
|
||||
"errno != EACCES" to (errno != EACCES && errno != ESTALE).
|
||||
The symptom was this failure in tests/install/basic-1:
|
||||
ginstall: cannot create directory `rel/a': Stale NFS file handle
|
||||
|
||||
The preceding change solved part of the problem. Now ginstall fails.
|
||||
* tests/install/basic-1: Temporarily, don't redirect ginstall's
|
||||
stderr to /dev/null, so I can see why the NFS autobuilder's NFS test
|
||||
is failing.
|
||||
|
||||
* tests/install/basic-1: When setting up an unreadable "." in an
|
||||
inaccessible parent, make the parent inaccessible *after* making "."
|
||||
unreadable. Otherwise, running "chmod a-r ." in an already-
|
||||
inaccessible parent would fail on NFS with "Stale NFS file handle".
|
||||
Reported by Bob Proulx.
|
||||
|
||||
* Makefile.maint (po-check): Exclude c99-to-c89.diff.
|
||||
|
||||
2007-03-09 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Avoid test failures on Darwin 7.9.0 (MacOS X 10.3.9)
|
||||
* tests/chgrp/basic: Don't let failure by chgrp to set the
|
||||
group of a symlink make this test fail. Do give a diagnostic.
|
||||
In the chgrp-no-change-ctime test, add darwin7.9.0 as another
|
||||
known-failing system.
|
||||
When failing on some other system, print $host_triplet, too.
|
||||
Also avoid test failures on Darwin 8.8.x (MacOS X 10.4).
|
||||
Reported by Peter Fales.
|
||||
|
||||
2007-03-08 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* src/c99-to-c89.diff: Reflect the new c99'ism, update offsets.
|
||||
|
||||
2007-03-08 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
rm without -f: give a better diagnostic when euidaccess fails.
|
||||
* src/remove.c (write_protected_non_symlink): Return int, not bool,
|
||||
so that we can indicate failure too (as a postive error number).
|
||||
(prompt): If write_protected_non_symlink fails, report that error
|
||||
number and fail rather than charging ahead and removing the dubious
|
||||
entry. Redo the logic of printing a diagnostic so that we need to
|
||||
invoke quote (full_filename (...)) only once. More details at:
|
||||
<http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/9952/focus=9996>
|
||||
|
||||
2007-03-08 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Generalize a few more cvs-isms.
|
||||
* bootstrap (checkout_only_file): Rename from CVS_only_file.
|
||||
Change comments and diagnostics not to say "CVS".
|
||||
|
||||
* bootstrap: Run libtool, if necessary.
|
||||
|
||||
Make bootstrap a little more general.
|
||||
* bootstrap (build_aux): Factor out/use this definition.
|
||||
Formally require a "AC_CONFIG_AUX_DIR($build_aux)" line in configure.ac.
|
||||
(insert_sorted_if_absent): Move function definition "up", to
|
||||
precede new first use.
|
||||
If $build_aux/ doesn't exist initially, create it, and
|
||||
mark it as ignored.
|
||||
|
||||
2007-03-03 Andrew Church <achurch@achurch.org> (tiny change)
|
||||
Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Fix a bug: cp -x would fail to set mount point permissions.
|
||||
* NEWS: mention cp -x bug fix
|
||||
* src/copy.c (copy_internal): Don't return immediately after
|
||||
copying a mount point that we do not intend to recurse under.
|
||||
Based on a patch by Andrew Church.
|
||||
|
||||
2007-03-03 Jim Meyering <jim@meyering.net>
|
||||
|
||||
pwd-unreadable-parent: Skip test on ia64/Linux, too.
|
||||
* tests/misc/pwd-unreadable-parent: Also skip when $REPLACE_GETCWD.
|
||||
Reported by Bob Proulx.
|
||||
|
||||
2007-03-02 Jim Meyering <jim@meyering.net>
|
||||
|
||||
pwd-unreadable-parent: Skip test on non-Linux/GNU systems.
|
||||
* tests/misc/pwd-unreadable-parent: Rather than trying to decide
|
||||
whether this test has a chance of succeeding, run it only when
|
||||
$(host_os) is linux-gnu. It was failing on powerpc-apple-darwin8.8.0
|
||||
* tests/misc/Makefile.am (TESTS_ENVIRONMENT): Add host_os=$(host_os).
|
||||
|
||||
* tests/misc/pwd-long: Also allow "+" in $PWD.
|
||||
|
||||
Remove another coreutils-ism. Formatting cleanup.
|
||||
* Makefile.maint (my-distcheck): Update an outdated comment.
|
||||
(emit_upload_commands): Use $(PACKAGE) rather than "coreutils".
|
||||
(my-distcheck): Skip the c99/c89 check if there's no such .diff file.
|
||||
|
||||
2007-03-01 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* Makefile.maint (warn_cflags): Hoist, adding "-Dlint -O".
|
||||
(my-distcheck): Use the new variable, instead of too-long literal.
|
||||
|
||||
Make "make syntax-check" rules less coreutils-specific.
|
||||
* Makefile.maint (sc_cast_of_x_alloc_return_value): Use CVS_LIST_EXCEPT.
|
||||
(sc_cast_of_alloca_return_value): Likewise.
|
||||
(sc_root_tests): Do nothing if there is no check-root target
|
||||
in tests/Makefile.am.
|
||||
|
||||
Run the writable-files check only for release-building targets.
|
||||
* Makefile.maint (local-checks-available): Remove writable-files.
|
||||
(alpha beta major): Put it here, instead.
|
||||
|
||||
"make syntax-check" now runs only Makefile.cfg-selected tests
|
||||
* Makefile.maint (syntax-check-rules): Hoist this definition so that
|
||||
it precedes the indirect use in the definition of $(local-check).
|
||||
(local-check): Use :=, not just "=".
|
||||
(syntax-check): Depend on $(local-check), not $(syntax-check-rules).
|
||||
|
||||
2007-02-28 Bruno Haible <bruno@clisp.org>
|
||||
|
||||
* bootstrap.conf (gnulib_modules): Replace xreadlink with
|
||||
xreadlink-with-size. Add xreadlink.
|
||||
* src/copy.c (copy_internal): Update.
|
||||
* src/ls.c (is_directory): Update.
|
||||
* src/stat.c (print_stat): Update.
|
||||
* src/readlink.c (main): Use the one-argument xreadlink function.
|
||||
|
||||
2007-02-28 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* doc/coreutils.texi (Common options): --si outputs "M", not "MB".
|
||||
Problem reported by Philip Rowlands in
|
||||
<http://lists.gnu.org/archive/html/bug-coreutils/2007-02/msg00283.html>.
|
||||
|
||||
2007-02-28 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* .x-sc_file_system: Add the new test, tests/misc/df-P, to this
|
||||
list of exceptions, for the "make distcheck" sc_file_system rule.
|
||||
|
||||
* Makefile.maint (gnulib_snapshot_date): Remove now-unused definition.
|
||||
|
||||
2007-02-27 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Make df -P immune to effects of e.g., the BLOCK_SIZE envvar.
|
||||
* NEWS: With -P, the default block size and output format is not
|
||||
affected by DF_BLOCK_SIZE, BLOCK_SIZE, or BLOCKSIZE.
|
||||
* src/df.c (main): Implement this.
|
||||
|
||||
2007-02-27 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Add a test for the above.
|
||||
* tests/misc/df-P: New file.
|
||||
* tests/misc/Makefile.am (TESTS): Add df-P.
|
||||
|
||||
2007-02-25 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* Makefile.maint (announcement): Adjust so that it works with
|
||||
announce-gen's --gnulib-snapshot-time-stamp option.
|
||||
Indent one of the command lines using TAB, not 8 spaces.
|
||||
|
||||
Post-release version change.
|
||||
* NEWS: Add a line for 6.8+.
|
||||
* configure.ac (AC_INIT): Set new version string.
|
||||
|
||||
2007-02-24 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Version 6.8.
|
||||
@@ -255,9 +486,17 @@
|
||||
consistent, so this can be applied with patch -p0.
|
||||
Reported by Matthew Woehlke.
|
||||
|
||||
Arrange for "make check-root" to run the new root-only test.
|
||||
* tests/Makefile.am (t9): New target, to run tests/cp/cp-a-selinux.
|
||||
(all_t): Add t9.
|
||||
|
||||
* Makefile.maint (patch-check): Use patch with its -p2 option,
|
||||
since that makes this check slightly more strict.
|
||||
|
||||
Use a directory on a loopback device mounted with -o context=...
|
||||
* tests/cp/cp-a-selinux: Since this test now runs mount and umount,
|
||||
it is a root-only one.
|
||||
|
||||
2007-01-29 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Plug a leak in ls.
|
||||
@@ -420,6 +659,10 @@
|
||||
Use reap_some.
|
||||
(avoid_trashing_input, merge, sort, main): Adapt to mergefps.
|
||||
|
||||
The idea of compressing sorts temporary files was first
|
||||
suggested/implemented by Jay Soffian in 1998, and again
|
||||
by Charles Randall in 2001.
|
||||
|
||||
2007-01-20 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* tests/misc/pwd-long: Work properly even when run from the
|
||||
@@ -487,6 +730,11 @@
|
||||
|
||||
2007-01-13 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* tests/cp/open-perm-race: Remove gdb-based test.
|
||||
It would run only when compiled with -g, and besides is now
|
||||
subsumed by file-perm-race.
|
||||
* tests/cp/Makefile.am (TESTS): Remove open-perm-race.
|
||||
|
||||
* Transform all Makefile.am files so that when running "make check",
|
||||
CU_TEST_NAME is set to the name of the test. This is so that when I
|
||||
run valgrind-enabled (--log-file-qualifier=CU_TEST_NAME) "make check"
|
||||
|
||||
208
ChangeLog-selinux
Normal file
208
ChangeLog-selinux
Normal file
@@ -0,0 +1,208 @@
|
||||
2007-03-18 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* src/runcon.c (main): Don't reorder arguments. Reported by
|
||||
Ulrich Drepper in <http://bugzilla.redhat.com/232652>.
|
||||
* tests/misc/runcon-no-reorder: New file. Test for the above.
|
||||
* tests/misc/Makefile.am (TESTS): Add runcon-no-reorder.
|
||||
|
||||
* src/runcon.c (main): Remove "." at end of a diagnostic.
|
||||
|
||||
2007-02-02 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* src/runcon.c: New program.
|
||||
* src/Makefile.am (bin_PROGRAMS): Add runcon.
|
||||
(runcon_LDADD): Define.
|
||||
* README: Add runcon to the list of programs.
|
||||
* AUTHORS: Add this: runcon: Russell Coker
|
||||
* tests/help-version: Add runcon as an exception.
|
||||
* man/Makefile.am (dist_man_MANS): Add runcon.1.
|
||||
(runcon.1): New dependency.
|
||||
|
||||
2007-01-31 Jim Meyering <jim@meyering.net>
|
||||
|
||||
mkfifo, mknod: Accept new "-Z, --context=C" option.
|
||||
* src/mkfifo.c, src/mknod.c: Include <selinux/selinux.h>.
|
||||
(main): Honor it.
|
||||
* src/Makefile.am (mkfifo_LDADD, mknod_LDADD): Use $(LIB_SELINUX).
|
||||
|
||||
mkdir: Accept new "-Z, --context=C" option.
|
||||
* src/mkdir.c: Include <selinux/selinux.h>.
|
||||
(main): Honor it.
|
||||
* src/Makefile.am (mkdir_LDADD): Use $(LIB_SELINUX).
|
||||
|
||||
* tests/cp/cp-a-selinux: New file. Test for the bug reported in
|
||||
<http://bugzilla.redhat.com/219900>.
|
||||
* tests/cp/Makefile.am (TESTS): Add cp-a-selinux.
|
||||
|
||||
* tests/selinux: New file.
|
||||
* tests/Makefile.am (EXTRA_DIST): Add selinux.
|
||||
* tests/misc/selinux: Source the new script, rather than open coding it.
|
||||
|
||||
Change how "cp -a" and "cp --preserve=context" work with SELinux.
|
||||
Now, cp -a attempts to preserve context, but failure to do so does
|
||||
not change cp's exit status. However "cp --preserve=context" is
|
||||
similar, but failure *does* cause cp to exit with nonzero status.
|
||||
* src/copy.h (struct cp_options) [require_preserve_context]: New member.
|
||||
* src/copy.c (copy_reg, copy_internal): Implement the above.
|
||||
* src/mv.c (cp_option_init): Initialize the new member.
|
||||
* src/install.c (cp_option_init): Likewise.
|
||||
* src/cp.c (cp_option_init): Likewise.
|
||||
(decode_preserve_arg): Set it or reset it.
|
||||
|
||||
FIXME: add an on-writable-NFS-only test
|
||||
|
||||
2007-01-20 Jim Meyering <jim@meyering.net>
|
||||
|
||||
cp, mv, install: add SELinux support, but unlike with the Red Hat
|
||||
patch, mv and cp do not provide the "-Z context" option.
|
||||
* src/copy.c: Include <selinux/selinux.h>.
|
||||
(restore_default_fscreatecon): New function.
|
||||
(copy_reg): Make cp --preserve=context work for existing destination.
|
||||
(copy_internal): Likewise for new destinations.
|
||||
* src/copy.h (cp_options) [preserve_security_context]: New member.
|
||||
* src/cp.c: Include <selinux/selinux.h>.
|
||||
(selinux_enabled): New global.
|
||||
(usage): Mention new --preserve=context option.
|
||||
(PRESERVE_CONTEXT): Define/use.
|
||||
(decode_preserve_arg): Handle PRESERVE_CONTEXT.
|
||||
(main): Remove an obsolete comment.
|
||||
If --preserve=context is specified on a system without SELinux
|
||||
enabled, give a diagnostic and fail.
|
||||
* src/mv.c: Include <selinux/selinux.h>.
|
||||
Set x->preserve_security_context if SELinux is enabled.
|
||||
* src/install.c: Accept new "-Z, --context=C" option.
|
||||
Accept --preserve-context option (but not -P option).
|
||||
Accept alternate spelling: --preserve_context, for now.
|
||||
Include <selinux/selinux.h> and "quotearg.h".
|
||||
(selinux_enabled, use_default_selinux_context): New globals.
|
||||
(PRESERVE_CONTEXT_OPTION): Define.
|
||||
(cp_option_init): Default: do not preserve security context.
|
||||
(setdefaultfilecon): New function.
|
||||
(main): Honor new options.
|
||||
* src/Makefile.am (mv_LDADD, cp_LDADD, ginstall_LDADD):
|
||||
Add $(LIB_SELINUX).
|
||||
* src/system.h (GETOPT_SELINUX_CONTEXT_OPTION_DECL): Define.
|
||||
|
||||
* tests/misc/selinux [VERBOSE]: Print version info for each
|
||||
of the tested tools, not just ls.
|
||||
|
||||
* src/c99-to-c89.diff: Remove the ls.c patch, now that I've
|
||||
temporarily removed the offending c99'ism.
|
||||
|
||||
* src/chcon.c (usage): Split a string literal that was longer than 509.
|
||||
|
||||
* src/ls.c (gobble_file): Don't call getfilecon unless print_scontext.
|
||||
Upon failed getfilecon, accept not just ENOTSUP, but also ENODATA.
|
||||
|
||||
* src/c99-to-c89.diff: Adjust offsets.
|
||||
|
||||
* AUTHORS: Add chcon.
|
||||
|
||||
* src/c99-to-c89.diff: Remove trailing blanks.
|
||||
|
||||
* src/chcon.c: Don't include "dirname.h". system.h already includes it.
|
||||
|
||||
* gl/lib/selinux-at.c: Remove a use of HAVE_CONFIG_H.
|
||||
|
||||
* src/c99-to-c89.diff: Handle a new c99'ism in ls.c.
|
||||
|
||||
* src/id.c (main): Tweak id -Z diagnostic.
|
||||
|
||||
id: Add SELinux support: -Z option.
|
||||
* src/id.c (main): Apply patches from Fedora, with these changes:
|
||||
Remove #ifdef WITH_SELINUX.
|
||||
Use error (EXIT_FAILURE, not fprintf+exit(1).
|
||||
* src/Makefile.am (id_LDADD): Define, so as to add $(LIB_SELINUX).
|
||||
|
||||
2007-01-06 Jim Meyering <jim@meyering.net>
|
||||
|
||||
stat: Add support for SELinux in the form of a %C format directive.
|
||||
* src/stat.c (follow_links): Make this variable file-global.
|
||||
(out_file_context): New function.
|
||||
(print_statfs): Honor %C.
|
||||
(print_stat): Honor %C.
|
||||
(do_stat): Remove follow_links parameter.
|
||||
(usage): Document the two %C directives.
|
||||
(main): Accept -Z (though it's a no-op).
|
||||
* src/Makefile.am (stat_LDADD): Define.
|
||||
|
||||
ls: Add support for SELinux and a slightly modified -Z option.
|
||||
I started with the patches from Red Hat.
|
||||
The entries below tell how the code evolved.
|
||||
|
||||
* src/ls.c (print_long_format, print_file_name_and_frills): When
|
||||
there is no security context (due to getfilecon/lgetfilecon failing
|
||||
with e.g. ENOTSUP), print it as "?", not "".
|
||||
* src/ls.c (print_file_name_and_frills): Make -Z work without -l.
|
||||
(length_of_file_name_and_frills): Likewise.
|
||||
|
||||
* src/ls.c: Remove the --lcontext and --scontext options.
|
||||
Change the way -Z, --context work so that it no longer implies -l.
|
||||
Thus, -Z -l will work like -lcontext and -Z without -l will work
|
||||
like --scontext.
|
||||
|
||||
Adjust tests to reflect new 'ls -l' syntax -- affects only
|
||||
systems with SELinux when operating on a file with no ACL.
|
||||
These tests assumed that everything before the first space on
|
||||
each line is the 10-byte mode string. But there may also be a "+"
|
||||
in the 11th column, just before the space. However, note that this
|
||||
is not new. The same thing would have happened even without the
|
||||
change below, when listing a file with an ACL.
|
||||
* tests/chmod/equals, tests/cp/cp-parents, tests/cp/fail-perm:
|
||||
* tests/cp/link-preserve, tests/install/basic-1, tests/misc/mknod:
|
||||
* tests/mkdir/parents, tests/mkdir/special-1, tests/mv/partition-perm:
|
||||
|
||||
Don't make compilation depend on USE_ACL. An SELinux security
|
||||
context counts as an "alternate access control method", so ls
|
||||
must output a "+" for each file with a security context.
|
||||
* src/ls.c [struct fileinfo] (have_acl): Declare unconditionally.
|
||||
(FILE_HAS_ACL): Remove macro definition. Use f->have_acl directly.
|
||||
(gobble_file): Record whether a file has a security context, and
|
||||
update the condition used to determine whether to print the "+".
|
||||
(gobble_file): Call getfilecon/lgetfilecon also when
|
||||
format == long_format, so that we get the "+".
|
||||
|
||||
* src/ls.c (gobble_file): Add a comment explaining why (with a
|
||||
security context option) ls doesn't exit nonzero due to e.g.,
|
||||
getfilecon failing with errno == ENOTSUP.
|
||||
|
||||
* src/ls.c (gobble_file): Ignore failure of getfilecon if it's due
|
||||
to ENOTSUP.
|
||||
|
||||
* src/ls.c (gobble_file): Factor out three small blocks using
|
||||
getfilecon and lgetfilecon.
|
||||
Don't ignore return value from getfilecon and lgetfilecon.
|
||||
|
||||
* src/ls.c (print_long_format): Don't use ?: (empty 2nd arg with C
|
||||
ternary operator).
|
||||
(print_scontext_format): Likewise.
|
||||
(print_scontext): Declare to be "bool", not int. Adjust uses.
|
||||
|
||||
* src/Makefile.am (dir_LDADD, ls_LDADD, vdir_LDADD): Add $(LIB_SELINUX).
|
||||
|
||||
* tests/misc/chcon: New file.
|
||||
* tests/misc/chcon-fail: New file.
|
||||
* tests/Makefile.am (check-root): Run new, root-only misc/chcon test.
|
||||
* tests/misc/Makefile.am (TESTS): Add chcon and chcon-fail.
|
||||
|
||||
* tests/misc/Makefile.am (TESTS): Add selinux.
|
||||
* tests/misc/selinux: New file.
|
||||
* tests/help-version: Skip chcon.
|
||||
* man/chcon.x: New file.
|
||||
* man/Makefile.am: Build chcon.1.
|
||||
|
||||
New program: chcon
|
||||
* gl/modules/selinux-at: New module. Check for libselinux and set
|
||||
LIB_SELINUX here, unconditionally, rather than depending on
|
||||
the configure-time --enable-selinux option.
|
||||
* gl/modules/selinux-h: New module.
|
||||
* bootstrap.conf (gnulib_modules): Add selinux-at.
|
||||
* gl/lib/selinux-at.c, gl/lib/selinux-at.h: New files.
|
||||
* gl/lib/se-selinux_.h: New file.
|
||||
* gl/lib/se-context_.h: New file.
|
||||
* gl/m4/selinux-selinux-h.m4: New file.
|
||||
* gl/m4/selinux-context-h.m4: New file.
|
||||
* src/Makefile.am (bin_PROGRAMS): Add chcon.
|
||||
(chcon_LDADD): Define.
|
||||
* README: Add chcon to the list of programs.
|
||||
* src/chcon.c: Rewrite the original (Red Hat) chcon to use fts.
|
||||
106
Makefile.maint
106
Makefile.maint
@@ -69,23 +69,23 @@ export LC_ALL = C
|
||||
# in system.h. E.g. today I removed from tail.c a useless definition of
|
||||
# ENOSYS. It was useless because system.h ensures it's defined.
|
||||
|
||||
# Collect the names of rules starting with `sc_'.
|
||||
syntax-check-rules := $(shell sed -n 's/^\(sc_[a-zA-Z0-9_-]*\):.*/\1/p' $(ME))
|
||||
.PHONY: $(syntax-check-rules)
|
||||
|
||||
# Checks that don't require cvs.
|
||||
# Run `changelog-check' last, as previous test may reveal problems requiring
|
||||
# new ChangeLog entries.
|
||||
local-checks-available = \
|
||||
po-check copyright-check writable-files m4-check author_mark_check \
|
||||
po-check copyright-check m4-check author_mark_check \
|
||||
changelog-check patch-check strftime-check $(syntax-check-rules) \
|
||||
makefile_path_separator_check \
|
||||
makefile-check check-AUTHORS
|
||||
.PHONY: $(local-checks-available)
|
||||
|
||||
local-check = $(filter-out $(local-checks-to-skip), $(local-checks-available))
|
||||
local-check := $(filter-out $(local-checks-to-skip), $(local-checks-available))
|
||||
|
||||
# Collect the names of rules starting with `sc_'.
|
||||
syntax-check-rules := $(shell sed -n 's/^\(sc_[a-zA-Z0-9_-]*\):.*/\1/p' $(ME))
|
||||
.PHONY: $(syntax-check-rules)
|
||||
|
||||
syntax-check: $(syntax-check-rules)
|
||||
syntax-check: $(local-check)
|
||||
# @grep -nE '# *include <(limits|std(def|arg|bool))\.h>' \
|
||||
# $$(find -type f -name '*.[chly]') && \
|
||||
# { echo '$(ME): found conditional include' 1>&2; \
|
||||
@@ -103,16 +103,12 @@ sc_cast_of_argument_to_free:
|
||||
exit 1; } || :
|
||||
|
||||
sc_cast_of_x_alloc_return_value:
|
||||
@grep -nE --exclude=$(srcdir)/lib/xalloc.h \
|
||||
--exclude=$(srcdir)/lib/regex.c \
|
||||
'\*\) *x(m|c|re)alloc\>' \
|
||||
$(srcdir)/{lib,src}/*.[chy] && \
|
||||
@grep -nE '\*\) *x(m|c|re)alloc\>' $$($(CVS_LIST_EXCEPT)) && \
|
||||
{ echo '$(ME): don'\''t cast x*alloc return value' 1>&2; \
|
||||
exit 1; } || :
|
||||
|
||||
sc_cast_of_alloca_return_value:
|
||||
@grep -nE '\*\) *alloca\>' \
|
||||
$(srcdir)/src/*.[chy] && \
|
||||
@grep -nE '\*\) *alloca\>' $$($(CVS_LIST_EXCEPT)) && \
|
||||
{ echo '$(ME): don'\''t cast alloca return value' 1>&2; \
|
||||
exit 1; } || :
|
||||
|
||||
@@ -121,18 +117,18 @@ sc_space_tab:
|
||||
{ echo '$(ME): found SPACE-TAB sequence; remove the SPACE' \
|
||||
1>&2; exit 1; } || :
|
||||
|
||||
# Don't use the old ato* functions in `real' code.
|
||||
# Don't use *scanf or the old ato* functions in `real' code.
|
||||
# They provide no error checking mechanism.
|
||||
# Instead, use strto* functions.
|
||||
sc_prohibit_atoi_atof:
|
||||
@grep -nE '\<ato([filq]|ll)\>' $$($(CVS_LIST_EXCEPT)) && \
|
||||
{ echo '$(ME): do not use ato''f, ato''i, ato''l, ato''ll, or ato''q' \
|
||||
@grep -nE '\<([fs]?scanf|ato([filq]|ll))\>' $$($(CVS_LIST_EXCEPT)) && \
|
||||
{ echo '$(ME): do not use *scan''f, ato''f, ato''i, ato''l, ato''ll, or ato''q' \
|
||||
1>&2; exit 1; } || :
|
||||
|
||||
# Using EXIT_SUCCESS as the first argument to error is misleading,
|
||||
# since when that parameter is 0, error does not exit. Use `0' instead.
|
||||
sc_error_exit_success:
|
||||
@grep -nF 'error (EXIT_SUCCESS,' \
|
||||
@grep -nF 'error (EXIT_SUCCESS,' \
|
||||
$$(find -type f -name '*.[chly]') && \
|
||||
{ echo '$(ME): found error (EXIT_SUCCESS' 1>&2; \
|
||||
exit 1; } || :
|
||||
@@ -212,7 +208,9 @@ sc_prohibit_jm_in_m4:
|
||||
1>&2; exit 1; } || :
|
||||
|
||||
sc_root_tests:
|
||||
@t1=sc-root.expected; t2=sc-root.actual; \
|
||||
@if test -d tests \
|
||||
&& grep check-root tests/Makefile.am>/dev/null 2>&1; then \
|
||||
t1=sc-root.expected; t2=sc-root.actual; \
|
||||
grep -nl '^PRIV_CHECK_ARG=require-root' \
|
||||
$$($(CVS_LIST) tests) |sed s,tests,., |sort > $$t1; \
|
||||
sed -n 's, cd \([^ ]*\) .*MAKE..check TESTS=\(.*\),./\1/\2,p' \
|
||||
@@ -221,7 +219,8 @@ sc_root_tests:
|
||||
rm -f $$t1 $$t2; \
|
||||
test "$$diff" \
|
||||
&& { echo 'tests/Makefile.am: missing check-root action'>&2; \
|
||||
exit 1; } || :
|
||||
exit 1; } || :; \
|
||||
fi
|
||||
|
||||
headers_with_interesting_macro_defs = \
|
||||
exit.h \
|
||||
@@ -368,22 +367,22 @@ makefile-check:
|
||||
&& { echo 'Makefile.maint: use $$(...), not @...@' 1>&2; exit 1; } || :
|
||||
|
||||
news-date-check: NEWS
|
||||
today=`date +%Y-%m-%d`; \
|
||||
if head NEWS | grep '^\*.* $(VERSION_REGEXP) ('$$today')' \
|
||||
>/dev/null; then \
|
||||
:; \
|
||||
else \
|
||||
echo "version or today's date is not in NEWS" 1>&2; \
|
||||
exit 1; \
|
||||
today=`date +%Y-%m-%d`; \
|
||||
if head NEWS | grep '^\*.* $(VERSION_REGEXP) ('$$today')' \
|
||||
>/dev/null; then \
|
||||
:; \
|
||||
else \
|
||||
echo "version or today's date is not in NEWS" 1>&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
changelog-check:
|
||||
if head ChangeLog | grep 'Version $(VERSION_REGEXP)\.$$' \
|
||||
>/dev/null; then \
|
||||
:; \
|
||||
else \
|
||||
echo "$(VERSION) not in ChangeLog" 1>&2; \
|
||||
exit 1; \
|
||||
if head ChangeLog | grep 'Version $(VERSION_REGEXP)\.$$' \
|
||||
>/dev/null; then \
|
||||
:; \
|
||||
else \
|
||||
echo "$(VERSION) not in ChangeLog" 1>&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
m4-check:
|
||||
@@ -401,6 +400,7 @@ po-check:
|
||||
for file in $$($(CVS_LIST_EXCEPT)) lib/*.[ch]; do \
|
||||
case $$file in \
|
||||
djgpp/* | man/*) continue;; \
|
||||
*/c99-to-c89.diff) continue;; \
|
||||
esac; \
|
||||
case $$file in \
|
||||
*.[ch]) \
|
||||
@@ -470,7 +470,7 @@ copyright-check:
|
||||
# Abort early if this tag has already been used.
|
||||
vc-tag-check:
|
||||
used=no; \
|
||||
if $(VC) --help | grep CVS; then \
|
||||
if $(VC) --help | grep CVS; then \
|
||||
$(CVS) -n log -h README|grep -e $(this-vc-tag): >/dev/null \
|
||||
&& used=yes; \
|
||||
else \
|
||||
@@ -514,11 +514,11 @@ null_AM_MAKEFLAGS = \
|
||||
AUTOHEADER=false \
|
||||
MAKEINFO=false
|
||||
|
||||
# Detect format-string/arg-list mismatches that would normally be obscured
|
||||
# by the use of _(). The --disable-nls effectively defines away that macro,
|
||||
# and building with CFLAGS='-Wformat -Werror' causes any format warning to be
|
||||
# treated as a failure. Also, check for shadowing problems with -Wshadow,
|
||||
# and for pointer arithmetic problems with -Wpointer-arith.
|
||||
warn_cflags = -Dlint -O -Werror -Wall -Wformat -Wshadow -Wpointer-arith
|
||||
|
||||
# Use -Wformat -Werror to detect format-string/arg-list mismatches.
|
||||
# Also, check for shadowing problems with -Wshadow, and for pointer
|
||||
# arithmetic problems with -Wpointer-arith.
|
||||
# These CFLAGS are pretty strict. If you build this target, you probably
|
||||
# have to have a recent version of gcc and glibc headers.
|
||||
TMPDIR ?= /tmp
|
||||
@@ -529,7 +529,7 @@ my-distcheck: $(local-check) $(release_archive_dir)/$(prev-tgz)
|
||||
GZIP=$(GZIP_ENV) $(AMTAR) -C $(t) -zxf $(distdir).tar.gz
|
||||
cd $(t)/$(distdir) \
|
||||
&& ./configure --disable-nls \
|
||||
&& $(MAKE) CFLAGS='-Werror -Wall -Wformat -Wshadow -Wpointer-arith' \
|
||||
&& $(MAKE) CFLAGS='$(warn_cflags)' \
|
||||
AM_MAKEFLAGS='$(null_AM_MAKEFLAGS)' \
|
||||
&& $(MAKE) dvi \
|
||||
&& $(MAKE) check \
|
||||
@@ -537,11 +537,13 @@ my-distcheck: $(local-check) $(release_archive_dir)/$(prev-tgz)
|
||||
(cd $(t) && mv $(distdir) $(distdir).old \
|
||||
&& $(AMTAR) -zxf - ) < $(distdir).tar.gz
|
||||
diff -ur $(t)/$(distdir).old $(t)/$(distdir)
|
||||
cd $(t)/$(distdir) \
|
||||
&& (cd src && patch -V never --fuzz=0 <c99-to-c89.diff) \
|
||||
&& ./configure --disable-largefile \
|
||||
CFLAGS='-Werror -ansi -pedantic -Wno-long-long' \
|
||||
&& $(MAKE)
|
||||
if test -f $(srcdir)/src/c99-to-c89.diff; then \
|
||||
cd $(t)/$(distdir) \
|
||||
&& (cd src && patch -V never --fuzz=0 <c99-to-c89.diff) \
|
||||
&& ./configure --disable-largefile \
|
||||
CFLAGS='-Werror -ansi -pedantic -Wno-long-long' \
|
||||
&& $(MAKE); \
|
||||
fi
|
||||
-rm -rf $(t)
|
||||
@echo "========================"; \
|
||||
echo "$(distdir).tar.gz is ready for distribution"; \
|
||||
@@ -564,12 +566,12 @@ xd-delta = $(PACKAGE)-$(PREV_VERSION)-$(VERSION).xdelta
|
||||
|
||||
rel-files = $(xd-delta) $(DIST_ARCHIVES)
|
||||
|
||||
# Approximate date of last "update" by the date on the ChangeLog file.
|
||||
gnulib_snapshot_date = \
|
||||
$$(date -u --date $$(stat --printf @%Y $(gnulib_dir)/ChangeLog) \
|
||||
'+%Y-%m-%d %T %z')
|
||||
# Approximate the date of last gnulib "update" by the ChangeLog file's
|
||||
# mtime, and provide that date in the announcement.
|
||||
announcement: NEWS ChangeLog $(rel-files)
|
||||
@./build-aux/announce-gen \
|
||||
@cl_date=$$(stat --printf @%Y $(gnulib_dir)/ChangeLog); \
|
||||
utc_date=$$(date -u --date $$cl_date '+%Y-%m-%d %T %z'); \
|
||||
./build-aux/announce-gen \
|
||||
--release-type=$(RELEASE_TYPE) \
|
||||
--package=$(PACKAGE) \
|
||||
--prev=$(PREV_VERSION) \
|
||||
@@ -577,7 +579,7 @@ announcement: NEWS ChangeLog $(rel-files)
|
||||
--gpg-key-id=$(gpg_key_ID) \
|
||||
--news=NEWS \
|
||||
--bootstrap-tools=autoconf,automake,bison,gnulib \
|
||||
--gnulib-snapshot-date=$(gnulib_snapshot_date) \
|
||||
--gnulib-snapshot-time-stamp="$$utc_date" \
|
||||
$(addprefix --url-dir=, $(url_dir_list))
|
||||
|
||||
## ---------------- ##
|
||||
@@ -594,7 +596,7 @@ emit_upload_commands:
|
||||
@echo =====================================
|
||||
@echo =====================================
|
||||
@echo "$(srcdir)/build-aux/gnupload $(GNUPLOADFLAGS) \\"
|
||||
@echo " --to $(gnu_rel_host):coreutils \\"
|
||||
@echo " --to $(gnu_rel_host):$(PACKAGE) \\"
|
||||
@echo " $(rel-files)"
|
||||
@echo '# send the /tmp/announcement e-mail'
|
||||
@echo =====================================
|
||||
@@ -604,7 +606,7 @@ $(xd-delta): $(release_archive_dir)/$(prev-tgz) $(distdir).tar.gz
|
||||
xdelta delta -9 $^ $@ || :
|
||||
|
||||
.PHONY: alpha beta major
|
||||
alpha beta major: news-date-check changelog-check $(local-check)
|
||||
alpha beta major: news-date-check changelog-check $(local-check) writable-files
|
||||
test $@ = major \
|
||||
&& { echo $(VERSION) | grep -E '^[0-9]+(\.[0-9]+)+$$' \
|
||||
|| { echo "invalid version string: $(VERSION)" 1>&2; exit 1;};}\
|
||||
|
||||
16
NEWS
16
NEWS
@@ -1,5 +1,19 @@
|
||||
GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
* Noteworthy changes in release 6.8+ (????-??-??) [not-unstable]
|
||||
|
||||
** Bug fixes
|
||||
|
||||
cp -x (--one-file-system) would fail to set mount point permissions
|
||||
|
||||
The default block size and output format for df -P are now unaffected by
|
||||
the DF_BLOCK_SIZE, BLOCK_SIZE, and BLOCKSIZE environment variables. It
|
||||
is still affected by POSIXLY_CORRECT, though.
|
||||
|
||||
Using pr -m -s (i.e. merging files, with TAB as the output separator)
|
||||
no longer inserts extraneous spaces between output columns.
|
||||
|
||||
|
||||
* Noteworthy changes in release 6.8 (2007-02-24) [not-unstable]
|
||||
|
||||
** Bug fixes
|
||||
@@ -48,8 +62,6 @@ GNU coreutils NEWS -*- outline -*-
|
||||
program to use when writing and reading temporary files.
|
||||
This can help save both time and disk space when sorting large inputs.
|
||||
|
||||
** New features
|
||||
|
||||
sort accepts the new option -C, which acts like -c except no diagnostic
|
||||
is printed. Its --check option now accepts an optional argument, and
|
||||
--check=quiet and --check=silent are now aliases for -C, while
|
||||
|
||||
16
README
16
README
@@ -7,14 +7,14 @@ arbitrary limits.
|
||||
|
||||
The programs that can be built with this package are:
|
||||
|
||||
[ base64 basename cat chgrp chmod chown chroot cksum comm cp csplit cut date
|
||||
dd df dir dircolors dirname du echo env expand expr factor false fmt fold
|
||||
ginstall groups head hostid hostname id join kill link ln logname ls
|
||||
md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr
|
||||
printenv printf ptx pwd readlink rm rmdir seq sha1sum sha224sum sha256sum
|
||||
sha384sum sha512sum shred shuf sleep sort split stat stty su sum sync tac
|
||||
tail tee test touch tr true tsort tty uname unexpand uniq unlink uptime
|
||||
users vdir wc who whoami yes
|
||||
[ base64 basename cat chcon chgrp chmod chown chroot cksum comm cp
|
||||
csplit cut date dd df dir dircolors dirname du echo env expand expr
|
||||
factor false fmt fold ginstall groups head hostid hostname id join
|
||||
kill link ln logname ls md5sum mkdir mkfifo mknod mv nice nl nohup
|
||||
od paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir
|
||||
runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf
|
||||
sleep sort split stat stty su sum sync tac tail tee test touch tr true
|
||||
tsort tty uname unexpand uniq unlink uptime users vdir wc who whoami yes
|
||||
|
||||
See the file NEWS for a list of major changes in the current release.
|
||||
|
||||
|
||||
1
THANKS
1
THANKS
@@ -519,6 +519,7 @@ William Bader william@nscs.fast.net
|
||||
William Dowling will@franklin.com
|
||||
William Lewis wiml@omnigroup.com
|
||||
wiregauze wiregauze@yahoo.com
|
||||
Wis Macomson wis.macomson@intel.com
|
||||
Wojciech Purczynski cliph@isec.pl
|
||||
Wolfram Kleff kleff@cs.uni-bonn.de
|
||||
Won-kyu Park wkpark@chem.skku.ac.kr
|
||||
|
||||
9
TODO
9
TODO
@@ -1,3 +1,12 @@
|
||||
stty.c:
|
||||
use xstrtoul, not sscanf
|
||||
|
||||
printf:
|
||||
Now that gnulib supports *printf("%a"), import one of the
|
||||
*printf-posix modules so that printf(1) will support %a even on
|
||||
platforms where the native *printf(3) is deficient.
|
||||
Suggestion form Eric Blake.
|
||||
|
||||
strip: add an option to specify the program used to strip binaries.
|
||||
suggestion from Karl Berry
|
||||
|
||||
|
||||
146
bootstrap
146
bootstrap
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Bootstrap this package from CVS.
|
||||
# Bootstrap this package from checked-out sources.
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
|
||||
@@ -49,8 +49,8 @@ Options:
|
||||
--force Attempt to bootstrap even if the sources seem
|
||||
not to have been checked out.
|
||||
--skip-po Do not download po files.
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
--cvs-user=USERNAME Set the username to use when checking out
|
||||
sources from the gnulib repository.
|
||||
|
||||
If the file .bootstrap.conf exists in the current working directory, its
|
||||
contents are read as shell variables to configure the bootstrap.
|
||||
@@ -89,18 +89,20 @@ extract_package_name='
|
||||
}
|
||||
'
|
||||
package=`sed -n "$extract_package_name" configure.ac` || exit
|
||||
gnulib_name=lib$package
|
||||
|
||||
build_aux=build-aux
|
||||
# Extra files from gnulib, which override files from other sources.
|
||||
gnulib_extra_files='
|
||||
build-aux/install-sh
|
||||
build-aux/missing
|
||||
build-aux/mdate-sh
|
||||
build-aux/texinfo.tex
|
||||
build-aux/depcomp
|
||||
build-aux/config.guess
|
||||
build-aux/config.sub
|
||||
gnulib_extra_files="
|
||||
$build_aux/install-sh
|
||||
$build_aux/missing
|
||||
$build_aux/mdate-sh
|
||||
$build_aux/texinfo.tex
|
||||
$build_aux/depcomp
|
||||
$build_aux/config.guess
|
||||
$build_aux/config.sub
|
||||
doc/INSTALL
|
||||
'
|
||||
"
|
||||
|
||||
# Other locale categories that need message catalogs.
|
||||
EXTRA_LOCALE_CATEGORIES=
|
||||
@@ -117,7 +119,7 @@ excluded_files=
|
||||
|
||||
# File that should exist in the top directory of a checked out hierarchy,
|
||||
# but not in a distribution tarball.
|
||||
CVS_only_file=README-hacking
|
||||
checkout_only_file=README-hacking
|
||||
|
||||
# Whether to use copies instead of symlinks.
|
||||
copy=false
|
||||
@@ -142,7 +144,7 @@ do
|
||||
--skip-po)
|
||||
SKIP_PO=t;;
|
||||
--force)
|
||||
CVS_only_file=;;
|
||||
checkout_only_file=;;
|
||||
--copy)
|
||||
copy=true;;
|
||||
*)
|
||||
@@ -151,12 +153,42 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
if test -n "$CVS_only_file" && test ! -r "$CVS_only_file"; then
|
||||
if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
|
||||
echo "$0: Bootstrapping from a non-checked-out distribution is risky." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$0: Bootstrapping CVS $package..."
|
||||
# If $STR is not already on a line by itself in $FILE, insert it,
|
||||
# sorting the new contents of the file and replacing $FILE with the result.
|
||||
insert_sorted_if_absent() {
|
||||
file=$1
|
||||
str=$2
|
||||
echo "$str" | sort -u - $file | cmp -s - $file \
|
||||
|| echo "$str" | sort -u - $file -o $file \
|
||||
|| exit 1
|
||||
}
|
||||
|
||||
# Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac.
|
||||
found_aux_dir=no
|
||||
grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \
|
||||
>/dev/null && found_aux_dir=yes
|
||||
grep '^[ ]*AC_CONFIG_AUX_DIR('"$build_aux"')' configure.ac \
|
||||
>/dev/null && found_aux_dir=yes
|
||||
if test $found_aux_dir = no; then
|
||||
echo "$0: expected line not found in configure.ac. Add the following:" >&2
|
||||
echo " AC_CONFIG_AUX_DIR([$build_aux])" >&2.
|
||||
fi
|
||||
|
||||
# If $build_aux doesn't exist, create it now, otherwise some bits
|
||||
# below will malfunction. If creating it, also mark it as ignored.
|
||||
if test ! -d $build_aux; then
|
||||
mkdir $build_aux
|
||||
for ig in .cvsignore .gitignore; do
|
||||
test -f $ig && insert_sorted_if_absent $ig $build_aux
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$0: Bootstrapping from checked-out $package sources..."
|
||||
|
||||
cleanup_gnulib() {
|
||||
status=$?
|
||||
@@ -358,16 +390,6 @@ version_controlled_file() {
|
||||
test $found = yes
|
||||
}
|
||||
|
||||
# If $STR is not already on a line by itself in $FILE, insert it,
|
||||
# sorting the new contents of the file and replacing $FILE with the result.
|
||||
insert_sorted_if_absent() {
|
||||
file=$1
|
||||
str=$2
|
||||
echo "$str" | sort -u - $file | cmp -s - $file \
|
||||
|| echo "$str" | sort -u - $file -o $file \
|
||||
|| exit
|
||||
}
|
||||
|
||||
slurp() {
|
||||
for dir in . `(cd $1 && find * -type d -print)`; do
|
||||
copied=
|
||||
@@ -431,9 +453,9 @@ mkdir $bt $bt2 || exit
|
||||
gnulib_tool_options="\
|
||||
--import\
|
||||
--no-changelog\
|
||||
--aux-dir $bt/build-aux\
|
||||
--aux-dir $bt/$build_aux\
|
||||
--doc-base $bt/doc\
|
||||
--lib lib$package\
|
||||
--lib $gnulib_name\
|
||||
--m4-base $bt/m4/\
|
||||
--source-base $bt/lib/\
|
||||
--tests-base $bt/tests\
|
||||
@@ -449,23 +471,34 @@ done
|
||||
|
||||
|
||||
# Import from gettext.
|
||||
with_gettext=yes
|
||||
grep '^[ ]*AM_GNU_GETTEXT_VERSION(' configure.ac >/dev/null || \
|
||||
with_gettext=no
|
||||
|
||||
echo "$0: (cd $bt2; autopoint) ..."
|
||||
cp configure.ac $bt2 &&
|
||||
(cd $bt2 && autopoint && rm configure.ac) &&
|
||||
slurp $bt2 $bt || exit
|
||||
if test $with_gettext = yes; then
|
||||
echo "$0: (cd $bt2; autopoint) ..."
|
||||
cp configure.ac $bt2 &&
|
||||
(cd $bt2 && autopoint && rm configure.ac) &&
|
||||
slurp $bt2 $bt || exit
|
||||
|
||||
rm -fr $bt $bt2 || exit
|
||||
rm -fr $bt $bt2 || exit
|
||||
fi
|
||||
|
||||
|
||||
# Reconfigure, getting other files.
|
||||
|
||||
for command in \
|
||||
libtool \
|
||||
'aclocal --force -I m4' \
|
||||
'autoconf --force' \
|
||||
'autoheader --force' \
|
||||
'automake --add-missing --copy --force-missing';
|
||||
do
|
||||
if test "$command" = libtool; then
|
||||
grep '^[ ]*AM_PROG_LIBTOOL\>' configure.ac >/dev/null ||
|
||||
continue
|
||||
command='libtoolize -c -f'
|
||||
fi
|
||||
echo "$0: $command ..."
|
||||
$command || exit
|
||||
done
|
||||
@@ -481,36 +514,37 @@ for file in $gnulib_extra_files; do
|
||||
symlink_to_gnulib $file $dst || exit
|
||||
done
|
||||
|
||||
|
||||
# Create gettext configuration.
|
||||
echo "$0: Creating po/Makevars from po/Makevars.template ..."
|
||||
rm -f po/Makevars
|
||||
sed '
|
||||
/^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
'"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' po/Makevars.template >po/Makevars
|
||||
|
||||
if test -d runtime-po; then
|
||||
# Similarly for runtime-po/Makevars, but not quite the same.
|
||||
rm -f runtime-po/Makevars
|
||||
if test $with_gettext = yes; then
|
||||
# Create gettext configuration.
|
||||
echo "$0: Creating po/Makevars from po/Makevars.template ..."
|
||||
rm -f po/Makevars
|
||||
sed '
|
||||
/^DOMAIN *=.*/s/=.*/= '"$package"'-runtime/
|
||||
/^subdir *=.*/s/=.*/= runtime-po/
|
||||
/^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
'"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
|
||||
'"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' <po/Makevars.template >runtime-po/Makevars
|
||||
' po/Makevars.template >po/Makevars
|
||||
|
||||
# Copy identical files from po to runtime-po.
|
||||
(cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po)
|
||||
if test -d runtime-po; then
|
||||
# Similarly for runtime-po/Makevars, but not quite the same.
|
||||
rm -f runtime-po/Makevars
|
||||
sed '
|
||||
/^DOMAIN *=.*/s/=.*/= '"$package"'-runtime/
|
||||
/^subdir *=.*/s/=.*/= runtime-po/
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
'"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' <po/Makevars.template >runtime-po/Makevars
|
||||
|
||||
# Copy identical files from po to runtime-po.
|
||||
(cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po)
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$0: done. Now you can run './configure'."
|
||||
|
||||
@@ -60,14 +60,16 @@ gnulib_modules="
|
||||
root-dev-ino
|
||||
rpmatch
|
||||
safe-read same
|
||||
save-cwd savedir savewd settime sha1 sig2str ssize_t stat-macros
|
||||
save-cwd savedir savewd
|
||||
selinux-at
|
||||
settime sha1 sig2str ssize_t stat-macros
|
||||
stat-time stdbool stdlib-safer stpcpy strftime
|
||||
strpbrk strtoimax strtoumax strverscmp sys_stat timespec tzset
|
||||
unicodeio unistd-safer unlink-busy unlinkdir unlocked-io
|
||||
uptime userspec utimecmp utimens vasprintf verify version-etc-fsf
|
||||
wcwidth winsz-ioctl winsz-termios xalloc xgetcwd xgethostname
|
||||
xmemcoll xnanosleep xreadlink xstrtod xstrtoimax xstrtol
|
||||
xstrtold xstrtoumax yesno
|
||||
xmemcoll xnanosleep xreadlink xreadlink-with-size xstrtod xstrtoimax
|
||||
xstrtol xstrtold xstrtoumax yesno
|
||||
"
|
||||
|
||||
# Other locale categories that need message catalogs.
|
||||
@@ -81,17 +83,32 @@ XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
|
||||
--flag=wrapf:1:c-format\\\
|
||||
'
|
||||
|
||||
# Gettext supplies these files, but we don't need them since
|
||||
# we don't have an intl subdirectory.
|
||||
excluded_files='
|
||||
m4/glibc2.m4
|
||||
m4/intdiv0.m4
|
||||
m4/lcmessage.m4
|
||||
m4/lock.m4
|
||||
m4/printf-posix.m4
|
||||
m4/size_max.m4
|
||||
m4/uintmax_t.m4
|
||||
m4/ulonglong.m4
|
||||
m4/visibility.m4
|
||||
m4/xsize.m4
|
||||
'
|
||||
# If "AM_GNU_GETTEXT(external" or "AM_GNU_GETTEXT([external]"
|
||||
# appears in configure.ac, exclude some unnecessary files.
|
||||
# Without grep's -E option (not portable enough, pre-configure),
|
||||
# the following test is ugly. Also, this depends on the existence
|
||||
# of configure.ac, not the obsolescent-named configure.in. But if
|
||||
# you're using this infrastructure, you should care about such things.
|
||||
|
||||
gettext_external=0
|
||||
grep '^[ ]*AM_GNU_GETTEXT(external\>' configure.ac > /dev/null &&
|
||||
gettext_external=1
|
||||
grep '^[ ]*AM_GNU_GETTEXT(\[external\]' configure.ac > /dev/null &&
|
||||
gettext_external=1
|
||||
|
||||
if test $gettext_external = 1; then
|
||||
# Gettext supplies these files, but we don't need them since
|
||||
# we don't have an intl subdirectory.
|
||||
excluded_files='
|
||||
m4/glibc2.m4
|
||||
m4/intdiv0.m4
|
||||
m4/lcmessage.m4
|
||||
m4/lock.m4
|
||||
m4/printf-posix.m4
|
||||
m4/size_max.m4
|
||||
m4/uintmax_t.m4
|
||||
m4/ulonglong.m4
|
||||
m4/visibility.m4
|
||||
m4/xsize.m4
|
||||
'
|
||||
fi
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
dnl Written by Jim Meyering.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([GNU coreutils],[6.8],[bug-coreutils@gnu.org])
|
||||
AC_INIT([GNU coreutils],[6.8+],[bug-coreutils@gnu.org])
|
||||
AC_CONFIG_SRCDIR(src/ls.c)
|
||||
|
||||
AC_CONFIG_AUX_DIR(build-aux)
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
2007-03-15 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Fix manual in response to bug reports by Dan Jacobson.
|
||||
* coreutils.texi (sort invocation): Explain numeric sorts better.
|
||||
Compress self-congratulation into a simple "comparison is exact"
|
||||
notice; the --general-numeric-sort option already explains the
|
||||
tradeoffs.
|
||||
(seq invocation): Add example of -f.
|
||||
|
||||
2007-03-12 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* coreutils.texi (cp invocation): Mention that --preserve=timestamps
|
||||
doesn't preserve time stamps on symbolic links.
|
||||
Reported by Polo Talnir in <https://bugzilla.redhat.com/230866>.
|
||||
|
||||
2007-02-27 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* coreutils.texi (df invocation): With -P, the default block size
|
||||
and output format is not affected by DF_BLOCK_SIZE, BLOCK_SIZE, or
|
||||
BLOCKSIZE.
|
||||
|
||||
2007-01-30 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* coreutils.texi
|
||||
|
||||
@@ -558,8 +558,8 @@ symbolic link to a directory. @xref{Target directory}.
|
||||
@itemx --si
|
||||
@opindex --si
|
||||
@cindex SI output
|
||||
Append an SI-style abbreviation to each size, such as @samp{MB} for
|
||||
megabytes. Powers of 1000 are used, not 1024; @samp{MB} stands for
|
||||
Append an SI-style abbreviation to each size, such as @samp{M} for
|
||||
megabytes. Powers of 1000 are used, not 1024; @samp{M} stands for
|
||||
1,000,000 bytes. This option is equivalent to
|
||||
@option{--block-size=si}. Use the @option{-h} or
|
||||
@option{--human-readable} option if
|
||||
@@ -3575,26 +3575,16 @@ can change this.
|
||||
@opindex --numeric-sort
|
||||
@cindex numeric sort
|
||||
@vindex LC_NUMERIC
|
||||
Sort numerically: the number begins each line; specifically, it consists
|
||||
Sort numerically. The number begins each line and consists
|
||||
of optional blanks, an optional @samp{-} sign, and zero or more
|
||||
digits possibly separated by thousands separators, optionally followed
|
||||
by a decimal-point character and zero or more digits. A string of
|
||||
no digits is interpreted as @samp{0}. The @env{LC_NUMERIC}
|
||||
by a decimal-point character and zero or more digits. An empty
|
||||
number is treated as @samp{0}. The @env{LC_NUMERIC}
|
||||
locale specifies the decimal-point character and thousands separator.
|
||||
By default a blank is a space or a tab, but the @env{LC_CTYPE} locale
|
||||
can change this.
|
||||
|
||||
Numeric sort uses what might be considered an unconventional method to
|
||||
compare strings representing floating point numbers. Rather than first
|
||||
converting each string to the C @code{double} type and then comparing
|
||||
those values, @command{sort} aligns the decimal-point characters in the
|
||||
two strings and compares the strings a character at a time. One benefit
|
||||
of using this approach is its speed. In practice this is much more
|
||||
efficient than performing the two corresponding string-to-double (or
|
||||
even string-to-integer) conversions and then comparing doubles. In
|
||||
addition, there is no corresponding loss of precision. Converting each
|
||||
string to @code{double} before comparison would limit precision to about
|
||||
16 digits on most systems.
|
||||
Comparison is exact; there is no rounding error.
|
||||
|
||||
Neither a leading @samp{+} nor exponential notation is recognized.
|
||||
To compare such strings numerically, use the
|
||||
@@ -7030,7 +7020,13 @@ and ordinary users
|
||||
may preserve the group ownership of a file only if they happen to be
|
||||
a member of the desired group.
|
||||
@itemx timestamps
|
||||
Preserve the times of last access and last modification.
|
||||
Preserve the times of last access and last modification, when possible.
|
||||
In general, it is not possible to preserve these attributes
|
||||
when the affected file is a symbolic link.
|
||||
However, FreeBSD now provides the @code{lutimes} function, which makes
|
||||
it possibile even for symbolic links. However, this implementation does
|
||||
not yet take advantage of that.
|
||||
@c FIXME: once we provide lutimes support, update the above.
|
||||
@itemx links
|
||||
Preserve in the destination files
|
||||
any links between corresponding source files.
|
||||
@@ -9481,6 +9477,13 @@ some network mounts), the columns are misaligned.
|
||||
|
||||
@item
|
||||
The labels in the header output line are changed to conform to @acronym{POSIX}.
|
||||
|
||||
@item
|
||||
The default block size and output format are unaffected by the
|
||||
@env{DF_BLOCK_SIZE}, @env{BLOCK_SIZE} and @env{BLOCKSIZE} environment
|
||||
variables. However, the default block size is still affected by
|
||||
@env{POSIXLY_CORRECT}: it is 512 if @env{POSIXLY_CORRECT} is set, 1024
|
||||
otherwise. @xref{Block size}.
|
||||
@end enumerate
|
||||
|
||||
@optSi
|
||||
@@ -13926,6 +13929,12 @@ Print all numbers using @var{format}.
|
||||
@var{format} must contain exactly one of the @samp{printf}-style
|
||||
floating point conversion specifications @samp{%a}, @samp{%e},
|
||||
@samp{%f}, @samp{%g}, @samp{%A}, @samp{%E}, @samp{%F}, @samp{%G}.
|
||||
The @samp{%} may be followed by zero or more flags taken from the set
|
||||
@samp{-+#0 '}, then an optional width containing one or more digits,
|
||||
then an optional precision consisting of a @samp{.} followed by zero
|
||||
or more digits. @var{format} may also contain any number of @samp{%%}
|
||||
conversion specifications. All conversion specifications have the
|
||||
same meaning as with @samp{printf}.
|
||||
|
||||
The default format is derived from @var{first}, @var{step}, and
|
||||
@var{last}. If these all use a fixed point decimal representation,
|
||||
@@ -13948,6 +13957,15 @@ decimal representation.
|
||||
|
||||
@end table
|
||||
|
||||
You can get finer-grained control over output with @option{-f}:
|
||||
|
||||
@example
|
||||
$ seq -f '(%9.2E)' -9e5 1.1e6 1.3e6
|
||||
(-9.00E+05)
|
||||
( 2.00E+05)
|
||||
( 1.30E+06)
|
||||
@end example
|
||||
|
||||
If you want hexadecimal integer output, you can use @command{printf}
|
||||
to perform the conversion:
|
||||
|
||||
|
||||
426
gl/lib/acl.c
Normal file
426
gl/lib/acl.c
Normal file
@@ -0,0 +1,426 @@
|
||||
/* acl.c - access control lists
|
||||
|
||||
Copyright (C) 2002, 2003, 2005, 2006, 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Written by Paul Eggert and Andreas Gruenbacher. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "acl.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef S_ISLNK
|
||||
# define S_ISLNK(Mode) 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
# include <acl/libacl.h>
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
#include "quote.h"
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef ENOSYS
|
||||
# define ENOSYS (-1)
|
||||
#endif
|
||||
#ifndef ENOTSUP
|
||||
# define ENOTSUP (-1)
|
||||
#endif
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(Text) gettext (Text)
|
||||
#else
|
||||
# define _(Text) Text
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FCHMOD
|
||||
# define HAVE_FCHMOD false
|
||||
# define fchmod(fd, mode) (-1)
|
||||
#endif
|
||||
|
||||
/* POSIX 1003.1e (draft 17) */
|
||||
#ifndef HAVE_ACL_GET_FD
|
||||
# define HAVE_ACL_GET_FD false
|
||||
# define acl_get_fd(fd) (NULL)
|
||||
#endif
|
||||
|
||||
/* POSIX 1003.1e (draft 17) */
|
||||
#ifndef HAVE_ACL_SET_FD
|
||||
# define HAVE_ACL_SET_FD false
|
||||
# define acl_set_fd(fd, acl) (-1)
|
||||
#endif
|
||||
|
||||
/* Linux-specific */
|
||||
#ifndef HAVE_ACL_EXTENDED_FILE
|
||||
# define HAVE_ACL_EXTENDED_FILE false
|
||||
# define acl_extended_file(name) (-1)
|
||||
#endif
|
||||
|
||||
/* Linux-specific */
|
||||
#ifndef HAVE_ACL_FROM_MODE
|
||||
# define HAVE_ACL_FROM_MODE false
|
||||
# define acl_from_mode(mode) (NULL)
|
||||
#endif
|
||||
|
||||
#define ACL_NOT_WELL_SUPPORTED(Errno) \
|
||||
(Errno == ENOTSUP || Errno == ENOSYS || Errno == EINVAL)
|
||||
|
||||
/* We detect the presence of POSIX 1003.1e (draft 17 -- abandoned) support
|
||||
by checking for HAVE_ACL_GET_FILE, HAVE_ACL_SET_FILE, and HAVE_ACL_FREE.
|
||||
Systems that have acl_get_file, acl_set_file, and acl_free must also
|
||||
have acl_to_text, acl_from_text, and acl_delete_def_file (all defined
|
||||
in the draft); systems that don't would hit #error statements here. */
|
||||
|
||||
#if USE_ACL && HAVE_ACL_GET_FILE && !HAVE_ACL_ENTRIES
|
||||
# ifndef HAVE_ACL_TO_TEXT
|
||||
# error Must have acl_to_text (see POSIX 1003.1e draft 17).
|
||||
# endif
|
||||
|
||||
/* Return the number of entries in ACL. Linux implements acl_entries
|
||||
as a more efficient extension than using this workaround. */
|
||||
|
||||
static int
|
||||
acl_entries (acl_t acl)
|
||||
{
|
||||
char *text = acl_to_text (acl, NULL), *t;
|
||||
int entries;
|
||||
if (text == NULL)
|
||||
return -1;
|
||||
for (entries = 0, t = text; ; t++, entries++) {
|
||||
t = strchr (t, '\n');
|
||||
if (t == NULL)
|
||||
break;
|
||||
}
|
||||
acl_free (text);
|
||||
return entries;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If DESC is a valid file descriptor use fchmod to change the
|
||||
file's mode to MODE on systems that have fchown. On systems
|
||||
that don't have fchown and if DESC is invalid, use chown on
|
||||
NAME instead. */
|
||||
|
||||
int
|
||||
chmod_or_fchmod (const char *name, int desc, mode_t mode)
|
||||
{
|
||||
if (HAVE_FCHMOD && desc != -1)
|
||||
return fchmod (desc, mode);
|
||||
else
|
||||
return chmod (name, mode);
|
||||
}
|
||||
|
||||
#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
|
||||
/* FIXME: use acl_trivial instead, once we have a replacement function */
|
||||
static bool
|
||||
is_trivial_acl (acl_t acl)
|
||||
{
|
||||
int n = acl_entries (acl);
|
||||
if (n <= 3)
|
||||
return true;
|
||||
if (5 <= n)
|
||||
return false;
|
||||
|
||||
/* Here, we know there are exactly 4 entries.
|
||||
If they are for user, group, mask, and other, then return true; */
|
||||
/* FIXME */
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if NAME has a nontrivial access control list, 0 if
|
||||
NAME only has no or a base access control list, and -1 on
|
||||
error. SB must be set to the stat buffer of FILE. */
|
||||
|
||||
int
|
||||
file_has_acl (char const *name, struct stat const *sb)
|
||||
{
|
||||
#if USE_ACL && HAVE_ACL && defined GETACLCNT
|
||||
/* This implementation should work on recent-enough versions of HP-UX,
|
||||
Solaris, and Unixware. */
|
||||
|
||||
# ifndef MIN_ACL_ENTRIES
|
||||
# define MIN_ACL_ENTRIES 4
|
||||
# endif
|
||||
|
||||
if (! S_ISLNK (sb->st_mode))
|
||||
{
|
||||
int n = acl (name, GETACLCNT, 0, NULL);
|
||||
return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n);
|
||||
}
|
||||
#elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
|
||||
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||||
|
||||
if (! S_ISLNK (sb->st_mode))
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (HAVE_ACL_EXTENDED_FILE)
|
||||
ret = acl_extended_file (name);
|
||||
else
|
||||
{
|
||||
acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
|
||||
if (acl)
|
||||
{
|
||||
ret = !is_trivial_acl (acl);
|
||||
acl_free (acl);
|
||||
if (ret == 0 && S_ISDIR (sb->st_mode))
|
||||
{
|
||||
acl = acl_get_file (name, ACL_TYPE_DEFAULT);
|
||||
if (acl)
|
||||
{
|
||||
ret = (0 < acl_entries (acl));
|
||||
acl_free (acl);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's
|
||||
source/lib/sysacls.c file for fix-related ideas. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy access control lists from one file to another. If SOURCE_DESC is
|
||||
a valid file descriptor, use file descriptor operations, else use
|
||||
filename based operations on SRC_NAME. Likewise for DEST_DESC and
|
||||
DEST_NAME.
|
||||
If access control lists are not available, fchmod the target file to
|
||||
MODE. Also sets the non-permission bits of the destination file
|
||||
(S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
|
||||
System call return value semantics. */
|
||||
|
||||
int
|
||||
copy_acl (const char *src_name, int source_desc, const char *dst_name,
|
||||
int dest_desc, mode_t mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
|
||||
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||||
|
||||
acl_t acl;
|
||||
if (HAVE_ACL_GET_FD && source_desc != -1)
|
||||
acl = acl_get_fd (source_desc);
|
||||
else
|
||||
acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
|
||||
if (acl == NULL)
|
||||
{
|
||||
if (ACL_NOT_WELL_SUPPORTED (errno))
|
||||
return set_acl (dst_name, dest_desc, mode);
|
||||
else
|
||||
{
|
||||
error (0, errno, "%s", quote (src_name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAVE_ACL_SET_FD && dest_desc != -1)
|
||||
ret = acl_set_fd (dest_desc, acl);
|
||||
else
|
||||
ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
|
||||
if (ret != 0)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
if (ACL_NOT_WELL_SUPPORTED (errno))
|
||||
{
|
||||
bool trivial = is_trivial_acl (acl);
|
||||
acl_free (acl);
|
||||
if (trivial)
|
||||
{
|
||||
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
|
||||
saved_errno = errno;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
chmod_or_fchmod (dst_name, dest_desc, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
acl_free (acl);
|
||||
chmod_or_fchmod (dst_name, dest_desc, mode);
|
||||
}
|
||||
error (0, saved_errno, _("preserving permissions for %s"),
|
||||
quote (dst_name));
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
acl_free (acl);
|
||||
|
||||
if (mode & (S_ISUID | S_ISGID | S_ISVTX))
|
||||
{
|
||||
/* We did not call chmod so far, so the special bits have not yet
|
||||
been set. */
|
||||
|
||||
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
|
||||
{
|
||||
error (0, errno, _("preserving permissions for %s"),
|
||||
quote (dst_name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISDIR (mode))
|
||||
{
|
||||
acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
|
||||
if (acl == NULL)
|
||||
{
|
||||
error (0, errno, "%s", quote (src_name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
|
||||
{
|
||||
error (0, errno, _("preserving permissions for %s"),
|
||||
quote (dst_name));
|
||||
acl_free (acl);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
acl_free (acl);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
ret = chmod_or_fchmod (dst_name, dest_desc, mode);
|
||||
if (ret != 0)
|
||||
error (0, errno, _("preserving permissions for %s"), quote (dst_name));
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the access control lists of a file. If DESC is a valid file
|
||||
descriptor, use file descriptor operations where available, else use
|
||||
filename based operations on NAME. If access control lists are not
|
||||
available, fchmod the target file to MODE. Also sets the
|
||||
non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
|
||||
to those from MODE if any are set. System call return value
|
||||
semantics. */
|
||||
|
||||
int
|
||||
set_acl (char const *name, int desc, mode_t mode)
|
||||
{
|
||||
#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
|
||||
/* POSIX 1003.1e draft 17 (abandoned) specific version. */
|
||||
|
||||
/* We must also have have_acl_from_text and acl_delete_def_file.
|
||||
(acl_delete_def_file could be emulated with acl_init followed
|
||||
by acl_set_file, but acl_set_file with an empty acl is
|
||||
unspecified.) */
|
||||
|
||||
# ifndef HAVE_ACL_FROM_TEXT
|
||||
# error Must have acl_from_text (see POSIX 1003.1e draft 17).
|
||||
# endif
|
||||
# ifndef HAVE_ACL_DELETE_DEF_FILE
|
||||
# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
|
||||
# endif
|
||||
|
||||
acl_t acl;
|
||||
int ret;
|
||||
|
||||
if (HAVE_ACL_FROM_MODE)
|
||||
{
|
||||
acl = acl_from_mode (mode);
|
||||
if (!acl)
|
||||
{
|
||||
error (0, errno, "%s", quote (name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char acl_text[] = "u::---,g::---,o::---";
|
||||
|
||||
if (mode & S_IRUSR) acl_text[ 3] = 'r';
|
||||
if (mode & S_IWUSR) acl_text[ 4] = 'w';
|
||||
if (mode & S_IXUSR) acl_text[ 5] = 'x';
|
||||
if (mode & S_IRGRP) acl_text[10] = 'r';
|
||||
if (mode & S_IWGRP) acl_text[11] = 'w';
|
||||
if (mode & S_IXGRP) acl_text[12] = 'x';
|
||||
if (mode & S_IROTH) acl_text[17] = 'r';
|
||||
if (mode & S_IWOTH) acl_text[18] = 'w';
|
||||
if (mode & S_IXOTH) acl_text[19] = 'x';
|
||||
|
||||
acl = acl_from_text (acl_text);
|
||||
if (!acl)
|
||||
{
|
||||
error (0, errno, "%s", quote (name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (HAVE_ACL_SET_FD && desc != -1)
|
||||
ret = acl_set_fd (desc, acl);
|
||||
else
|
||||
ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
|
||||
if (ret != 0)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
acl_free (acl);
|
||||
|
||||
if (ACL_NOT_WELL_SUPPORTED (errno))
|
||||
{
|
||||
if (chmod_or_fchmod (name, desc, mode) != 0)
|
||||
saved_errno = errno;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
error (0, saved_errno, _("setting permissions for %s"), quote (name));
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
acl_free (acl);
|
||||
|
||||
if (S_ISDIR (mode) && acl_delete_def_file (name))
|
||||
{
|
||||
error (0, errno, _("setting permissions for %s"), quote (name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mode & (S_ISUID | S_ISGID | S_ISVTX))
|
||||
{
|
||||
/* We did not call chmod so far, so the special bits have not yet
|
||||
been set. */
|
||||
|
||||
if (chmod_or_fchmod (name, desc, mode))
|
||||
{
|
||||
error (0, errno, _("preserving permissions for %s"), quote (name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
int ret = chmod_or_fchmod (name, desc, mode);
|
||||
if (ret)
|
||||
error (0, errno, _("setting permissions for %s"), quote (name));
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
308
gl/lib/savewd.c
Normal file
308
gl/lib/savewd.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/* Save and restore the working directory, possibly using a child process.
|
||||
|
||||
Copyright (C) 2006, 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "savewd.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dirname.h"
|
||||
#include "fcntl-safer.h"
|
||||
|
||||
|
||||
/* Save the working directory into *WD, if it hasn't been saved
|
||||
already. Return true if a child has been forked to do the real
|
||||
work. */
|
||||
static bool
|
||||
savewd_save (struct savewd *wd)
|
||||
{
|
||||
switch (wd->state)
|
||||
{
|
||||
case INITIAL_STATE:
|
||||
/* Save the working directory, or prepare to fall back if possible. */
|
||||
{
|
||||
int fd = open_safer (".", O_RDONLY);
|
||||
if (0 <= fd)
|
||||
{
|
||||
wd->state = FD_STATE;
|
||||
wd->val.fd = fd;
|
||||
break;
|
||||
}
|
||||
if (errno != EACCES && errno != ESTALE)
|
||||
{
|
||||
wd->state = ERROR_STATE;
|
||||
wd->val.errnum = errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wd->state = FORKING_STATE;
|
||||
wd->val.child = -1;
|
||||
/* Fall through. */
|
||||
case FORKING_STATE:
|
||||
if (wd->val.child < 0)
|
||||
{
|
||||
/* "Save" the initial working directory by forking a new
|
||||
subprocess that will attempt all the work from the chdir
|
||||
until until the next savewd_restore. */
|
||||
wd->val.child = fork ();
|
||||
if (wd->val.child != 0)
|
||||
{
|
||||
if (0 < wd->val.child)
|
||||
return true;
|
||||
wd->state = ERROR_STATE;
|
||||
wd->val.errnum = errno;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FD_STATE:
|
||||
case FD_POST_CHDIR_STATE:
|
||||
case ERROR_STATE:
|
||||
case FINAL_STATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
savewd_chdir (struct savewd *wd, char const *dir, int options,
|
||||
int open_result[2])
|
||||
{
|
||||
int fd = -1;
|
||||
int result = 0;
|
||||
|
||||
/* Open the directory if requested, or if avoiding a race condition
|
||||
is requested and possible. */
|
||||
if (open_result
|
||||
|| (options & (HAVE_WORKING_O_NOFOLLOW ? SAVEWD_CHDIR_NOFOLLOW : 0)))
|
||||
{
|
||||
fd = open (dir,
|
||||
(O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
|
||||
| (options & SAVEWD_CHDIR_NOFOLLOW ? O_NOFOLLOW : 0)));
|
||||
|
||||
if (open_result)
|
||||
{
|
||||
open_result[0] = fd;
|
||||
open_result[1] = errno;
|
||||
}
|
||||
|
||||
if (fd < 0 && ((errno != EACCES && errno != ESTALE)
|
||||
|| (options & SAVEWD_CHDIR_READABLE)))
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if (result == 0 && ! (0 <= fd && options & SAVEWD_CHDIR_SKIP_READABLE))
|
||||
{
|
||||
if (savewd_save (wd))
|
||||
{
|
||||
open_result = NULL;
|
||||
result = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (fd < 0 ? chdir (dir) : fchdir (fd));
|
||||
|
||||
if (result == 0)
|
||||
switch (wd->state)
|
||||
{
|
||||
case FD_STATE:
|
||||
wd->state = FD_POST_CHDIR_STATE;
|
||||
break;
|
||||
|
||||
case ERROR_STATE:
|
||||
case FD_POST_CHDIR_STATE:
|
||||
case FINAL_STATE:
|
||||
break;
|
||||
|
||||
case FORKING_STATE:
|
||||
assert (wd->val.child == 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 <= fd && ! open_result)
|
||||
{
|
||||
int e = errno;
|
||||
close (fd);
|
||||
errno = e;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
savewd_restore (struct savewd *wd, int status)
|
||||
{
|
||||
switch (wd->state)
|
||||
{
|
||||
case INITIAL_STATE:
|
||||
case FD_STATE:
|
||||
/* The working directory is the desired directory, so there's no
|
||||
work to do. */
|
||||
break;
|
||||
|
||||
case FD_POST_CHDIR_STATE:
|
||||
/* Restore the working directory using fchdir. */
|
||||
if (fchdir (wd->val.fd) == 0)
|
||||
{
|
||||
wd->state = FD_STATE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int chdir_errno = errno;
|
||||
close (wd->val.fd);
|
||||
wd->state = ERROR_STATE;
|
||||
wd->val.errnum = chdir_errno;
|
||||
}
|
||||
/* Fall through. */
|
||||
case ERROR_STATE:
|
||||
/* Report an error if asked to restore the working directory. */
|
||||
errno = wd->val.errnum;
|
||||
return -1;
|
||||
|
||||
case FORKING_STATE:
|
||||
/* "Restore" the working directory by waiting for the subprocess
|
||||
to finish. */
|
||||
{
|
||||
pid_t child = wd->val.child;
|
||||
if (child == 0)
|
||||
_exit (status);
|
||||
if (0 < child)
|
||||
{
|
||||
int child_status;
|
||||
while (waitpid (child, &child_status, 0) < 0)
|
||||
assert (errno == EINTR);
|
||||
wd->val.child = -1;
|
||||
if (! WIFEXITED (child_status))
|
||||
raise (WTERMSIG (child_status));
|
||||
return WEXITSTATUS (child_status);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
savewd_finish (struct savewd *wd)
|
||||
{
|
||||
switch (wd->state)
|
||||
{
|
||||
case INITIAL_STATE:
|
||||
case ERROR_STATE:
|
||||
break;
|
||||
|
||||
case FD_STATE:
|
||||
case FD_POST_CHDIR_STATE:
|
||||
close (wd->val.fd);
|
||||
break;
|
||||
|
||||
case FORKING_STATE:
|
||||
assert (wd->val.child < 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
|
||||
wd->state = FINAL_STATE;
|
||||
}
|
||||
|
||||
/* Return true if the actual work is currently being done by a
|
||||
subprocess.
|
||||
|
||||
A true return means that the caller and the subprocess should
|
||||
resynchronize later with savewd_restore, using only their own
|
||||
memory to decide when to resynchronize; they should not consult the
|
||||
file system to decide, because that might lead to race conditions.
|
||||
This is why savewd_chdir is broken out into another function;
|
||||
savewd_chdir's callers _can_ inspect the file system to decide
|
||||
whether to call savewd_chdir. */
|
||||
static inline bool
|
||||
savewd_delegating (struct savewd const *wd)
|
||||
{
|
||||
return wd->state == FORKING_STATE && 0 < wd->val.child;
|
||||
}
|
||||
|
||||
int
|
||||
savewd_process_files (int n_files, char **file,
|
||||
int (*act) (char *, struct savewd *, void *),
|
||||
void *options)
|
||||
{
|
||||
int i = 0;
|
||||
int last_relative;
|
||||
int exit_status = EXIT_SUCCESS;
|
||||
struct savewd wd;
|
||||
savewd_init (&wd);
|
||||
|
||||
for (last_relative = n_files - 1; 0 <= last_relative; last_relative--)
|
||||
if (! IS_ABSOLUTE_FILE_NAME (file[last_relative]))
|
||||
break;
|
||||
|
||||
for (; i < last_relative; i++)
|
||||
{
|
||||
if (! savewd_delegating (&wd))
|
||||
{
|
||||
int s = act (file[i], &wd, options);
|
||||
if (exit_status < s)
|
||||
exit_status = s;
|
||||
}
|
||||
|
||||
if (! IS_ABSOLUTE_FILE_NAME (file[i + 1]))
|
||||
{
|
||||
int r = savewd_restore (&wd, exit_status);
|
||||
if (exit_status < r)
|
||||
exit_status = r;
|
||||
}
|
||||
}
|
||||
|
||||
savewd_finish (&wd);
|
||||
|
||||
for (; i < n_files; i++)
|
||||
{
|
||||
int s = act (file[i], &wd, options);
|
||||
if (exit_status < s)
|
||||
exit_status = s;
|
||||
}
|
||||
|
||||
return exit_status;
|
||||
}
|
||||
31
gl/lib/se-context_.h
Normal file
31
gl/lib/se-context_.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef SELINUX_CONTEXT_H
|
||||
# define SELINUX_CONTEXT_H
|
||||
|
||||
# include <errno.h>
|
||||
/* Some systems don't have ENOSYS. */
|
||||
# ifndef ENOSYS
|
||||
# ifdef ENOTSUP
|
||||
# define ENOSYS ENOTSUP
|
||||
# else
|
||||
/* Some systems don't have ENOTSUP either. */
|
||||
# define ENOSYS EINVAL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
typedef int context_t;
|
||||
static inline context_t context_new (char const *s)
|
||||
{ errno = ENOTSUP; return 0; }
|
||||
static inline char *context_str (context_t con)
|
||||
{ errno = ENOTSUP; return (void *) 0; }
|
||||
static inline void context_free (context_t c) {}
|
||||
|
||||
static inline int context_user_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int context_role_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int context_range_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int context_type_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
#endif
|
||||
54
gl/lib/se-selinux_.h
Normal file
54
gl/lib/se-selinux_.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef SELINUX_SELINUX_H
|
||||
# define SELINUX_SELINUX_H
|
||||
|
||||
# include <sys/types.h>
|
||||
# include <errno.h>
|
||||
/* Some systems don't have ENOSYS. */
|
||||
# ifndef ENOSYS
|
||||
# ifdef ENOTSUP
|
||||
# define ENOSYS ENOTSUP
|
||||
# else
|
||||
/* Some systems don't have ENOTSUP either. */
|
||||
# define ENOSYS EINVAL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
typedef unsigned short security_class_t;
|
||||
# define security_context_t char*
|
||||
# define is_selinux_enabled() 0
|
||||
|
||||
static inline int getcon (security_context_t *con) { errno = ENOTSUP; return -1; }
|
||||
static inline void freecon (security_context_t con) {}
|
||||
|
||||
|
||||
static inline int getfscreatecon (security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int setfscreatecon (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int matchpathcon (char const *s, mode_t m,
|
||||
security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline int getfilecon (char const *s, security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int lgetfilecon (char const *s, security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int setfilecon (char const *s, security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int lsetfilecon (char const *s, security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int fsetfilecon (int fd, security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline int security_check_context (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int security_check_context_raw (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int setexeccon (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int security_compute_create (security_context_t scon,
|
||||
security_context_t tcon,
|
||||
security_class_t tclass,
|
||||
security_context_t *newcon)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
#endif
|
||||
92
gl/lib/selinux-at.c
Normal file
92
gl/lib/selinux-at.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/* openat-style fd-relative functions for SE Linux
|
||||
Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "selinux-at.h"
|
||||
#include "openat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
#include "save-cwd.h"
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#define AT_FUNC_NAME getfileconat
|
||||
#define AT_FUNC_F1 getfilecon
|
||||
#define AT_FUNC_F2 getfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#define AT_FUNC_NAME lgetfileconat
|
||||
#define AT_FUNC_F1 lgetfilecon
|
||||
#define AT_FUNC_F2 lgetfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#define AT_FUNC_NAME setfileconat
|
||||
#define AT_FUNC_F1 setfilecon
|
||||
#define AT_FUNC_F2 setfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#define AT_FUNC_NAME lsetfileconat
|
||||
#define AT_FUNC_F1 lsetfilecon
|
||||
#define AT_FUNC_F2 lsetfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
24
gl/lib/selinux-at.h
Normal file
24
gl/lib/selinux-at.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* Prototypes for openat-style fd-relative SELinux functions
|
||||
Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/context.h>
|
||||
|
||||
int getfileconat (int fd, char const *file, security_context_t *con);
|
||||
int lgetfileconat (int fd, char const *file, security_context_t *con);
|
||||
int setfileconat (int fd, char const *file, security_context_t con);
|
||||
int lsetfileconat (int fd, char const *file, security_context_t con);
|
||||
18
gl/m4/selinux-context-h.m4
Normal file
18
gl/m4/selinux-context-h.m4
Normal file
@@ -0,0 +1,18 @@
|
||||
# serial 1 -*- Autoconf -*-
|
||||
# Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# From Jim Meyering
|
||||
# Provide <selinux/context.h>, if necessary.
|
||||
|
||||
AC_DEFUN([gl_HEADERS_SELINUX_CONTEXT_H],
|
||||
[
|
||||
AC_LIBSOURCES([se-context_.h])
|
||||
# Check for <selinux/context.h>,
|
||||
AC_CHECK_HEADERS([selinux/context.h],
|
||||
[SELINUX_CONTEXT_H=],
|
||||
[SELINUX_CONTEXT_H=selinux/context.h])
|
||||
AC_SUBST([SELINUX_CONTEXT_H])
|
||||
])
|
||||
18
gl/m4/selinux-selinux-h.m4
Normal file
18
gl/m4/selinux-selinux-h.m4
Normal file
@@ -0,0 +1,18 @@
|
||||
# serial 1 -*- Autoconf -*-
|
||||
# Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# From Jim Meyering
|
||||
# Provide <selinux/selinux.h>, if necessary.
|
||||
|
||||
AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H],
|
||||
[
|
||||
AC_LIBSOURCES([se-selinux_.h])
|
||||
# Check for <selinux/selinux.h>,
|
||||
AC_CHECK_HEADERS([selinux/selinux.h],
|
||||
[SELINUX_SELINUX_H=],
|
||||
[SELINUX_SELINUX_H=selinux/selinux.h])
|
||||
AC_SUBST([SELINUX_SELINUX_H])
|
||||
])
|
||||
32
gl/modules/selinux-at
Normal file
32
gl/modules/selinux-at
Normal file
@@ -0,0 +1,32 @@
|
||||
Description:
|
||||
openat-style fd-relative functions for SE Linux
|
||||
|
||||
Files:
|
||||
lib/selinux-at.c
|
||||
lib/selinux-at.h
|
||||
|
||||
Depends-on:
|
||||
selinux-h
|
||||
|
||||
configure.ac:
|
||||
# FIXME: put this in an .m4 file?
|
||||
# For runcon.
|
||||
AC_CHECK_HEADERS([selinux/flask.h])
|
||||
AC_LIBOBJ([selinux-at])
|
||||
ac_save_LIBS="$LIBS"
|
||||
AC_SEARCH_LIBS(setfilecon, selinux,
|
||||
[test "$ac_cv_search_setfilecon" = "none required" ||
|
||||
LIB_SELINUX=$ac_cv_search_setfilecon])
|
||||
AC_SUBST(LIB_SELINUX)
|
||||
LIBS="$ac_save_LIBS"
|
||||
|
||||
Makefile.am:
|
||||
|
||||
Include:
|
||||
selinux-at.h
|
||||
|
||||
License:
|
||||
LGPL
|
||||
|
||||
Maintainer:
|
||||
Jim Meyering
|
||||
54
gl/modules/selinux-h
Normal file
54
gl/modules/selinux-h
Normal file
@@ -0,0 +1,54 @@
|
||||
Description:
|
||||
SELinux-related headers for systems that lack them.
|
||||
|
||||
Files:
|
||||
lib/se-context_.h
|
||||
lib/se-selinux_.h
|
||||
m4/selinux-context-h.m4
|
||||
m4/selinux-selinux-h.m4
|
||||
|
||||
Depends-on:
|
||||
|
||||
configure.ac:
|
||||
gl_HEADERS_SELINUX_SELINUX_H
|
||||
gl_HEADERS_SELINUX_CONTEXT_H
|
||||
|
||||
Makefile.am:
|
||||
BUILT_SOURCES += $(SELINUX_SELINUX_H)
|
||||
selinux/selinux.h: se-selinux_.h
|
||||
mkdir -p selinux
|
||||
cp $(srcdir)/se-selinux_.h $@-t
|
||||
chmod a-x $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += selinux/selinux.h selinux/selinux.h-t
|
||||
|
||||
BUILT_SOURCES += $(SELINUX_CONTEXT_H)
|
||||
selinux/context.h: se-context_.h
|
||||
mkdir -p selinux
|
||||
cp $(srcdir)/se-context_.h $@-t
|
||||
chmod a-x $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += selinux/context.h selinux/context.h-t
|
||||
MOSTLYCLEANDIRS += selinux
|
||||
|
||||
Include:
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/context.h>
|
||||
|
||||
License:
|
||||
LGPL
|
||||
|
||||
Maintainer:
|
||||
Jim Meyering
|
||||
|
||||
# lib/selinux-at.c
|
||||
#
|
||||
# # For runcon.
|
||||
# AC_CHECK_HEADERS([selinux/flask.h])
|
||||
#
|
||||
# ac_save_LIBS="$LIBS"
|
||||
# AC_SEARCH_LIBS(setfilecon, selinux,
|
||||
# [test "$ac_cv_search_setfilecon" = "none required" ||
|
||||
# LIB_SELINUX=$ac_cv_search_setfilecon])
|
||||
# AC_SUBST(LIB_SELINUX)
|
||||
# LIBS="$ac_save_LIBS"
|
||||
@@ -219,6 +219,8 @@ mountlist.h
|
||||
mpsort.c
|
||||
mpsort.h
|
||||
nanosleep.c
|
||||
netinet_in.h
|
||||
netinet_in_.h
|
||||
obstack.c
|
||||
obstack.h
|
||||
offtostr.c
|
||||
@@ -284,7 +286,14 @@ savedir.c
|
||||
savedir.h
|
||||
savewd.c
|
||||
savewd.h
|
||||
se-context.h
|
||||
se-context_.h
|
||||
se-selinux.h
|
||||
se-selinux_.h
|
||||
search.h
|
||||
selinux
|
||||
selinux-at.c
|
||||
selinux-at.h
|
||||
setenv.c
|
||||
setenv.h
|
||||
settime.c
|
||||
@@ -389,6 +398,7 @@ xmemcoll.c
|
||||
xmemcoll.h
|
||||
xnanosleep.c
|
||||
xnanosleep.h
|
||||
xreadlink-with-size.c
|
||||
xreadlink.c
|
||||
xreadlink.h
|
||||
xstrndup.c
|
||||
|
||||
10
lib/.gitignore
vendored
10
lib/.gitignore
vendored
@@ -213,6 +213,8 @@ mountlist.h
|
||||
mpsort.c
|
||||
mpsort.h
|
||||
nanosleep.c
|
||||
netinet_in.h
|
||||
netinet_in_.h
|
||||
obstack.c
|
||||
obstack.h
|
||||
offtostr.c
|
||||
@@ -277,6 +279,13 @@ savedir.c
|
||||
savedir.h
|
||||
savewd.c
|
||||
savewd.h
|
||||
se-context.h
|
||||
se-context_.h
|
||||
se-selinux.h
|
||||
se-selinux_.h
|
||||
selinux
|
||||
selinux-at.c
|
||||
selinux-at.h
|
||||
setenv.c
|
||||
setenv.h
|
||||
settime.c
|
||||
@@ -380,6 +389,7 @@ xmemcoll.c
|
||||
xmemcoll.h
|
||||
xnanosleep.c
|
||||
xnanosleep.h
|
||||
xreadlink-with-size.c
|
||||
xreadlink.c
|
||||
xreadlink.h
|
||||
xstrndup.c
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
2007-03-04 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* vasnprintf.c (VASNPRINTF): Add missing semicolon.
|
||||
|
||||
2007-03-02 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* vasnprintf.c (VASNPRINTF): Remove cast of alloca return value.
|
||||
|
||||
2007-03-01 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Merge in changes from gnulib:
|
||||
* vasnprintf.c: Add a comment explaining why coreutils has its own
|
||||
version of this file.
|
||||
Include <stdint.h>.
|
||||
(SIZE_MAX): Remove definition (now, stdint.h covers that).
|
||||
(EOVERFLOW): Remove definition (now done via the eoverflow module).
|
||||
Update some #ifdef to #if.
|
||||
Use HAVE_LONG_LONG_INT, not HAVE_LONG_LONG.
|
||||
* printf-parse.c: Likewise.
|
||||
|
||||
2007-02-28 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* tsearch.c: Remove unused file.
|
||||
|
||||
2007-02-23 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* randperm.c (randperm_new): Comment: say that this function
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
/* Formatted output to strings.
|
||||
Copyright (C) 1999-2000, 2002-2004, 2006 Free Software Foundation, Inc.
|
||||
This file is intended to provide exactly the same functionality
|
||||
as the version in gnulib, but without the need for the xsize module.
|
||||
|
||||
Copyright (C) 1999-2000, 2002-2003, 2006-2007 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
|
||||
@@ -27,21 +30,12 @@
|
||||
/* Get size_t, NULL. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Get intmax_t. */
|
||||
#if HAVE_STDINT_H_WITH_UINTMAX
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#if HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
/* Get intmax_t, SIZE_MAX. */
|
||||
#include <stdint.h>
|
||||
|
||||
/* malloc(), realloc(), free(). */
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
#if WIDE_CHAR_VERSION
|
||||
# define PRINTF_PARSE wprintf_parse
|
||||
# define CHAR_T wchar_t
|
||||
@@ -329,7 +323,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
flags += 8;
|
||||
cp++;
|
||||
}
|
||||
#ifdef HAVE_INTMAX_T
|
||||
#if HAVE_INTMAX_T
|
||||
else if (*cp == 'j')
|
||||
{
|
||||
if (sizeof (intmax_t) > sizeof (long))
|
||||
@@ -385,11 +379,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
switch (c)
|
||||
{
|
||||
case 'd': case 'i':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if HAVE_LONG_LONG_INT
|
||||
/* If 'long long' exists and is larger than 'long': */
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_LONGLONGINT;
|
||||
else
|
||||
#endif
|
||||
/* If 'long long' exists and is the same as 'long', we parse
|
||||
"lld" into TYPE_LONGINT. */
|
||||
if (flags >= 8)
|
||||
type = TYPE_LONGINT;
|
||||
else if (flags & 2)
|
||||
@@ -400,11 +397,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
type = TYPE_INT;
|
||||
break;
|
||||
case 'o': case 'u': case 'x': case 'X':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if HAVE_LONG_LONG_INT
|
||||
/* If 'long long' exists and is larger than 'long': */
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_ULONGLONGINT;
|
||||
else
|
||||
#endif
|
||||
/* If 'unsigned long long' exists and is the same as
|
||||
'unsigned long', we parse "llu" into TYPE_ULONGINT. */
|
||||
if (flags >= 8)
|
||||
type = TYPE_ULONGINT;
|
||||
else if (flags & 2)
|
||||
@@ -416,7 +416,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
break;
|
||||
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
|
||||
case 'a': case 'A':
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#if HAVE_LONG_DOUBLE
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_LONGDOUBLE;
|
||||
else
|
||||
@@ -425,7 +425,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
break;
|
||||
case 'c':
|
||||
if (flags >= 8)
|
||||
#ifdef HAVE_WINT_T
|
||||
#if HAVE_WINT_T
|
||||
type = TYPE_WIDE_CHAR;
|
||||
#else
|
||||
goto error;
|
||||
@@ -433,7 +433,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
else
|
||||
type = TYPE_CHAR;
|
||||
break;
|
||||
#ifdef HAVE_WINT_T
|
||||
#if HAVE_WINT_T
|
||||
case 'C':
|
||||
type = TYPE_WIDE_CHAR;
|
||||
c = 'c';
|
||||
@@ -441,7 +441,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
#endif
|
||||
case 's':
|
||||
if (flags >= 8)
|
||||
#ifdef HAVE_WCHAR_T
|
||||
#if HAVE_WCHAR_T
|
||||
type = TYPE_WIDE_STRING;
|
||||
#else
|
||||
goto error;
|
||||
@@ -449,7 +449,7 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
else
|
||||
type = TYPE_STRING;
|
||||
break;
|
||||
#ifdef HAVE_WCHAR_T
|
||||
#if HAVE_WCHAR_T
|
||||
case 'S':
|
||||
type = TYPE_WIDE_STRING;
|
||||
c = 's';
|
||||
@@ -459,11 +459,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
type = TYPE_POINTER;
|
||||
break;
|
||||
case 'n':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if HAVE_LONG_LONG_INT
|
||||
/* If 'long long' exists and is larger than 'long': */
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_COUNT_LONGLONGINT_POINTER;
|
||||
else
|
||||
#endif
|
||||
/* If 'long long' exists and is the same as 'long', we parse
|
||||
"lln" into TYPE_COUNT_LONGINT_POINTER. */
|
||||
if (flags >= 8)
|
||||
type = TYPE_COUNT_LONGINT_POINTER;
|
||||
else if (flags & 2)
|
||||
|
||||
698
lib/tsearch.c
698
lib/tsearch.c
@@ -1,698 +0,0 @@
|
||||
/* Copyright (C) 1995, 1996, 1997, 2000, 2005, 2006 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA. */
|
||||
|
||||
/* Tree search for red/black trees.
|
||||
The algorithm for adding nodes is taken from one of the many "Algorithms"
|
||||
books by Robert Sedgewick, although the implementation differs.
|
||||
The algorithm for deleting nodes can probably be found in a book named
|
||||
"Introduction to Algorithms" by Cormen/Leiserson/Rivest. At least that's
|
||||
the book that my professor took most algorithms from during the "Data
|
||||
Structures" course...
|
||||
|
||||
Totally public domain. */
|
||||
|
||||
/* Red/black trees are binary trees in which the edges are colored either red
|
||||
or black. They have the following properties:
|
||||
1. The number of black edges on every path from the root to a leaf is
|
||||
constant.
|
||||
2. No two red edges are adjacent.
|
||||
Therefore there is an upper bound on the length of every path, it's
|
||||
O(log n) where n is the number of nodes in the tree. No path can be longer
|
||||
than 1+2*P where P is the length of the shortest path in the tree.
|
||||
Useful for the implementation:
|
||||
3. If one of the children of a node is NULL, then the other one is red
|
||||
(if it exists).
|
||||
|
||||
In the implementation, not the edges are colored, but the nodes. The color
|
||||
interpreted as the color of the edge leading to this node. The color is
|
||||
meaningless for the root node, but we color the root node black for
|
||||
convenience. All added nodes are red initially.
|
||||
|
||||
Adding to a red/black tree is rather easy. The right place is searched
|
||||
with a usual binary tree search. Additionally, whenever a node N is
|
||||
reached that has two red successors, the successors are colored black and
|
||||
the node itself colored red. This moves red edges up the tree where they
|
||||
pose less of a problem once we get to really insert the new node. Changing
|
||||
N's color to red may violate rule 2, however, so rotations may become
|
||||
necessary to restore the invariants. Adding a new red leaf may violate
|
||||
the same rule, so afterwards an additional check is run and the tree
|
||||
possibly rotated.
|
||||
|
||||
Deleting is hairy. There are mainly two nodes involved: the node to be
|
||||
deleted (n1), and another node that is to be unchained from the tree (n2).
|
||||
If n1 has a successor (the node with a smallest key that is larger than
|
||||
n1), then the successor becomes n2 and its contents are copied into n1,
|
||||
otherwise n1 becomes n2.
|
||||
Unchaining a node may violate rule 1: if n2 is black, one subtree is
|
||||
missing one black edge afterwards. The algorithm must try to move this
|
||||
error upwards towards the root, so that the subtree that does not have
|
||||
enough black edges becomes the whole tree. Once that happens, the error
|
||||
has disappeared. It may not be necessary to go all the way up, since it
|
||||
is possible that rotations and recoloring can fix the error before that.
|
||||
|
||||
Although the deletion algorithm must walk upwards through the tree, we
|
||||
do not store parent pointers in the nodes. Instead, delete allocates a
|
||||
small array of parent pointers and fills it while descending the tree.
|
||||
Since we know that the length of a path is O(log n), where n is the number
|
||||
of nodes, this is likely to use less memory. */
|
||||
|
||||
/* Tree rotations look like this:
|
||||
A C
|
||||
/ \ / \
|
||||
B C A G
|
||||
/ \ / \ --> / \
|
||||
D E F G B F
|
||||
/ \
|
||||
D E
|
||||
|
||||
In this case, A has been rotated left. This preserves the ordering of the
|
||||
binary tree. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
#else
|
||||
# if HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
# pragma alloca
|
||||
# else
|
||||
char *alloca ();
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <search.h>
|
||||
|
||||
#ifndef weak_alias
|
||||
# define __tsearch tsearch
|
||||
# define __tfind tfind
|
||||
# define __tdelete tdelete
|
||||
# define __twalk twalk
|
||||
# define __tdestroy tdestroy
|
||||
#endif
|
||||
|
||||
#ifndef _LIBC
|
||||
# define weak_alias(f,g)
|
||||
# define internal_function
|
||||
#endif
|
||||
|
||||
typedef struct node_t
|
||||
{
|
||||
/* Callers expect this to be the first element in the structure - do not
|
||||
move! */
|
||||
const void *key;
|
||||
struct node_t *left;
|
||||
struct node_t *right;
|
||||
unsigned int red:1;
|
||||
} *node;
|
||||
typedef const struct node_t *const_node;
|
||||
|
||||
#undef DEBUGGING
|
||||
|
||||
#ifdef DEBUGGING
|
||||
|
||||
/* Routines to check tree invariants. */
|
||||
|
||||
# include <assert.h>
|
||||
|
||||
# define CHECK_TREE(a) check_tree(a)
|
||||
|
||||
static void
|
||||
check_tree_recurse (node p, int d_sofar, int d_total)
|
||||
{
|
||||
if (p == NULL)
|
||||
{
|
||||
assert (d_sofar == d_total);
|
||||
return;
|
||||
}
|
||||
|
||||
check_tree_recurse (p->left, d_sofar + (p->left && !p->left->red), d_total);
|
||||
check_tree_recurse (p->right, d_sofar + (p->right && !p->right->red), d_total);
|
||||
if (p->left)
|
||||
assert (!(p->left->red && p->red));
|
||||
if (p->right)
|
||||
assert (!(p->right->red && p->red));
|
||||
}
|
||||
|
||||
static void
|
||||
check_tree (node root)
|
||||
{
|
||||
int cnt = 0;
|
||||
node p;
|
||||
if (root == NULL)
|
||||
return;
|
||||
root->red = 0;
|
||||
for(p = root->left; p; p = p->left)
|
||||
cnt += !p->red;
|
||||
check_tree_recurse (root, 0, cnt);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
# define CHECK_TREE(a)
|
||||
|
||||
#endif
|
||||
|
||||
/* Possibly "split" a node with two red successors, and/or fix up two red
|
||||
edges in a row. ROOTP is a pointer to the lowest node we visited, PARENTP
|
||||
and GPARENTP pointers to its parent/grandparent. P_R and GP_R contain the
|
||||
comparison values that determined which way was taken in the tree to reach
|
||||
ROOTP. MODE is 1 if we need not do the split, but must check for two red
|
||||
edges between GPARENTP and ROOTP. */
|
||||
static void
|
||||
maybe_split_for_insert (node *rootp, node *parentp, node *gparentp,
|
||||
int p_r, int gp_r, int mode)
|
||||
{
|
||||
node root = *rootp;
|
||||
node *rp, *lp;
|
||||
rp = &(*rootp)->right;
|
||||
lp = &(*rootp)->left;
|
||||
|
||||
/* See if we have to split this node (both successors red). */
|
||||
if (mode == 1
|
||||
|| ((*rp) != NULL && (*lp) != NULL && (*rp)->red && (*lp)->red))
|
||||
{
|
||||
/* This node becomes red, its successors black. */
|
||||
root->red = 1;
|
||||
if (*rp)
|
||||
(*rp)->red = 0;
|
||||
if (*lp)
|
||||
(*lp)->red = 0;
|
||||
|
||||
/* If the parent of this node is also red, we have to do
|
||||
rotations. */
|
||||
if (parentp != NULL && (*parentp)->red)
|
||||
{
|
||||
node gp = *gparentp;
|
||||
node p = *parentp;
|
||||
/* There are two main cases:
|
||||
1. The edge types (left or right) of the two red edges differ.
|
||||
2. Both red edges are of the same type.
|
||||
There exist two symmetries of each case, so there is a total of
|
||||
4 cases. */
|
||||
if ((p_r > 0) != (gp_r > 0))
|
||||
{
|
||||
/* Put the child at the top of the tree, with its parent
|
||||
and grandparent as successors. */
|
||||
p->red = 1;
|
||||
gp->red = 1;
|
||||
root->red = 0;
|
||||
if (p_r < 0)
|
||||
{
|
||||
/* Child is left of parent. */
|
||||
p->left = *rp;
|
||||
*rp = p;
|
||||
gp->right = *lp;
|
||||
*lp = gp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Child is right of parent. */
|
||||
p->right = *lp;
|
||||
*lp = p;
|
||||
gp->left = *rp;
|
||||
*rp = gp;
|
||||
}
|
||||
*gparentp = root;
|
||||
}
|
||||
else
|
||||
{
|
||||
*gparentp = *parentp;
|
||||
/* Parent becomes the top of the tree, grandparent and
|
||||
child are its successors. */
|
||||
p->red = 0;
|
||||
gp->red = 1;
|
||||
if (p_r < 0)
|
||||
{
|
||||
/* Left edges. */
|
||||
gp->left = p->right;
|
||||
p->right = gp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right edges. */
|
||||
gp->right = p->left;
|
||||
p->left = gp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find or insert datum into search tree.
|
||||
KEY is the key to be located, ROOTP is the address of tree root,
|
||||
COMPAR the ordering function. */
|
||||
void *
|
||||
__tsearch (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
{
|
||||
node q;
|
||||
node *parentp = NULL, *gparentp = NULL;
|
||||
node *rootp = (node *) vrootp;
|
||||
node *nextp;
|
||||
int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
|
||||
/* This saves some additional tests below. */
|
||||
if (*rootp != NULL)
|
||||
(*rootp)->red = 0;
|
||||
|
||||
CHECK_TREE (*rootp);
|
||||
|
||||
nextp = rootp;
|
||||
while (*nextp != NULL)
|
||||
{
|
||||
node root = *rootp;
|
||||
r = (*compar) (key, root->key);
|
||||
if (r == 0)
|
||||
return root;
|
||||
|
||||
maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
|
||||
/* If that did any rotations, parentp and gparentp are now garbage.
|
||||
That doesn't matter, because the values they contain are never
|
||||
used again in that case. */
|
||||
|
||||
nextp = r < 0 ? &root->left : &root->right;
|
||||
if (*nextp == NULL)
|
||||
break;
|
||||
|
||||
gparentp = parentp;
|
||||
parentp = rootp;
|
||||
rootp = nextp;
|
||||
|
||||
gp_r = p_r;
|
||||
p_r = r;
|
||||
}
|
||||
|
||||
q = (struct node_t *) malloc (sizeof (struct node_t));
|
||||
if (q != NULL)
|
||||
{
|
||||
*nextp = q; /* link new node to old */
|
||||
q->key = key; /* initialize new node */
|
||||
q->red = 1;
|
||||
q->left = q->right = NULL;
|
||||
}
|
||||
if (nextp != rootp)
|
||||
/* There may be two red edges in a row now, which we must avoid by
|
||||
rotating the tree. */
|
||||
maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
|
||||
|
||||
return q;
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tsearch, tsearch)
|
||||
#endif
|
||||
|
||||
|
||||
/* Find datum in search tree.
|
||||
KEY is the key to be located, ROOTP is the address of tree root,
|
||||
COMPAR the ordering function. */
|
||||
void *
|
||||
__tfind (key, vrootp, compar)
|
||||
const void *key;
|
||||
void *const *vrootp;
|
||||
__compar_fn_t compar;
|
||||
{
|
||||
node *rootp = (node *) vrootp;
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
|
||||
CHECK_TREE (*rootp);
|
||||
|
||||
while (*rootp != NULL)
|
||||
{
|
||||
node root = *rootp;
|
||||
int r;
|
||||
|
||||
r = (*compar) (key, root->key);
|
||||
if (r == 0)
|
||||
return root;
|
||||
|
||||
rootp = r < 0 ? &root->left : &root->right;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tfind, tfind)
|
||||
#endif
|
||||
|
||||
|
||||
/* Delete node with given key.
|
||||
KEY is the key to be deleted, ROOTP is the address of the root of tree,
|
||||
COMPAR the comparison function. */
|
||||
void *
|
||||
__tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
{
|
||||
node p, q, r, retval;
|
||||
int cmp;
|
||||
node *rootp = (node *) vrootp;
|
||||
node root, unchained;
|
||||
/* Stack of nodes so we remember the parents without recursion. It's
|
||||
_very_ unlikely that there are paths longer than 40 nodes. The tree
|
||||
would need to have around 250.000 nodes. */
|
||||
int stacksize = 40;
|
||||
int sp = 0;
|
||||
node **nodestack = (node **) alloca (sizeof (node *) * stacksize);
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
p = *rootp;
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
CHECK_TREE (p);
|
||||
|
||||
while ((cmp = (*compar) (key, (*rootp)->key)) != 0)
|
||||
{
|
||||
if (sp == stacksize)
|
||||
{
|
||||
node **newstack;
|
||||
stacksize += 20;
|
||||
newstack = (node **) alloca (sizeof (node *) * stacksize);
|
||||
nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
|
||||
}
|
||||
|
||||
nodestack[sp++] = rootp;
|
||||
p = *rootp;
|
||||
rootp = ((cmp < 0)
|
||||
? &(*rootp)->left
|
||||
: &(*rootp)->right);
|
||||
if (*rootp == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is bogus if the node to be deleted is the root... this routine
|
||||
really should return an integer with 0 for success, -1 for failure
|
||||
and errno = ESRCH or something. */
|
||||
retval = p;
|
||||
|
||||
/* We don't unchain the node we want to delete. Instead, we overwrite
|
||||
it with its successor and unchain the successor. If there is no
|
||||
successor, we really unchain the node to be deleted. */
|
||||
|
||||
root = *rootp;
|
||||
|
||||
r = root->right;
|
||||
q = root->left;
|
||||
|
||||
if (q == NULL || r == NULL)
|
||||
unchained = root;
|
||||
else
|
||||
{
|
||||
node *parent = rootp, *up = &root->right;
|
||||
for (;;)
|
||||
{
|
||||
if (sp == stacksize)
|
||||
{
|
||||
node **newstack;
|
||||
stacksize += 20;
|
||||
newstack = (node **) alloca (sizeof (node *) * stacksize);
|
||||
nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
|
||||
}
|
||||
nodestack[sp++] = parent;
|
||||
parent = up;
|
||||
if ((*up)->left == NULL)
|
||||
break;
|
||||
up = &(*up)->left;
|
||||
}
|
||||
unchained = *up;
|
||||
}
|
||||
|
||||
/* We know that either the left or right successor of UNCHAINED is NULL.
|
||||
R becomes the other one, it is chained into the parent of UNCHAINED. */
|
||||
r = unchained->left;
|
||||
if (r == NULL)
|
||||
r = unchained->right;
|
||||
if (sp == 0)
|
||||
*rootp = r;
|
||||
else
|
||||
{
|
||||
q = *nodestack[sp-1];
|
||||
if (unchained == q->right)
|
||||
q->right = r;
|
||||
else
|
||||
q->left = r;
|
||||
}
|
||||
|
||||
if (unchained != root)
|
||||
root->key = unchained->key;
|
||||
if (!unchained->red)
|
||||
{
|
||||
/* Now we lost a black edge, which means that the number of black
|
||||
edges on every path is no longer constant. We must balance the
|
||||
tree. */
|
||||
/* NODESTACK now contains all parents of R. R is likely to be NULL
|
||||
in the first iteration. */
|
||||
/* NULL nodes are considered black throughout - this is necessary for
|
||||
correctness. */
|
||||
while (sp > 0 && (r == NULL || !r->red))
|
||||
{
|
||||
node *pp = nodestack[sp - 1];
|
||||
p = *pp;
|
||||
/* Two symmetric cases. */
|
||||
if (r == p->left)
|
||||
{
|
||||
/* Q is R's brother, P is R's parent. The subtree with root
|
||||
R has one black edge less than the subtree with root Q. */
|
||||
q = p->right;
|
||||
if (q != NULL && q->red)
|
||||
{
|
||||
/* If Q is red, we know that P is black. We rotate P left
|
||||
so that Q becomes the top node in the tree, with P below
|
||||
it. P is colored red, Q is colored black.
|
||||
This action does not change the black edge count for any
|
||||
leaf in the tree, but we will be able to recognize one
|
||||
of the following situations, which all require that Q
|
||||
is black. */
|
||||
q->red = 0;
|
||||
p->red = 1;
|
||||
/* Left rotate p. */
|
||||
p->right = q->left;
|
||||
q->left = p;
|
||||
*pp = q;
|
||||
/* Make sure pp is right if the case below tries to use
|
||||
it. */
|
||||
nodestack[sp++] = pp = &q->left;
|
||||
q = p->right;
|
||||
}
|
||||
/* We know that Q can't be NULL here. We also know that Q is
|
||||
black. */
|
||||
if ((q->left == NULL || !q->left->red)
|
||||
&& (q->right == NULL || !q->right->red))
|
||||
{
|
||||
/* Q has two black successors. We can simply color Q red.
|
||||
The whole subtree with root P is now missing one black
|
||||
edge. Note that this action can temporarily make the
|
||||
tree invalid (if P is red). But we will exit the loop
|
||||
in that case and set P black, which both makes the tree
|
||||
valid and also makes the black edge count come out
|
||||
right. If P is black, we are at least one step closer
|
||||
to the root and we'll try again the next iteration. */
|
||||
q->red = 1;
|
||||
r = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Q is black, one of Q's successors is red. We can
|
||||
repair the tree with one operation and will exit the
|
||||
loop afterwards. */
|
||||
if (q->right == NULL || !q->right->red)
|
||||
{
|
||||
/* The left one is red. We perform the same action as
|
||||
in maybe_split_for_insert where two red edges are
|
||||
adjacent but point in different directions:
|
||||
Q's left successor (let's call it Q2) becomes the
|
||||
top of the subtree we are looking at, its parent (Q)
|
||||
and grandparent (P) become its successors. The former
|
||||
successors of Q2 are placed below P and Q.
|
||||
P becomes black, and Q2 gets the color that P had.
|
||||
This changes the black edge count only for node R and
|
||||
its successors. */
|
||||
node q2 = q->left;
|
||||
q2->red = p->red;
|
||||
p->right = q2->left;
|
||||
q->left = q2->right;
|
||||
q2->right = q;
|
||||
q2->left = p;
|
||||
*pp = q2;
|
||||
p->red = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's the right one. Rotate P left. P becomes black,
|
||||
and Q gets the color that P had. Q's right successor
|
||||
also becomes black. This changes the black edge
|
||||
count only for node R and its successors. */
|
||||
q->red = p->red;
|
||||
p->red = 0;
|
||||
|
||||
q->right->red = 0;
|
||||
|
||||
/* left rotate p */
|
||||
p->right = q->left;
|
||||
q->left = p;
|
||||
*pp = q;
|
||||
}
|
||||
|
||||
/* We're done. */
|
||||
sp = 1;
|
||||
r = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Comments: see above. */
|
||||
q = p->left;
|
||||
if (q != NULL && q->red)
|
||||
{
|
||||
q->red = 0;
|
||||
p->red = 1;
|
||||
p->left = q->right;
|
||||
q->right = p;
|
||||
*pp = q;
|
||||
nodestack[sp++] = pp = &q->right;
|
||||
q = p->left;
|
||||
}
|
||||
if ((q->right == NULL || !q->right->red)
|
||||
&& (q->left == NULL || !q->left->red))
|
||||
{
|
||||
q->red = 1;
|
||||
r = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (q->left == NULL || !q->left->red)
|
||||
{
|
||||
node q2 = q->right;
|
||||
q2->red = p->red;
|
||||
p->left = q2->right;
|
||||
q->right = q2->left;
|
||||
q2->left = q;
|
||||
q2->right = p;
|
||||
*pp = q2;
|
||||
p->red = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
q->red = p->red;
|
||||
p->red = 0;
|
||||
q->left->red = 0;
|
||||
p->left = q->right;
|
||||
q->right = p;
|
||||
*pp = q;
|
||||
}
|
||||
sp = 1;
|
||||
r = NULL;
|
||||
}
|
||||
}
|
||||
--sp;
|
||||
}
|
||||
if (r != NULL)
|
||||
r->red = 0;
|
||||
}
|
||||
|
||||
free (unchained);
|
||||
return retval;
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tdelete, tdelete)
|
||||
#endif
|
||||
|
||||
|
||||
/* Walk the nodes of a tree.
|
||||
ROOT is the root of the tree to be walked, ACTION the function to be
|
||||
called at each node. LEVEL is the level of ROOT in the whole tree. */
|
||||
static void
|
||||
internal_function
|
||||
trecurse (const void *vroot, __action_fn_t action, int level)
|
||||
{
|
||||
const_node root = (const_node) vroot;
|
||||
|
||||
if (root->left == NULL && root->right == NULL)
|
||||
(*action) (root, leaf, level);
|
||||
else
|
||||
{
|
||||
(*action) (root, preorder, level);
|
||||
if (root->left != NULL)
|
||||
trecurse (root->left, action, level + 1);
|
||||
(*action) (root, postorder, level);
|
||||
if (root->right != NULL)
|
||||
trecurse (root->right, action, level + 1);
|
||||
(*action) (root, endorder, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Walk the nodes of a tree.
|
||||
ROOT is the root of the tree to be walked, ACTION the function to be
|
||||
called at each node. */
|
||||
void
|
||||
__twalk (const void *vroot, __action_fn_t action)
|
||||
{
|
||||
const_node root = (const_node) vroot;
|
||||
|
||||
CHECK_TREE (root);
|
||||
|
||||
if (root != NULL && action != NULL)
|
||||
trecurse (root, action, 0);
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__twalk, twalk)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* The standardized functions miss an important functionality: the
|
||||
tree cannot be removed easily. We provide a function to do this. */
|
||||
static void
|
||||
internal_function
|
||||
tdestroy_recurse (node root, void (*freefct)(void *))
|
||||
{
|
||||
if (root->left != NULL)
|
||||
tdestroy_recurse (root->left, freefct);
|
||||
if (root->right != NULL)
|
||||
tdestroy_recurse (root->right, freefct);
|
||||
(*freefct) ((void *) root->key);
|
||||
/* Free the node itself. */
|
||||
free (root);
|
||||
}
|
||||
|
||||
void
|
||||
__tdestroy (void *vroot, void (*freefct)(void *))
|
||||
{
|
||||
node root = (node) vroot;
|
||||
|
||||
CHECK_TREE (root);
|
||||
|
||||
if (root != NULL)
|
||||
tdestroy_recurse (root, freefct);
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tdestroy, tdestroy)
|
||||
#endif
|
||||
@@ -1,5 +1,8 @@
|
||||
/* vsprintf with automatic memory allocation.
|
||||
Copyright (C) 1999, 2002-2006 Free Software Foundation, Inc.
|
||||
This file is intended to provide exactly the same functionality
|
||||
as the version in gnulib, but without the need for the xsize module.
|
||||
|
||||
Copyright (C) 1999, 2002-2007 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
|
||||
@@ -23,7 +26,6 @@
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef IN_LIBINTL
|
||||
# include <alloca.h>
|
||||
#endif
|
||||
@@ -37,6 +39,7 @@
|
||||
|
||||
#include <stdio.h> /* snprintf(), sprintf() */
|
||||
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
|
||||
#include <stdint.h> /* SIZE_MAX */
|
||||
#include <string.h> /* memcpy(), strlen() */
|
||||
#include <errno.h> /* errno */
|
||||
#include <limits.h> /* CHAR_BIT, INT_MAX */
|
||||
@@ -47,17 +50,8 @@
|
||||
# include "printf-parse.h"
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
|
||||
#ifndef EOVERFLOW
|
||||
# define EOVERFLOW E2BIG
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WCHAR_T
|
||||
# ifdef HAVE_WCSLEN
|
||||
#if HAVE_WCHAR_T
|
||||
# if HAVE_WCSLEN
|
||||
# define local_wcslen wcslen
|
||||
# else
|
||||
/* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
|
||||
@@ -152,7 +146,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
#if HAVE_ALLOCA
|
||||
if (buf_neededlength < 4000 / sizeof (CHAR_T))
|
||||
{
|
||||
buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
|
||||
buf = alloca (buf_neededlength * sizeof (CHAR_T));
|
||||
buf_malloced = NULL;
|
||||
}
|
||||
else
|
||||
@@ -254,7 +248,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
case TYPE_COUNT_LONGINT_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_longint_pointer = length;
|
||||
break;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if HAVE_LONG_LONG_INT
|
||||
case TYPE_COUNT_LONGLONGINT_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
|
||||
break;
|
||||
@@ -338,7 +332,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
{
|
||||
|
||||
case 'd': case 'i': case 'u':
|
||||
# ifdef HAVE_LONG_LONG
|
||||
# if HAVE_LONG_LONG_INT
|
||||
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
|
||||
@@ -369,7 +363,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
# ifdef HAVE_LONG_LONG
|
||||
# if HAVE_LONG_LONG_INT
|
||||
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
|
||||
@@ -397,7 +391,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
break;
|
||||
|
||||
case 'x': case 'X':
|
||||
# ifdef HAVE_LONG_LONG
|
||||
# if HAVE_LONG_LONG_INT
|
||||
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
|
||||
@@ -426,7 +420,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
break;
|
||||
|
||||
case 'f': case 'F':
|
||||
# ifdef HAVE_LONG_DOUBLE
|
||||
# if HAVE_LONG_DOUBLE
|
||||
if (type == TYPE_LONGDOUBLE)
|
||||
tmp_length =
|
||||
(unsigned int) (LDBL_MAX_EXP
|
||||
@@ -450,7 +444,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
break;
|
||||
|
||||
case 'e': case 'E': case 'g': case 'G':
|
||||
case 'a': case 'A':
|
||||
tmp_length =
|
||||
12; /* sign, decimal point, exponent etc. */
|
||||
tmp_length += precision;
|
||||
@@ -458,8 +451,31 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
goto out_of_memory;
|
||||
break;
|
||||
|
||||
case 'a': case 'A':
|
||||
# if HAVE_LONG_DOUBLE
|
||||
if (type == TYPE_LONGDOUBLE)
|
||||
tmp_length =
|
||||
(unsigned int) (LDBL_DIG
|
||||
* 0.831 /* decimal -> hexadecimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
# endif
|
||||
tmp_length =
|
||||
(unsigned int) (DBL_DIG
|
||||
* 0.831 /* decimal -> hexadecimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
if (tmp_length < precision)
|
||||
tmp_length = precision;
|
||||
/* Account for sign, decimal point etc. */
|
||||
tmp_length += 12;
|
||||
if (tmp_length < 12)
|
||||
goto out_of_memory;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
|
||||
# if HAVE_WINT_T && !WIDE_CHAR_VERSION
|
||||
if (type == TYPE_WIDE_CHAR)
|
||||
tmp_length = MB_CUR_MAX;
|
||||
else
|
||||
@@ -468,7 +484,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
break;
|
||||
|
||||
case 's':
|
||||
# ifdef HAVE_WCHAR_T
|
||||
# if HAVE_WCHAR_T
|
||||
if (type == TYPE_WIDE_STRING)
|
||||
{
|
||||
tmp_length =
|
||||
@@ -551,7 +567,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
|
||||
switch (type)
|
||||
{
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if HAVE_LONG_LONG_INT
|
||||
case TYPE_LONGLONGINT:
|
||||
case TYPE_ULONGLONGINT:
|
||||
*p++ = 'l';
|
||||
@@ -559,15 +575,15 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
#endif
|
||||
case TYPE_LONGINT:
|
||||
case TYPE_ULONGINT:
|
||||
#ifdef HAVE_WINT_T
|
||||
#if HAVE_WINT_T
|
||||
case TYPE_WIDE_CHAR:
|
||||
#endif
|
||||
#ifdef HAVE_WCHAR_T
|
||||
#if HAVE_WCHAR_T
|
||||
case TYPE_WIDE_STRING:
|
||||
#endif
|
||||
*p++ = 'l';
|
||||
break;
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#if HAVE_LONG_DOUBLE
|
||||
case TYPE_LONGDOUBLE:
|
||||
*p++ = 'L';
|
||||
break;
|
||||
@@ -705,7 +721,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if HAVE_LONG_LONG_INT
|
||||
case TYPE_LONGLONGINT:
|
||||
{
|
||||
long long int arg = a.arg[dp->arg_index].a.a_longlongint;
|
||||
@@ -725,7 +741,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#if HAVE_LONG_DOUBLE
|
||||
case TYPE_LONGDOUBLE:
|
||||
{
|
||||
long double arg = a.arg[dp->arg_index].a.a_longdouble;
|
||||
@@ -739,7 +755,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_WINT_T
|
||||
#if HAVE_WINT_T
|
||||
case TYPE_WIDE_CHAR:
|
||||
{
|
||||
wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
|
||||
@@ -753,7 +769,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_WCHAR_T
|
||||
#if HAVE_WCHAR_T
|
||||
case TYPE_WIDE_STRING:
|
||||
{
|
||||
const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
|
||||
|
||||
@@ -175,6 +175,8 @@ same.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
savewd.m4
|
||||
selinux-context-h.m4
|
||||
selinux-selinux-h.m4
|
||||
setenv.m4
|
||||
settime.m4
|
||||
sha1.m4
|
||||
|
||||
2
m4/.gitignore
vendored
2
m4/.gitignore
vendored
@@ -168,6 +168,8 @@ same.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
savewd.m4
|
||||
selinux-context-h.m4
|
||||
selinux-selinux-h.m4
|
||||
setenv.m4
|
||||
settime.m4
|
||||
sha1.m4
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
dist_man_MANS = \
|
||||
base64.1 basename.1 cat.1 chgrp.1 chmod.1 chown.1 cksum.1 comm.1 \
|
||||
base64.1 basename.1 cat.1 chcon.1 chgrp.1 chmod.1 chown.1 cksum.1 comm.1 \
|
||||
cp.1 csplit.1 cut.1 date.1 dd.1 df.1 dir.1 dircolors.1 dirname.1 du.1 \
|
||||
echo.1 env.1 expand.1 expr.1 factor.1 false.1 fmt.1 fold.1 groups.1 \
|
||||
head.1 hostname.1 id.1 install.1 join.1 kill.1 \
|
||||
link.1 ln.1 logname.1 \
|
||||
ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nl.1 nohup.1 od.1 \
|
||||
paste.1 pathchk.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \
|
||||
rm.1 rmdir.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \
|
||||
rm.1 rmdir.1 runcon.1 seq.1 \
|
||||
sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \
|
||||
shred.1 shuf.1 sleep.1 sort.1 split.1 stat.1 \
|
||||
su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \
|
||||
tty.1 unexpand.1 uniq.1 unlink.1 vdir.1 wc.1 \
|
||||
@@ -45,6 +46,7 @@ common_dep = $(top_srcdir)/configure.ac
|
||||
base64.1: $(common_dep) $(srcdir)/base64.x ../src/base64.c
|
||||
basename.1: $(common_dep) $(srcdir)/basename.x ../src/basename.c
|
||||
cat.1: $(common_dep) $(srcdir)/cat.x ../src/cat.c
|
||||
chcon.1: $(common_dep) $(srcdir)/chcon.x ../src/chcon.c
|
||||
chgrp.1: $(common_dep) $(srcdir)/chgrp.x ../src/chgrp.c
|
||||
chmod.1: $(common_dep) $(srcdir)/chmod.x ../src/chmod.c
|
||||
chown.1: $(common_dep) $(srcdir)/chown.x ../src/chown.c
|
||||
@@ -104,6 +106,7 @@ pwd.1: $(common_dep) $(srcdir)/pwd.x ../src/pwd.c
|
||||
readlink.1: $(common_dep) $(srcdir)/readlink.x ../src/readlink.c
|
||||
rm.1: $(common_dep) $(srcdir)/rm.x ../src/rm.c
|
||||
rmdir.1: $(common_dep) $(srcdir)/rmdir.x ../src/rmdir.c
|
||||
runcon.1: $(common_dep) $(srcdir)/runcon.x ../src/runcon.c
|
||||
seq.1: $(common_dep) $(srcdir)/seq.x ../src/seq.c
|
||||
sha1sum.1: $(common_dep) $(srcdir)/sha1sum.x ../src/md5sum.c
|
||||
sha224sum.1: $(common_dep) $(srcdir)/sha224sum.x ../src/md5sum.c
|
||||
|
||||
4
man/chcon.x
Normal file
4
man/chcon.x
Normal file
@@ -0,0 +1,4 @@
|
||||
[NAME]
|
||||
chcon \- change file security context
|
||||
[DESCRIPTION]
|
||||
.\" Add any additional description here
|
||||
14
man/runcon.x
Normal file
14
man/runcon.x
Normal file
@@ -0,0 +1,14 @@
|
||||
[NAME]
|
||||
runcon \- run command with specified security context
|
||||
[DESCRIPTION]
|
||||
Run COMMAND with completely-specified CONTEXT, or with current or
|
||||
transitioned security context modified by one or more of LEVEL,
|
||||
ROLE, TYPE, and USER.
|
||||
.PP
|
||||
If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified,
|
||||
the first argument is used as the complete context. Any additional
|
||||
arguments after \fICOMMAND\fR are interpreted as arguments to the
|
||||
command.
|
||||
.PP
|
||||
Note that only carefully-chosen contexts are likely to successfully
|
||||
run.
|
||||
@@ -1,3 +1,11 @@
|
||||
2007-02-02 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* POTFILES.in: Add src/runcon.c.
|
||||
|
||||
2007-01-13 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* POTFILES.in: Add src/chcon.c.
|
||||
|
||||
2006-10-19 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* POTFILES.in: Also include lib/regcomp.c, since it too uses gettext.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# List of files which contain translatable strings.
|
||||
# Copyright (C) 1996-2006 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2007 Free Software Foundation, Inc.
|
||||
|
||||
# These are nominally temporary...
|
||||
lib/acl.c
|
||||
@@ -33,6 +33,7 @@ lib/xstrtol.h
|
||||
src/base64.c
|
||||
src/basename.c
|
||||
src/cat.c
|
||||
src/chcon.c
|
||||
src/chgrp.c
|
||||
src/chmod.c
|
||||
src/chown-core.c
|
||||
@@ -90,6 +91,7 @@ src/readlink.c
|
||||
src/remove.c
|
||||
src/rm.c
|
||||
src/rmdir.c
|
||||
src/runcon.c
|
||||
src/seq.c
|
||||
src/setuidgid.c
|
||||
src/shred.c
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who
|
||||
|
||||
bin_SCRIPTS = groups
|
||||
bin_PROGRAMS = [ chgrp chown chmod cp dd dircolors du \
|
||||
bin_PROGRAMS = [ chcon chgrp chown chmod cp dd dircolors du \
|
||||
ginstall link ln dir vdir ls mkdir \
|
||||
mkfifo mknod mv nohup 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 sha224sum sha256sum sha384sum sha512sum \
|
||||
shuf 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 \
|
||||
hostname id kill logname pathchk printenv printf pwd \
|
||||
runcon seq sleep tee \
|
||||
test true tty whoami yes \
|
||||
base64 \
|
||||
$(OPTIONAL_BIN_PROGS) $(DF_PROG)
|
||||
@@ -60,9 +61,14 @@ AM_CPPFLAGS = -I$(top_srcdir)/lib
|
||||
LDADD = ../lib/libcoreutils.a $(LIBINTL) ../lib/libcoreutils.a
|
||||
|
||||
# for eaccess in lib/euidaccess.c.
|
||||
cp_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
ginstall_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
mv_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
chcon_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
cp_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
ginstall_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
mkdir_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
mkfifo_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
mknod_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
mv_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
runcon_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
pathchk_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
rm_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
test_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
@@ -71,12 +77,13 @@ __LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
|
||||
# for clock_gettime and fdatasync
|
||||
dd_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC)
|
||||
dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX)
|
||||
id_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX)
|
||||
pr_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
shred_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC)
|
||||
shuf_LDADD = $(LDADD) $(LIB_GETHRXTIME)
|
||||
vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX)
|
||||
|
||||
## If necessary, add -lm to resolve use of pow in lib/strtod.c.
|
||||
sort_LDADD = $(LDADD) $(POW_LIB) $(LIB_GETHRXTIME)
|
||||
@@ -111,6 +118,8 @@ cp_LDADD += $(LIB_ACL)
|
||||
mv_LDADD += $(LIB_ACL)
|
||||
ginstall_LDADD += $(LIB_ACL)
|
||||
|
||||
stat_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
|
||||
$(PROGRAMS): ../lib/libcoreutils.a
|
||||
|
||||
SUFFIXES = .sh
|
||||
|
||||
@@ -31,7 +31,24 @@ index 4728bdd..7477da5 100644
|
||||
if (top->unremovable)
|
||||
hash_free (top->unremovable);
|
||||
obstack_blank (&ds->Active_dir, -(int) sizeof (struct AD_ent));
|
||||
@@ -1481,6 +1483,7 @@ rm_1 (Dirstack_state *ds, char const *fi
|
||||
@@ -815,6 +817,7 @@ prompt (int fd_cwd, Dirstack_state const *ds, char const *filename,
|
||||
|
||||
if (write_protected || x->interactive == RMI_ALWAYS)
|
||||
{
|
||||
+ char const *quoted_name = quote (full_filename (filename));
|
||||
if (write_protected <= 0
|
||||
&& cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
{
|
||||
@@ -832,8 +835,6 @@ prompt (int fd_cwd, Dirstack_state const *ds, char const *filename,
|
||||
write_protected = EISDIR;
|
||||
}
|
||||
|
||||
- char const *quoted_name = quote (full_filename (filename));
|
||||
-
|
||||
if (0 < write_protected)
|
||||
{
|
||||
error (0, write_protected, _("cannot remove %s"), quoted_name);
|
||||
@@ -1487,6 +1488,7 @@ rm_1 (Dirstack_state *ds, char const *filename,
|
||||
return RM_ERROR;
|
||||
}
|
||||
|
||||
@@ -39,7 +56,7 @@ index 4728bdd..7477da5 100644
|
||||
struct stat st;
|
||||
cache_stat_init (&st);
|
||||
cycle_check_init (&ds->cycle_check_state);
|
||||
@@ -1503,6 +1506,7 @@ rm_1 (Dirstack_state *ds, char const *fi
|
||||
@@ -1509,6 +1511,7 @@ rm_1 (Dirstack_state *ds, char const *filename,
|
||||
AD_push_initial (ds);
|
||||
AD_INIT_OTHER_MEMBERS ();
|
||||
|
||||
@@ -47,7 +64,7 @@ index 4728bdd..7477da5 100644
|
||||
enum RM_status status = remove_entry (AT_FDCWD, ds, filename, &st, x, NULL);
|
||||
if (status == RM_NONEMPTY_DIR)
|
||||
{
|
||||
@@ -1519,6 +1523,8 @@ rm_1 (Dirstack_state *ds, char const *fi
|
||||
@@ -1525,6 +1528,8 @@ rm_1 (Dirstack_state *ds, char const *filename,
|
||||
|
||||
ds_clear (ds);
|
||||
return status;
|
||||
|
||||
590
src/chcon.c
Normal file
590
src/chcon.c
Normal file
@@ -0,0 +1,590 @@
|
||||
/* chcon -- change security context of files
|
||||
Copyright (C) 2005-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "dev-ino.h"
|
||||
#include "error.h"
|
||||
#include "openat.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
#include "root-dev-ino.h"
|
||||
#include "selinux-at.h"
|
||||
#include "xfts.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "chcon"
|
||||
|
||||
#define AUTHORS "Russell Coker", "Jim Meyering"
|
||||
|
||||
enum Change_status
|
||||
{
|
||||
CH_NOT_APPLIED,
|
||||
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
|
||||
};
|
||||
|
||||
/* The name the program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, and the systems has support for it, change the context
|
||||
of symbolic links rather than any files they point to. */
|
||||
static bool affect_symlink_referent;
|
||||
|
||||
/* If true, change the modes of directories recursively. */
|
||||
static bool recurse;
|
||||
|
||||
/* Level of verbosity. */
|
||||
static bool verbose;
|
||||
|
||||
/* Pointer to the device and inode numbers of `/', when --recursive.
|
||||
Otherwise NULL. */
|
||||
static struct dev_ino *root_dev_ino;
|
||||
|
||||
/* The name of the context file is being given. */
|
||||
static char const *specified_context;
|
||||
|
||||
/* Specific components of the context */
|
||||
static char const *specified_user;
|
||||
static char const *specified_role;
|
||||
static char const *specified_range;
|
||||
static char const *specified_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
|
||||
{
|
||||
DEREFERENCE_OPTION = CHAR_MAX + 1,
|
||||
NO_PRESERVE_ROOT,
|
||||
PRESERVE_ROOT,
|
||||
REFERENCE_FILE_OPTION
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{"recursive", no_argument, NULL, 'R'},
|
||||
{"dereference", no_argument, NULL, DEREFERENCE_OPTION},
|
||||
{"no-dereference", no_argument, NULL, 'h'},
|
||||
{"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
|
||||
{"preserve-root", no_argument, NULL, PRESERVE_ROOT},
|
||||
{"reference", required_argument, NULL, REFERENCE_FILE_OPTION},
|
||||
{"user", required_argument, NULL, 'u'},
|
||||
{"role", required_argument, NULL, 'r'},
|
||||
{"type", required_argument, NULL, 't'},
|
||||
{"range", required_argument, NULL, 'l'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Given a security context, CONTEXT, derive a context_t (*RET),
|
||||
setting any portions selected via the global variables, specified_user,
|
||||
specified_role, etc. */
|
||||
static int
|
||||
compute_context_from_mask (security_context_t context, context_t *ret)
|
||||
{
|
||||
bool ok = true;
|
||||
context_t new_context = context_new (context);
|
||||
if (!new_context)
|
||||
{
|
||||
error (0, errno, _("failed to create security context: %s"),
|
||||
quotearg_colon (context));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SET_COMPONENT(C, comp) \
|
||||
do \
|
||||
{ \
|
||||
if (specified_ ## comp \
|
||||
&& context_ ## comp ## _set ((C), specified_ ## comp)) \
|
||||
{ \
|
||||
error (0, errno, \
|
||||
_("failed to set %s security context component to %s"), \
|
||||
#comp, quote (specified_ ## comp)); \
|
||||
ok = false; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
SET_COMPONENT (new_context, user);
|
||||
SET_COMPONENT (new_context, range);
|
||||
SET_COMPONENT (new_context, role);
|
||||
SET_COMPONENT (new_context, type);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
context_free (new_context);
|
||||
errno = saved_errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*ret = new_context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change the context of FILE, using specified components.
|
||||
If it is a directory and -R is given, recurse.
|
||||
Return 0 if successful, 1 if errors occurred. */
|
||||
|
||||
static int
|
||||
change_file_context (int fd, char const *file)
|
||||
{
|
||||
security_context_t file_context = NULL;
|
||||
context_t context;
|
||||
security_context_t context_string;
|
||||
int errors = 0;
|
||||
|
||||
if (specified_context == NULL)
|
||||
{
|
||||
int status = (affect_symlink_referent
|
||||
? getfileconat (fd, file, &file_context)
|
||||
: lgetfileconat (fd, file, &file_context));
|
||||
|
||||
if (status < 0 && errno != ENODATA)
|
||||
{
|
||||
error (0, errno, _("failed to get security context of %s"),
|
||||
quote (file));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If the file doesn't have a context, and we're not setting all of
|
||||
the context components, there isn't really an obvious default.
|
||||
Thus, we just give up. */
|
||||
if (file_context == NULL)
|
||||
{
|
||||
error (0, 0, _("can't apply partial context to unlabeled file %s"),
|
||||
quote (file));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (compute_context_from_mask (file_context, &context))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: this should be done exactly once, in main. */
|
||||
context = context_new (specified_context);
|
||||
if (!context)
|
||||
abort ();
|
||||
}
|
||||
|
||||
context_string = context_str (context);
|
||||
|
||||
if (file_context == NULL || ! STREQ (context_string, file_context))
|
||||
{
|
||||
int fail = (affect_symlink_referent
|
||||
? setfileconat (fd, file, context_string)
|
||||
: lsetfileconat (fd, file, context_string));
|
||||
|
||||
if (fail)
|
||||
{
|
||||
errors = 1;
|
||||
error (0, errno, _("failed to change context of %s to %s"),
|
||||
quote_n (0, file), quote_n (1, context_string));
|
||||
}
|
||||
}
|
||||
|
||||
context_free (context);
|
||||
freecon (file_context);
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/* Change the context of FILE.
|
||||
Return true if successful. This function is called
|
||||
once for every file system object that fts encounters. */
|
||||
|
||||
static bool
|
||||
process_file (FTS *fts, FTSENT *ent)
|
||||
{
|
||||
char const *file_full_name = ent->fts_path;
|
||||
char const *file = ent->fts_accpath;
|
||||
const struct stat *file_stats = ent->fts_statp;
|
||||
bool ok = true;
|
||||
|
||||
switch (ent->fts_info)
|
||||
{
|
||||
case FTS_D:
|
||||
if (recurse)
|
||||
{
|
||||
if (ROOT_DEV_INO_CHECK (root_dev_ino, ent->fts_statp))
|
||||
{
|
||||
/* This happens e.g., with "chcon -R --preserve-root ... /"
|
||||
and with "chcon -RH --preserve-root ... symlink-to-root". */
|
||||
ROOT_DEV_INO_WARN (file_full_name);
|
||||
/* Tell fts not to traverse into this hierarchy. */
|
||||
fts_set (fts, ent, FTS_SKIP);
|
||||
/* Ensure that we do not process "/" on the second visit. */
|
||||
ent = fts_read (fts);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case FTS_DP:
|
||||
if (! recurse)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case FTS_NS:
|
||||
/* For a top-level file or directory, this FTS_NS (stat failed)
|
||||
indicator is determined at the time of the initial fts_open call.
|
||||
With programs like chmod, chown, and chgrp, that modify
|
||||
permissions, it is possible that the file in question is
|
||||
accessible when control reaches this point. So, if this is
|
||||
the first time we've seen the FTS_NS for this file, tell
|
||||
fts_read to stat it "again". */
|
||||
if (ent->fts_level == 0 && ent->fts_number == 0)
|
||||
{
|
||||
ent->fts_number = 1;
|
||||
fts_set (fts, ent, FTS_AGAIN);
|
||||
return true;
|
||||
}
|
||||
error (0, ent->fts_errno, _("cannot access %s"), quote (file_full_name));
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
case FTS_ERR:
|
||||
error (0, ent->fts_errno, _("%s"), quote (file_full_name));
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
case FTS_DNR:
|
||||
error (0, ent->fts_errno, _("cannot read directory %s"),
|
||||
quote (file_full_name));
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ent->fts_info == FTS_DP
|
||||
&& ok && ROOT_DEV_INO_CHECK (root_dev_ino, file_stats))
|
||||
{
|
||||
ROOT_DEV_INO_WARN (file_full_name);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if (verbose)
|
||||
printf (_("changing security context of %s"),
|
||||
quote (file_full_name));
|
||||
|
||||
if (change_file_context (fts->fts_cwd_fd, file) != 0)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if ( ! recurse)
|
||||
fts_set (fts, ent, FTS_SKIP);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* Recursively operate on the specified FILES (the last entry
|
||||
of which is NULL). BIT_FLAGS controls how fts works.
|
||||
Return true if successful. */
|
||||
|
||||
static bool
|
||||
process_files (char **files, int bit_flags)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
FTS *fts = xfts_open (files, bit_flags, NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
FTSENT *ent;
|
||||
|
||||
ent = fts_read (fts);
|
||||
if (ent == NULL)
|
||||
{
|
||||
if (errno != 0)
|
||||
{
|
||||
/* FIXME: try to give a better message */
|
||||
error (0, errno, _("fts_read failed"));
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ok &= process_file (fts, ent);
|
||||
}
|
||||
|
||||
/* Ignore failure, since the only way it can do so is in failing to
|
||||
return to the original directory, and since we're about to exit,
|
||||
that doesn't matter. */
|
||||
fts_close (fts);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]... CONTEXT FILE...\n\
|
||||
or: %s [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...\n\
|
||||
or: %s [OPTION]... --reference=RFILE FILE...\n\
|
||||
"),
|
||||
program_name, program_name, program_name);
|
||||
fputs (_("\
|
||||
Change the security context of each FILE to CONTEXT.\n\
|
||||
With --reference, change the security context of each FILE to that of RFILE.\n\
|
||||
\n\
|
||||
-c, --changes like verbose but report only when a change is made\n\
|
||||
-h, --no-dereference affect symbolic links instead of any referenced file\n\
|
||||
(available only on systems with lchown system call)\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--reference=RFILE use RFILE's security context rather than specifying\n\
|
||||
a CONTEXT value\n\
|
||||
-R, --recursive operate on files and directories recursively\n\
|
||||
-v, --verbose output a diagnostic for every file processed\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-u, --user=USER set user USER in the target security context\n\
|
||||
-r, --role=ROLE set role ROLE in the target security context\n\
|
||||
-t, --type=TYPE set type TYPE in the target security context\n\
|
||||
-l, --range=RANGE set range RANGE in the target security context\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
The following options modify how a hierarchy is traversed when the -R\n\
|
||||
option is also specified. If more than one is specified, only the final\n\
|
||||
one takes effect.\n\
|
||||
\n\
|
||||
-H if a command line argument is a symbolic link\n\
|
||||
to a directory, traverse it\n\
|
||||
-L traverse every symbolic link to a directory\n\
|
||||
encountered\n\
|
||||
-P do not traverse any symbolic links (default)\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
security_context_t ref_context = NULL;
|
||||
|
||||
/* Bit flags that control how fts works. */
|
||||
int bit_flags = FTS_PHYSICAL;
|
||||
|
||||
/* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
|
||||
specified. */
|
||||
int dereference = -1;
|
||||
|
||||
bool ok;
|
||||
bool preserve_root = false;
|
||||
bool component_specified = false;
|
||||
char *reference_file = NULL;
|
||||
int optc;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "HLPRchvu:r:t:l:", long_options, NULL))
|
||||
!= -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'H': /* Traverse command-line symlinks-to-directories. */
|
||||
bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
|
||||
break;
|
||||
|
||||
case 'L': /* Traverse all symlinks-to-directories. */
|
||||
bit_flags = FTS_LOGICAL;
|
||||
break;
|
||||
|
||||
case 'P': /* Traverse no symlinks-to-directories. */
|
||||
bit_flags = FTS_PHYSICAL;
|
||||
break;
|
||||
|
||||
case 'h': /* --no-dereference: affect symlinks */
|
||||
dereference = 0;
|
||||
break;
|
||||
|
||||
case DEREFERENCE_OPTION: /* --dereference: affect the referent
|
||||
of each symlink */
|
||||
dereference = 1;
|
||||
break;
|
||||
|
||||
case NO_PRESERVE_ROOT:
|
||||
preserve_root = false;
|
||||
break;
|
||||
|
||||
case PRESERVE_ROOT:
|
||||
preserve_root = true;
|
||||
break;
|
||||
|
||||
case REFERENCE_FILE_OPTION:
|
||||
reference_file = optarg;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
recurse = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
/* ignore */
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
specified_user = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
specified_role = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
specified_type = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
specified_range = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (recurse)
|
||||
{
|
||||
if (bit_flags == FTS_PHYSICAL)
|
||||
{
|
||||
if (dereference == 1)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("-R --dereference requires either -H or -L"));
|
||||
affect_symlink_referent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dereference == 0)
|
||||
error (EXIT_FAILURE, 0, _("-R -h requires -P"));
|
||||
affect_symlink_referent = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bit_flags = FTS_PHYSICAL;
|
||||
affect_symlink_referent = (dereference != 0);
|
||||
}
|
||||
|
||||
if (argc - optind < (reference_file || component_specified ? 1 : 2))
|
||||
{
|
||||
if (argc <= optind)
|
||||
error (0, 0, _("missing operand"));
|
||||
else
|
||||
error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (reference_file)
|
||||
{
|
||||
if (getfilecon (reference_file, &ref_context) < 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to get security context of %s"),
|
||||
quote (reference_file));
|
||||
|
||||
specified_context = ref_context;
|
||||
}
|
||||
else if (component_specified)
|
||||
{
|
||||
/* FIXME: it's already null, so this is a no-op. */
|
||||
specified_context = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
context_t context;
|
||||
specified_context = argv[optind++];
|
||||
context = context_new (specified_context);
|
||||
if (!context)
|
||||
error (EXIT_FAILURE, 0, _("invalid context: %s"),
|
||||
quotearg_colon (specified_context));
|
||||
context_free (context);
|
||||
}
|
||||
|
||||
if (reference_file && component_specified)
|
||||
{
|
||||
error (0, 0, _("conflicting security context specifiers given"));
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (recurse & preserve_root)
|
||||
{
|
||||
static struct dev_ino dev_ino_buf;
|
||||
root_dev_ino = get_root_dev_ino (&dev_ino_buf);
|
||||
if (root_dev_ino == NULL)
|
||||
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
|
||||
quote ("/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
root_dev_ino = NULL;
|
||||
}
|
||||
|
||||
ok = process_files (argv + optind, bit_flags | FTS_NOSTAT);
|
||||
|
||||
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
123
src/copy.c
123
src/copy.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#if HAVE_HURD_H
|
||||
# include <hurd.h>
|
||||
@@ -38,6 +39,7 @@
|
||||
#include "euidaccess.h"
|
||||
#include "error.h"
|
||||
#include "fcntl--.h"
|
||||
#include "filemode.h"
|
||||
#include "filenamecat.h"
|
||||
#include "full-write.h"
|
||||
#include "getpagesize.h"
|
||||
@@ -301,6 +303,42 @@ copy_reg (char const *src_name, char const *dst_name,
|
||||
{
|
||||
dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY);
|
||||
|
||||
/* When using cp --preserve=context to copy to an existing destination,
|
||||
use the default context rather than that of the source. Why?
|
||||
1) the src context may prohibit writing, and
|
||||
2) because it's more consistent to use the same context
|
||||
that is used when the destination file doesn't already exist. */
|
||||
if (x->preserve_security_context && 0 <= dest_desc)
|
||||
{
|
||||
security_context_t con;
|
||||
if (getfscreatecon (&con) < 0)
|
||||
{
|
||||
error (0, errno, _("failed to get file system create context"));
|
||||
if (x->require_preserve_context)
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_desc;
|
||||
}
|
||||
}
|
||||
|
||||
if (con)
|
||||
{
|
||||
if (fsetfilecon (dest_desc, con) < 0)
|
||||
{
|
||||
error (0, errno,
|
||||
_("failed to set the security context of %s to %s"),
|
||||
quote_n (0, dst_name), quote_n (1, con));
|
||||
if (x->require_preserve_context)
|
||||
{
|
||||
return_val = false;
|
||||
freecon (con);
|
||||
goto close_src_desc;
|
||||
}
|
||||
}
|
||||
freecon(con);
|
||||
}
|
||||
}
|
||||
|
||||
if (dest_desc < 0 && x->unlink_dest_after_failed_open)
|
||||
{
|
||||
if (unlink (dst_name) != 0)
|
||||
@@ -797,10 +835,14 @@ overwrite_prompt (char const *dst_name, struct stat const *dst_sb)
|
||||
{
|
||||
if (euidaccess (dst_name, W_OK) != 0)
|
||||
{
|
||||
char perms[12]; /* "-rwxrwxrwx " ls-style modes. */
|
||||
strmode (dst_sb->st_mode, perms);
|
||||
perms[10] = '\0';
|
||||
fprintf (stderr,
|
||||
_("%s: overwrite %s, overriding mode %04lo? "),
|
||||
_("%s: try to overwrite %s, overriding mode %04lo (%s)? "),
|
||||
program_name, quote (dst_name),
|
||||
(unsigned long int) (dst_sb->st_mode & CHMOD_MODE_BITS));
|
||||
(unsigned long int) (dst_sb->st_mode & CHMOD_MODE_BITS),
|
||||
&perms[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -990,6 +1032,15 @@ emit_verbose (char const *src, char const *dst, char const *backup_dst_name)
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* A wrapper around "setfscreatecon (NULL)" that exits upon failure. */
|
||||
static void
|
||||
restore_default_fscreatecon_or_die (void)
|
||||
{
|
||||
if (setfscreatecon (NULL) != 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to restore the default file creation context"));
|
||||
}
|
||||
|
||||
/* Copy the file SRC_NAME to the file DST_NAME. The files may be of
|
||||
any type. NEW_DST should be true if the file DST_NAME cannot
|
||||
exist because its parent directory was just created; NEW_DST should
|
||||
@@ -1338,7 +1389,7 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
if (x->move_mode && src_sb.st_nlink == 1)
|
||||
{
|
||||
earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
|
||||
earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
|
||||
}
|
||||
else if ((x->preserve_links
|
||||
&& (1 < src_sb.st_nlink
|
||||
@@ -1528,6 +1579,38 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
delayed_ok = true;
|
||||
|
||||
if (x->preserve_security_context)
|
||||
{
|
||||
security_context_t con;
|
||||
|
||||
if (0 <= lgetfilecon (src_name, &con))
|
||||
{
|
||||
if (setfscreatecon (con) < 0)
|
||||
{
|
||||
error (0, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (con));
|
||||
if (x->require_preserve_context)
|
||||
{
|
||||
freecon (con);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
freecon (con);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != ENOTSUP && errno != ENODATA)
|
||||
{
|
||||
error (0, errno,
|
||||
_("failed to get security context of %s"),
|
||||
quote (src_name));
|
||||
if (x->require_preserve_context)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In certain modes (cp's --symbolic-link), and for certain file types
|
||||
(symlinks and hard links) it doesn't make sense to preserve metadata,
|
||||
or it's possible to preserve only some of it.
|
||||
@@ -1604,19 +1687,20 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
emit_verbose (src_name, dst_name, NULL);
|
||||
}
|
||||
|
||||
/* Are we crossing a file system boundary? */
|
||||
/* Decide whether to copy the contents of the directory. */
|
||||
if (x->one_file_system && device != 0 && device != src_sb.st_dev)
|
||||
return true;
|
||||
|
||||
/* Copy the contents of the directory. */
|
||||
|
||||
if (! copy_dir (src_name, dst_name, new_dst, &src_sb, dir, x,
|
||||
copy_into_self))
|
||||
{
|
||||
/* Don't just return here -- otherwise, the failure to read a
|
||||
single file in a source directory would cause the containing
|
||||
destination directory not to have owner/perms set properly. */
|
||||
delayed_ok = false;
|
||||
/* Here, we are crossing a file system boundary and cp's -x option
|
||||
is in effect: so don't copy the contents of this directory. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the contents of the directory. Don't just return if
|
||||
this fails -- otherwise, the failure to read a single file
|
||||
in a source directory would cause the containing destination
|
||||
directory not to have owner/perms set properly. */
|
||||
delayed_ok = copy_dir (src_name, dst_name, new_dst, &src_sb, dir, x,
|
||||
copy_into_self);
|
||||
}
|
||||
}
|
||||
else if (x->symbolic_link)
|
||||
@@ -1720,7 +1804,7 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
}
|
||||
else if (S_ISLNK (src_mode))
|
||||
{
|
||||
char *src_link_val = xreadlink (src_name, src_sb.st_size);
|
||||
char *src_link_val = xreadlink_with_size (src_name, src_sb.st_size);
|
||||
if (src_link_val == NULL)
|
||||
{
|
||||
error (0, errno, _("cannot read symbolic link %s"), quote (src_name));
|
||||
@@ -1740,7 +1824,8 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
FIXME: This behavior isn't documented, and seems wrong
|
||||
in some cases, e.g., if the destination symlink has the
|
||||
wrong ownership, permissions, or time stamps. */
|
||||
char *dest_link_val = xreadlink (dst_name, dst_sb.st_size);
|
||||
char *dest_link_val =
|
||||
xreadlink_with_size (dst_name, dst_sb.st_size);
|
||||
if (STREQ (dest_link_val, src_link_val))
|
||||
same_link = true;
|
||||
free (dest_link_val);
|
||||
@@ -1755,6 +1840,9 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
}
|
||||
}
|
||||
|
||||
if (x->preserve_security_context)
|
||||
restore_default_fscreatecon_or_die ();
|
||||
|
||||
/* There's no need to preserve timestamps or permissions. */
|
||||
preserve_metadata = false;
|
||||
|
||||
@@ -1888,6 +1976,9 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
un_backup:
|
||||
|
||||
if (x->preserve_security_context)
|
||||
restore_default_fscreatecon_or_die ();
|
||||
|
||||
/* We have failed to create the destination file.
|
||||
If we've just added a dev/ino entry via the remember_copied
|
||||
call above (i.e., unless we've just failed to create a hard link),
|
||||
|
||||
21
src/copy.h
21
src/copy.h
@@ -1,5 +1,5 @@
|
||||
/* core functions for copying files and directories
|
||||
Copyright (C) 89, 90, 91, 1995-2005 Free Software Foundation.
|
||||
Copyright (C) 89, 90, 91, 1995-2007 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
|
||||
@@ -142,10 +142,25 @@ struct cp_options
|
||||
|
||||
/* If true 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. */
|
||||
nonzero immediately. E.g. for cp -p this must be true, for mv it
|
||||
must be false. */
|
||||
bool require_preserve;
|
||||
|
||||
/* If true, attempt to preserve the SELinux security context, too.
|
||||
Set this only if the kernel is SELinux enabled. */
|
||||
bool preserve_security_context;
|
||||
|
||||
/* Useful only when preserve_security_context is true.
|
||||
If true, a failed attempt to preserve a file's security context
|
||||
propagates failure "out" to the caller. If false, a failure to
|
||||
preserve a file's security context does not change the invoking
|
||||
application's exit status. Give diagnostics for failed syscalls
|
||||
regardless of this setting. For example, with "cp --preserve=context"
|
||||
this flag is "true", while with "cp -a", it is false. That means
|
||||
"cp -a" attempts to preserve any security context, but does not
|
||||
fail if it is unable to do so. */
|
||||
bool require_preserve_context;
|
||||
|
||||
/* If true, copy directories recursively and copy special files
|
||||
as themselves rather than copying their contents. */
|
||||
bool recursive;
|
||||
|
||||
32
src/cp.c
32
src/cp.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "argmatch.h"
|
||||
@@ -85,6 +86,9 @@ enum
|
||||
/* The invocation name of this program. */
|
||||
char *program_name;
|
||||
|
||||
/* True if the kernel is SELinux enabled. */
|
||||
static bool selinux_enabled;
|
||||
|
||||
/* If true, the command "cp x/e_file e_dir" uses "e_dir/x/e_file"
|
||||
as its destination instead of the usual "e_dir/e_file." */
|
||||
static bool parents_option = false;
|
||||
@@ -191,7 +195,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-p same as --preserve=mode,ownership,timestamps\n\
|
||||
--preserve[=ATTR_LIST] preserve the specified attributes (default:\n\
|
||||
mode,ownership,timestamps), if possible\n\
|
||||
additional attributes: links, all\n\
|
||||
additional attributes: context, links, all\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--no-preserve=ATTR_LIST don't preserve the specified attributes\n\
|
||||
@@ -749,6 +753,8 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_links = false;
|
||||
x->preserve_mode = false;
|
||||
x->preserve_timestamps = false;
|
||||
x->preserve_security_context = false;
|
||||
x->require_preserve_context = false;
|
||||
|
||||
x->require_preserve = false;
|
||||
x->recursive = false;
|
||||
@@ -777,18 +783,19 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
PRESERVE_TIMESTAMPS,
|
||||
PRESERVE_OWNERSHIP,
|
||||
PRESERVE_LINK,
|
||||
PRESERVE_CONTEXT,
|
||||
PRESERVE_ALL
|
||||
};
|
||||
static enum File_attribute const preserve_vals[] =
|
||||
{
|
||||
PRESERVE_MODE, PRESERVE_TIMESTAMPS,
|
||||
PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL
|
||||
PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL
|
||||
};
|
||||
/* Valid arguments to the `--preserve' option. */
|
||||
static char const* const preserve_args[] =
|
||||
{
|
||||
"mode", "timestamps",
|
||||
"ownership", "links", "all", NULL
|
||||
"ownership", "links", "context", "all", NULL
|
||||
};
|
||||
ARGMATCH_VERIFY (preserve_args, preserve_vals);
|
||||
|
||||
@@ -824,11 +831,18 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
x->preserve_links = on_off;
|
||||
break;
|
||||
|
||||
case PRESERVE_CONTEXT:
|
||||
x->preserve_security_context = on_off;
|
||||
x->require_preserve_context = on_off;
|
||||
break;
|
||||
|
||||
case PRESERVE_ALL:
|
||||
x->preserve_mode = on_off;
|
||||
x->preserve_timestamps = on_off;
|
||||
x->preserve_ownership = on_off;
|
||||
x->preserve_links = on_off;
|
||||
if (selinux_enabled)
|
||||
x->preserve_security_context = on_off;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -862,6 +876,7 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
/* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
|
||||
@@ -1048,9 +1063,6 @@ main (int argc, char **argv)
|
||||
x.dereference = DEREF_ALWAYS;
|
||||
}
|
||||
|
||||
/* The key difference between -d (--no-dereference) and not is the version
|
||||
of `stat' to call. */
|
||||
|
||||
if (x.recursive)
|
||||
x.copy_as_regular = copy_contents;
|
||||
|
||||
@@ -1059,6 +1071,14 @@ main (int argc, char **argv)
|
||||
if (x.unlink_dest_after_failed_open & (x.hard_link | x.symbolic_link))
|
||||
x.unlink_dest_before_opening = true;
|
||||
|
||||
if (x.preserve_security_context)
|
||||
{
|
||||
if (!selinux_enabled)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot preserve security context "
|
||||
"without an SELinux-enabled kernel"));
|
||||
}
|
||||
|
||||
/* Allocate space for remembering copied and created files. */
|
||||
|
||||
hash_init ();
|
||||
|
||||
17
src/df.c
17
src/df.c
@@ -796,10 +796,7 @@ main (int argc, char **argv)
|
||||
inode_format = false;
|
||||
show_all_fs = false;
|
||||
show_listed_fs = false;
|
||||
|
||||
human_output_opts = human_options (getenv ("DF_BLOCK_SIZE"), false,
|
||||
&output_block_size);
|
||||
|
||||
human_output_opts = -1;
|
||||
print_type = false;
|
||||
file_systems_processed = false;
|
||||
posix_format = false;
|
||||
@@ -876,6 +873,18 @@ main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (human_output_opts == -1)
|
||||
{
|
||||
if (posix_format)
|
||||
{
|
||||
human_output_opts = 0;
|
||||
output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
|
||||
}
|
||||
else
|
||||
human_output_opts = human_options (getenv ("DF_BLOCK_SIZE"), false,
|
||||
&output_block_size);
|
||||
}
|
||||
|
||||
/* Fail if the same file system type was both selected and excluded. */
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
43
src/fs.h
43
src/fs.h
@@ -1,43 +0,0 @@
|
||||
/* Define the magic numbers as given by statfs(2).
|
||||
Please send additions to bug-coreutils@gnu.org and meskes@debian.org.
|
||||
This file is generated automatically from ./stat.c. */
|
||||
|
||||
#if defined __linux__
|
||||
# define S_MAGIC_AFFS 0xADFF
|
||||
# define S_MAGIC_DEVPTS 0x1CD1
|
||||
# define S_MAGIC_EXT 0x137D
|
||||
# define S_MAGIC_EXT2_OLD 0xEF51
|
||||
# define S_MAGIC_EXT2 0xEF53
|
||||
# define S_MAGIC_JFS 0x3153464a
|
||||
# define S_MAGIC_XFS 0x58465342
|
||||
# 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
|
||||
# define S_MAGIC_RAMFS 0x858458f6
|
||||
# define S_MAGIC_SQUASHFS 0x73717368
|
||||
# define S_MAGIC_SYSFS 0x62656572
|
||||
#elif defined __GNU__
|
||||
# include <hurd/hurd_types.h>
|
||||
#endif
|
||||
63
src/id.c
63
src/id.c
@@ -1,5 +1,5 @@
|
||||
/* id -- print real and effective UIDs and GIDs
|
||||
Copyright (C) 1989-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1989-2007 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
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <getopt.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -37,6 +38,9 @@
|
||||
|
||||
int getugroups ();
|
||||
|
||||
/* If nonzero, output only the SELinux context. -Z */
|
||||
static int just_context = 0;
|
||||
|
||||
static void print_user (uid_t uid);
|
||||
static void print_group (gid_t gid);
|
||||
static void print_group_list (const char *username);
|
||||
@@ -55,8 +59,13 @@ static gid_t rgid, egid;
|
||||
/* True unless errors have been encountered. */
|
||||
static bool ok = true;
|
||||
|
||||
/* The SELinux context. Start with a known invalid value so print_full_info
|
||||
knows when `context' has not been set to a meaningful value. */
|
||||
static security_context_t context = NULL;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"context", no_argument, NULL, 'Z'},
|
||||
{"group", no_argument, NULL, 'g'},
|
||||
{"groups", no_argument, NULL, 'G'},
|
||||
{"name", no_argument, NULL, 'n'},
|
||||
@@ -80,6 +89,7 @@ usage (int status)
|
||||
Print information for USERNAME, or the current user.\n\
|
||||
\n\
|
||||
-a ignore, for compatibility with other versions\n\
|
||||
-Z, --context print only the security context of the current user\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\
|
||||
@@ -101,6 +111,7 @@ int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc;
|
||||
int selinux_enabled = (is_selinux_enabled () > 0);
|
||||
|
||||
/* If true, output the list of all group IDs. -G */
|
||||
bool just_group_list = false;
|
||||
@@ -119,13 +130,22 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'a':
|
||||
/* Ignore -a, for compatibility with SVR4. */
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
/* politely decline if we're not on a selinux-enabled kernel. */
|
||||
if (!selinux_enabled)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("--context (-Z) works only on an SELinux-enabled kernel"));
|
||||
just_context = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
just_group = true;
|
||||
break;
|
||||
@@ -148,19 +168,38 @@ main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (1 < argc - optind)
|
||||
{
|
||||
error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc - optind == 1 && just_context)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot print security context when user specified"));
|
||||
|
||||
if (just_context && !selinux_enabled)
|
||||
error (EXIT_FAILURE, 0, _("\
|
||||
cannot display context when selinux not enabled or when displaying the id\n\
|
||||
of a different user"));
|
||||
|
||||
/* If we are on a selinux-enabled kernel, get our context.
|
||||
Otherwise, leave the context variable alone - it has
|
||||
been initialized known invalid value; if we see this invalid
|
||||
value later, we will know we are on a non-selinux kernel. */
|
||||
if (selinux_enabled)
|
||||
{
|
||||
if (getcon (&context) && just_context)
|
||||
error (EXIT_FAILURE, 0, _("can't get process context"));
|
||||
}
|
||||
|
||||
if (just_user + just_group + just_group_list + just_context > 1)
|
||||
error (EXIT_FAILURE, 0, _("cannot print \"only\" of more than one choice"));
|
||||
|
||||
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)
|
||||
{
|
||||
struct passwd *pwd = getpwnam (argv[optind]);
|
||||
@@ -183,6 +222,8 @@ main (int argc, char **argv)
|
||||
print_group (use_real ? rgid : egid);
|
||||
else if (just_group_list)
|
||||
print_group_list (argv[optind]);
|
||||
else if (just_context)
|
||||
fputs (context, stdout);
|
||||
else
|
||||
print_full_info (argv[optind]);
|
||||
putchar ('\n');
|
||||
@@ -385,4 +426,6 @@ print_full_info (const char *username)
|
||||
free (groups);
|
||||
}
|
||||
#endif /* HAVE_GETGROUPS */
|
||||
if (context != NULL)
|
||||
printf (" context=%s", context);
|
||||
}
|
||||
|
||||
113
src/install.c
113
src/install.c
@@ -24,6 +24,7 @@
|
||||
#include <signal.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "backupfile.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "mkdir-p.h"
|
||||
#include "modechange.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
#include "savewd.h"
|
||||
#include "stat-time.h"
|
||||
#include "utimens.h"
|
||||
@@ -49,6 +51,9 @@
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
static int selinux_enabled = 0;
|
||||
static bool use_default_selinux_context = true;
|
||||
|
||||
#if ! HAVE_ENDGRENT
|
||||
# define endgrent() ((void) 0)
|
||||
#endif
|
||||
@@ -121,15 +126,28 @@ static bool strip_files;
|
||||
/* If true, install a directory instead of a regular file. */
|
||||
static bool dir_arg;
|
||||
|
||||
/* For long options that have no equivalent short option, use a
|
||||
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
||||
enum
|
||||
{
|
||||
PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{"backup", optional_argument, NULL, 'b'},
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"directory", no_argument, NULL, 'd'},
|
||||
{"group", required_argument, NULL, 'g'},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{"no-target-directory", no_argument, NULL, 'T'},
|
||||
{"owner", required_argument, NULL, 'o'},
|
||||
{"preserve-timestamps", no_argument, NULL, 'p'},
|
||||
{"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
|
||||
/* Continue silent support for --preserve_context until Jan 2008. FIXME-obs
|
||||
After that, FIXME-obs: warn in, say, late 2008, and disable altogether
|
||||
a year or two later. */
|
||||
{"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
|
||||
{"strip", no_argument, NULL, 's'},
|
||||
{"suffix", required_argument, NULL, 'S'},
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
@@ -156,6 +174,7 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_mode = false;
|
||||
x->preserve_timestamps = false;
|
||||
x->require_preserve = false;
|
||||
x->require_preserve_context = false;
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
@@ -169,11 +188,47 @@ cp_option_init (struct cp_options *x)
|
||||
x->stdin_tty = false;
|
||||
|
||||
x->update = false;
|
||||
x->preserve_security_context = false;
|
||||
x->verbose = false;
|
||||
x->dest_info = NULL;
|
||||
x->src_info = NULL;
|
||||
}
|
||||
|
||||
/* Modify file context to match the specified policy.
|
||||
If an error occurs the file will remain with the default directory
|
||||
context. */
|
||||
static void
|
||||
setdefaultfilecon (char const *file)
|
||||
{
|
||||
struct stat st;
|
||||
security_context_t scontext = NULL;
|
||||
if (selinux_enabled != 1)
|
||||
{
|
||||
/* Indicate no context found. */
|
||||
return;
|
||||
}
|
||||
if (lstat (file, &st) != 0)
|
||||
return;
|
||||
|
||||
/* If there's an error determining the context, or it has none,
|
||||
return to allow default context */
|
||||
if ((matchpathcon (file, st.st_mode, &scontext) != 0) ||
|
||||
(strcmp (scontext, "<<none>>") == 0))
|
||||
{
|
||||
if (scontext != NULL)
|
||||
freecon (scontext);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
|
||||
error (0, errno,
|
||||
_("warning: %s: failed to change context to %s"),
|
||||
quotearg_colon (file), scontext);
|
||||
|
||||
freecon (scontext);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FILE is the last operand of this command. Return true if FILE is a
|
||||
directory. But report an error there is a problem accessing FILE,
|
||||
or if FILE does not exist but would have to refer to an existing
|
||||
@@ -222,6 +277,9 @@ main (int argc, char **argv)
|
||||
bool no_target_directory = false;
|
||||
int n_files;
|
||||
char **file;
|
||||
security_context_t scontext = NULL;
|
||||
/* set iff kernel has extra selinux system calls */
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
@@ -243,7 +301,7 @@ main (int argc, char **argv)
|
||||
we'll actually use backup_suffix_string. */
|
||||
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:", long_options,
|
||||
while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:Z:", long_options,
|
||||
NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
@@ -305,6 +363,27 @@ main (int argc, char **argv)
|
||||
case 'T':
|
||||
no_target_directory = true;
|
||||
break;
|
||||
|
||||
case PRESERVE_CONTEXT_OPTION:
|
||||
if ( ! selinux_enabled)
|
||||
{
|
||||
error (0, 0, _("Warning: ignoring --preserve-context; "
|
||||
"this kernel is not SELinux-enabled."));
|
||||
break;
|
||||
}
|
||||
x.preserve_security_context = true;
|
||||
use_default_selinux_context = false;
|
||||
break;
|
||||
case 'Z':
|
||||
if ( ! selinux_enabled)
|
||||
{
|
||||
error (0, 0, _("Warning: ignoring --context (-Z); "
|
||||
"this kernel is not SELinux-enabled."));
|
||||
break;
|
||||
}
|
||||
scontext = optarg;
|
||||
use_default_selinux_context = false;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -320,6 +399,11 @@ main (int argc, char **argv)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("target directory not allowed when installing a directory"));
|
||||
|
||||
if (x.preserve_security_context && scontext != NULL)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot force target context to %s and preserve it"),
|
||||
quote (scontext));
|
||||
|
||||
if (backup_suffix_string)
|
||||
simple_backup_suffix = xstrdup (backup_suffix_string);
|
||||
|
||||
@@ -328,6 +412,11 @@ main (int argc, char **argv)
|
||||
version_control_string)
|
||||
: no_backups);
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (scontext));
|
||||
|
||||
n_files = argc - optind;
|
||||
file = argv + optind;
|
||||
|
||||
@@ -503,6 +592,7 @@ copy_file (const char *from, const char *to, const struct cp_options *x)
|
||||
static bool
|
||||
change_attributes (char const *name)
|
||||
{
|
||||
bool ok = false;
|
||||
/* chown must precede chmod because on some systems,
|
||||
chown clears the set[ug]id bits for non-superusers,
|
||||
resulting in incorrect permissions.
|
||||
@@ -521,9 +611,12 @@ change_attributes (char const *name)
|
||||
else if (chmod (name, mode) != 0)
|
||||
error (0, errno, _("cannot change permissions of %s"), quote (name));
|
||||
else
|
||||
return true;
|
||||
ok = true;
|
||||
|
||||
return false;
|
||||
if (use_default_selinux_context)
|
||||
setdefaultfilecon (name);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* Set the timestamps of file TO to match those of file FROM.
|
||||
@@ -566,11 +659,10 @@ strip (char const *name)
|
||||
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"));
|
||||
if (waitpid (pid, &status, 0) < 0)
|
||||
error (EXIT_FAILURE, errno, _("waiting for strip"));
|
||||
else if (! WIFEXITED (status) || WEXITSTATUS (status))
|
||||
error (EXIT_FAILURE, 0, _("strip process terminated abnormally"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -688,6 +780,11 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-T, --no-target-directory treat DEST as a normal file\n\
|
||||
-v, --verbose print the name of each directory as it is created\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--preserve-context preserve SELinux security context\n\
|
||||
-Z, --context=CONTEXT set SELinux security context of files and directories\n\
|
||||
"), stdout);
|
||||
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
fputs (_("\
|
||||
|
||||
93
src/ls.c
93
src/ls.c
@@ -61,6 +61,7 @@
|
||||
#include <pwd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
|
||||
present. */
|
||||
@@ -167,24 +168,20 @@ struct fileinfo
|
||||
zero. */
|
||||
mode_t linkmode;
|
||||
|
||||
/* SELinux security context. */
|
||||
security_context_t scontext;
|
||||
|
||||
bool stat_ok;
|
||||
|
||||
/* For symbolic link and color printing, true if linked-to file
|
||||
exists, otherwise false. */
|
||||
bool linkok;
|
||||
|
||||
#if USE_ACL
|
||||
/* For long listings, true if the file has an access control list. */
|
||||
/* For long listings, true if the file has an access control list,
|
||||
or an SELinux security context. */
|
||||
bool have_acl;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if USE_ACL
|
||||
# define FILE_HAS_ACL(F) ((F)->have_acl)
|
||||
#else
|
||||
# define FILE_HAS_ACL(F) 0
|
||||
#endif
|
||||
|
||||
#define LEN_STR_PAIR(s) sizeof (s) - 1, s
|
||||
|
||||
/* Null is a valid character in a color indicator (think about Epson
|
||||
@@ -320,14 +317,12 @@ static struct pending *pending_dirs;
|
||||
static time_t current_time = TYPE_MINIMUM (time_t);
|
||||
static int current_time_ns = -1;
|
||||
|
||||
static bool print_scontext;
|
||||
|
||||
/* Whether any of the files has an ACL. This affects the width of the
|
||||
mode column. */
|
||||
|
||||
#if USE_ACL
|
||||
static bool any_has_acl;
|
||||
#else
|
||||
enum { any_has_acl = false };
|
||||
#endif
|
||||
|
||||
/* The number of columns to use for columns containing inode numbers,
|
||||
block sizes, link counts, owners, groups, authors, major device
|
||||
@@ -336,6 +331,7 @@ enum { any_has_acl = false };
|
||||
static int inode_number_width;
|
||||
static int block_size_width;
|
||||
static int nlink_width;
|
||||
static int scontext_width;
|
||||
static int owner_width;
|
||||
static int group_width;
|
||||
static int author_width;
|
||||
@@ -787,6 +783,7 @@ static struct option const long_options[] =
|
||||
{"time-style", required_argument, NULL, TIME_STYLE_OPTION},
|
||||
{"color", optional_argument, NULL, COLOR_OPTION},
|
||||
{"block-size", required_argument, NULL, BLOCK_SIZE_OPTION},
|
||||
{"context", no_argument, 0, 'Z'},
|
||||
{"author", no_argument, NULL, AUTHOR_OPTION},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -1246,6 +1243,7 @@ main (int argc, char **argv)
|
||||
|
||||
format_needs_stat = sort_type == sort_time || sort_type == sort_size
|
||||
|| format == long_format
|
||||
|| print_scontext
|
||||
|| print_block_size;
|
||||
format_needs_type = (! format_needs_stat
|
||||
&& (recursive
|
||||
@@ -1439,6 +1437,7 @@ decode_switches (int argc, char **argv)
|
||||
ignore_mode = IGNORE_DEFAULT;
|
||||
ignore_patterns = NULL;
|
||||
hide_patterns = NULL;
|
||||
print_scontext = false;
|
||||
|
||||
/* FIXME: put this in a function. */
|
||||
{
|
||||
@@ -1514,7 +1513,7 @@ decode_switches (int argc, char **argv)
|
||||
}
|
||||
|
||||
while ((c = getopt_long (argc, argv,
|
||||
"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1",
|
||||
"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1",
|
||||
long_options, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -1813,6 +1812,10 @@ decode_switches (int argc, char **argv)
|
||||
file_output_block_size = output_block_size = 1;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
print_scontext = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
@@ -2516,18 +2519,22 @@ clear_files (void)
|
||||
struct fileinfo *f = sorted_file[i];
|
||||
free (f->name);
|
||||
free (f->linkname);
|
||||
if (f->scontext)
|
||||
{
|
||||
freecon (f->scontext);
|
||||
f->scontext = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cwd_n_used = 0;
|
||||
#if USE_ACL
|
||||
any_has_acl = false;
|
||||
#endif
|
||||
inode_number_width = 0;
|
||||
block_size_width = 0;
|
||||
nlink_width = 0;
|
||||
owner_width = 0;
|
||||
group_width = 0;
|
||||
author_width = 0;
|
||||
scontext_width = 0;
|
||||
major_device_number_width = 0;
|
||||
minor_device_number_width = 0;
|
||||
file_size_width = 0;
|
||||
@@ -2589,9 +2596,11 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
)))))
|
||||
|
||||
{
|
||||
/* FIXME-c99: move this decl "down", once ls.c stabilizes. */
|
||||
bool file_has_security_context = false;
|
||||
/* Absolute name of this file. */
|
||||
char *absolute_name;
|
||||
|
||||
bool do_deref;
|
||||
int err;
|
||||
|
||||
if (name[0] == '/' || dirname[0] == 0)
|
||||
@@ -2606,6 +2615,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
{
|
||||
case DEREF_ALWAYS:
|
||||
err = stat (absolute_name, &f->stat);
|
||||
do_deref = true;
|
||||
break;
|
||||
|
||||
case DEREF_COMMAND_LINE_ARGUMENTS:
|
||||
@@ -2614,6 +2624,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
{
|
||||
bool need_lstat;
|
||||
err = stat (absolute_name, &f->stat);
|
||||
do_deref = true;
|
||||
|
||||
if (dereference == DEREF_COMMAND_LINE_ARGUMENTS)
|
||||
break;
|
||||
@@ -2632,9 +2643,26 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
|
||||
default: /* DEREF_NEVER */
|
||||
err = lstat (absolute_name, &f->stat);
|
||||
do_deref = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == 0 && print_scontext)
|
||||
{
|
||||
int attr_len = (do_deref
|
||||
? getfilecon (absolute_name, &f->scontext)
|
||||
: lgetfilecon (absolute_name, &f->scontext));
|
||||
err = (attr_len < 0);
|
||||
file_has_security_context = (err == 0);
|
||||
|
||||
/* When requesting security context information, don't make
|
||||
ls fail just because the file (even a command line argument)
|
||||
isn't on the right type of file system. I.e., a getfilecon
|
||||
failure isn't in the same class as a stat failure. */
|
||||
if (err && (errno == ENOTSUP || errno == ENODATA))
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
/* Failure to stat a command line argument leads to
|
||||
@@ -2653,16 +2681,14 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
|
||||
f->stat_ok = true;
|
||||
|
||||
#if USE_ACL
|
||||
if (format == long_format)
|
||||
{
|
||||
int n = file_has_acl (absolute_name, &f->stat);
|
||||
f->have_acl = (0 < n);
|
||||
f->have_acl = (0 < n || file_has_security_context);
|
||||
any_has_acl |= f->have_acl;
|
||||
if (n < 0)
|
||||
error (0, errno, "%s", quotearg_colon (absolute_name));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (S_ISLNK (f->stat.st_mode)
|
||||
&& (format == long_format || check_symlink_color))
|
||||
@@ -2738,6 +2764,13 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
author_width = len;
|
||||
}
|
||||
|
||||
if (print_scontext)
|
||||
{
|
||||
int len = f->scontext ? strlen (f->scontext) : 0;
|
||||
if (scontext_width < len)
|
||||
scontext_width = len;
|
||||
}
|
||||
|
||||
{
|
||||
char buf[INT_BUFSIZE_BOUND (uintmax_t)];
|
||||
int len = strlen (umaxtostr (f->stat.st_nlink, buf));
|
||||
@@ -2798,7 +2831,7 @@ is_directory (const struct fileinfo *f)
|
||||
static void
|
||||
get_link_name (char const *filename, struct fileinfo *f, bool command_line_arg)
|
||||
{
|
||||
f->linkname = xreadlink (filename, f->stat.st_size);
|
||||
f->linkname = xreadlink_with_size (filename, f->stat.st_size);
|
||||
if (f->linkname == NULL)
|
||||
file_failure (command_line_arg, _("cannot read symbolic link %s"),
|
||||
filename);
|
||||
@@ -3387,7 +3420,7 @@ print_long_format (const struct fileinfo *f)
|
||||
struct tm *when_local;
|
||||
|
||||
/* Compute the mode string, except remove the trailing space if no
|
||||
files in this directory have ACLs. */
|
||||
file in this directory has an ACL or SELinux security context. */
|
||||
if (f->stat_ok)
|
||||
filemodestring (&f->stat, modebuf);
|
||||
else
|
||||
@@ -3398,7 +3431,7 @@ print_long_format (const struct fileinfo *f)
|
||||
}
|
||||
if (! any_has_acl)
|
||||
modebuf[10] = '\0';
|
||||
else if (FILE_HAS_ACL (f))
|
||||
else if (f->have_acl)
|
||||
modebuf[10] = '+';
|
||||
|
||||
switch (time_type)
|
||||
@@ -3463,7 +3496,7 @@ print_long_format (const struct fileinfo *f)
|
||||
|
||||
DIRED_INDENT ();
|
||||
|
||||
if (print_owner | print_group | print_author)
|
||||
if (print_owner | print_group | print_author | print_scontext)
|
||||
{
|
||||
DIRED_FPUTS (buf, stdout, p - buf);
|
||||
|
||||
@@ -3476,6 +3509,10 @@ print_long_format (const struct fileinfo *f)
|
||||
if (print_author)
|
||||
format_user (f->stat.st_author, author_width, f->stat_ok);
|
||||
|
||||
if (print_scontext)
|
||||
format_user_or_group ((f->scontext ? f->scontext : "?"),
|
||||
0, scontext_width);
|
||||
|
||||
p = buf;
|
||||
}
|
||||
|
||||
@@ -3812,6 +3849,10 @@ print_file_name_and_frills (const struct fileinfo *f)
|
||||
human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts,
|
||||
ST_NBLOCKSIZE, output_block_size));
|
||||
|
||||
if (print_scontext)
|
||||
printf ("%*s ", format == with_commas ? 0 : scontext_width,
|
||||
(f->scontext ? f->scontext : "?"));
|
||||
|
||||
print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
|
||||
f->stat_ok, f->filetype, NULL);
|
||||
|
||||
@@ -3975,6 +4016,9 @@ length_of_file_name_and_frills (const struct fileinfo *f)
|
||||
output_block_size))
|
||||
: block_size_width);
|
||||
|
||||
if (print_scontext)
|
||||
len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width);
|
||||
|
||||
quote_name (NULL, f->name, filename_quoting_options, &name_width);
|
||||
len += name_width;
|
||||
|
||||
@@ -4403,6 +4447,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-w, --width=COLS assume screen width instead of current value\n\
|
||||
-x list entries by lines instead of by columns\n\
|
||||
-X sort alphabetically by entry extension\n\
|
||||
-Z, --context print any SELinux security context of each file\n\
|
||||
-1 list one file per line\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
|
||||
18
src/mkdir.c
18
src/mkdir.c
@@ -1,5 +1,5 @@
|
||||
/* mkdir -- make directories
|
||||
Copyright (C) 90, 1995-2002, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 90, 1995-2002, 2004-2007 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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -40,6 +41,7 @@ char *program_name;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{"parents", no_argument, NULL, 'p'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
@@ -68,6 +70,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\
|
||||
-p, --parents no error if existing, make parent directories as needed\n\
|
||||
-v, --verbose print a message for each created directory\n\
|
||||
-Z, --context=CTX set the SELinux security context of each created\n\
|
||||
directory to CTX\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
@@ -140,7 +144,9 @@ main (int argc, char **argv)
|
||||
{
|
||||
const char *specified_mode = NULL;
|
||||
int optc;
|
||||
security_context_t scontext = NULL;
|
||||
struct mkdir_options options;
|
||||
|
||||
options.make_ancestor_function = NULL;
|
||||
options.mode = S_IRWXUGO;
|
||||
options.mode_bits = 0;
|
||||
@@ -154,7 +160,7 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
@@ -167,6 +173,9 @@ main (int argc, char **argv)
|
||||
case 'v': /* --verbose */
|
||||
options.created_directory_format = _("created directory %s");
|
||||
break;
|
||||
case 'Z':
|
||||
scontext = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -180,6 +189,11 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (optarg));
|
||||
|
||||
if (options.make_ancestor_function || specified_mode)
|
||||
{
|
||||
mode_t umask_value = umask (0);
|
||||
|
||||
18
src/mkfifo.c
18
src/mkfifo.c
@@ -1,5 +1,5 @@
|
||||
/* mkfifo -- make fifo's (named pipes)
|
||||
Copyright (C) 90, 91, 1995-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 90, 91, 1995-2007 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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -37,6 +38,7 @@ char *program_name;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -55,6 +57,9 @@ usage (int status)
|
||||
fputs (_("\
|
||||
Create named pipes (FIFOs) with the given NAMEs.\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-Z, --context=CTX set the SELinux security context of each NAME to CTX\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
@@ -76,6 +81,7 @@ main (int argc, char **argv)
|
||||
char const *specified_mode = NULL;
|
||||
int exit_status = EXIT_SUCCESS;
|
||||
int optc;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
@@ -85,13 +91,16 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'm':
|
||||
specified_mode = optarg;
|
||||
break;
|
||||
case 'Z':
|
||||
scontext = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -105,6 +114,11 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (optarg));
|
||||
|
||||
newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (specified_mode)
|
||||
{
|
||||
|
||||
18
src/mknod.c
18
src/mknod.c
@@ -1,5 +1,5 @@
|
||||
/* mknod -- make special files
|
||||
Copyright (C) 90, 91, 1995-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 90, 91, 1995-2007 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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -38,6 +39,7 @@ char *program_name;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -57,6 +59,9 @@ usage (int status)
|
||||
fputs (_("\
|
||||
Create the special file NAME of the given TYPE.\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs(_("\
|
||||
-Z, --context=CTX set the SELinux security context of NAME to CTX\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
@@ -92,6 +97,7 @@ main (int argc, char **argv)
|
||||
int optc;
|
||||
int expected_operands;
|
||||
mode_t node_type;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
@@ -101,13 +107,16 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'm':
|
||||
specified_mode = optarg;
|
||||
break;
|
||||
case 'Z':
|
||||
scontext = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -157,6 +166,11 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (optarg));
|
||||
|
||||
/* Only check the first character, to allow mnemonic usage like
|
||||
`mknod /dev/rst0 character 18 0'. */
|
||||
|
||||
|
||||
5
src/mv.c
5
src/mv.c
@@ -22,6 +22,7 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "argmatch.h"
|
||||
@@ -113,6 +114,8 @@ rm_option_init (struct rm_options *x)
|
||||
static void
|
||||
cp_option_init (struct cp_options *x)
|
||||
{
|
||||
bool selinux_enabled = (0 < is_selinux_enabled ());
|
||||
|
||||
x->copy_as_regular = false; /* FIXME: maybe make this an option */
|
||||
x->dereference = DEREF_NEVER;
|
||||
x->unlink_dest_before_opening = false;
|
||||
@@ -126,7 +129,9 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_links = true;
|
||||
x->preserve_mode = true;
|
||||
x->preserve_timestamps = true;
|
||||
x->preserve_security_context = selinux_enabled;
|
||||
x->require_preserve = false; /* FIXME: maybe make this an option */
|
||||
x->require_preserve_context = false;
|
||||
x->recursive = true;
|
||||
x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */
|
||||
x->symbolic_link = false;
|
||||
|
||||
3
src/pr.c
3
src/pr.c
@@ -1,5 +1,5 @@
|
||||
/* pr -- convert text files for printing.
|
||||
Copyright (C) 88, 91, 1995-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 88, 91, 1995-2007 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
|
||||
@@ -1265,7 +1265,6 @@ init_parameters (int number_of_files)
|
||||
col_sep_string = column_separator;
|
||||
|
||||
truncate_lines = true;
|
||||
untabify_input = true;
|
||||
tabify_output = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* readlink -- display value of a symbolic link.
|
||||
Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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
|
||||
@@ -159,7 +159,7 @@ main (int argc, char **argv)
|
||||
|
||||
value = (can_mode != -1
|
||||
? canonicalize_filename_mode (fname, can_mode)
|
||||
: xreadlink (fname, 1024));
|
||||
: xreadlink (fname));
|
||||
if (value)
|
||||
{
|
||||
printf ("%s%s", value, (no_newline ? "" : "\n"));
|
||||
|
||||
122
src/remove.c
122
src/remove.c
@@ -704,20 +704,21 @@ is_empty_dir (int fd_cwd, char const *dir)
|
||||
return saved_errno == 0 ? true : false;
|
||||
}
|
||||
|
||||
/* Return true if FILE is determined to be an unwritable non-symlink.
|
||||
Otherwise, return false (including when lstat'ing it fails).
|
||||
/* Return -1 if FILE is an unwritable non-symlink,
|
||||
0 if it is writable or some other type of file,
|
||||
a positive error number if there is some problem in determining the answer.
|
||||
Set *BUF to the file status.
|
||||
This is to avoid calling euidaccess when FILE is a symlink. */
|
||||
static bool
|
||||
static int
|
||||
write_protected_non_symlink (int fd_cwd,
|
||||
char const *file,
|
||||
Dirstack_state const *ds,
|
||||
struct stat *buf)
|
||||
{
|
||||
if (cache_fstatat (fd_cwd, file, buf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
return false;
|
||||
return errno;
|
||||
if (S_ISLNK (buf->st_mode))
|
||||
return false;
|
||||
return 0;
|
||||
/* Here, we know FILE is not a symbolic link. */
|
||||
|
||||
/* In order to be reentrant -- i.e., to avoid changing the working
|
||||
@@ -771,9 +772,16 @@ write_protected_non_symlink (int fd_cwd,
|
||||
size_t file_name_len
|
||||
= obstack_object_size (&ds->dir_stack) + strlen (file);
|
||||
|
||||
return (file_name_len < MIN (PATH_MAX, 8192)
|
||||
? euidaccess (full_filename (file), W_OK) != 0 && errno == EACCES
|
||||
: euidaccess_stat (buf, W_OK) != 0);
|
||||
if (MIN (PATH_MAX, 8192) <= file_name_len)
|
||||
return - euidaccess_stat (buf, W_OK);
|
||||
if (euidaccess (full_filename (file), W_OK) == 0)
|
||||
return 0;
|
||||
if (errno == EACCES)
|
||||
return -1;
|
||||
|
||||
/* Perhaps some other process has removed the file, or perhaps this
|
||||
is a buggy NFS client. */
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,75 +802,73 @@ prompt (int fd_cwd, Dirstack_state const *ds, char const *filename,
|
||||
struct rm_options const *x, enum Prompt_action mode,
|
||||
Ternary *is_empty)
|
||||
{
|
||||
bool write_protected = false;
|
||||
int write_protected = 0;
|
||||
|
||||
*is_empty = T_UNKNOWN;
|
||||
|
||||
if (x->interactive == RMI_NEVER)
|
||||
return RM_OK;
|
||||
|
||||
if (((!x->ignore_missing_files & ((x->interactive == RMI_ALWAYS)
|
||||
| x->stdin_tty))
|
||||
&& (write_protected = write_protected_non_symlink (fd_cwd, filename,
|
||||
ds, sbuf)))
|
||||
|| x->interactive == RMI_ALWAYS)
|
||||
if (!x->ignore_missing_files
|
||||
& ((x->interactive == RMI_ALWAYS) | x->stdin_tty))
|
||||
write_protected = write_protected_non_symlink (fd_cwd, filename, ds, sbuf);
|
||||
|
||||
if (write_protected || x->interactive == RMI_ALWAYS)
|
||||
{
|
||||
if (cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
if (write_protected <= 0
|
||||
&& cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
{
|
||||
/* This happens, e.g., with `rm '''. */
|
||||
error (0, errno, _("cannot remove %s"),
|
||||
quote (full_filename (filename)));
|
||||
return RM_ERROR;
|
||||
write_protected = errno;
|
||||
}
|
||||
|
||||
if (S_ISDIR (sbuf->st_mode) && !x->recursive)
|
||||
if (write_protected <= 0)
|
||||
{
|
||||
error (0, EISDIR, _("cannot remove %s"),
|
||||
quote (full_filename (filename)));
|
||||
return RM_ERROR;
|
||||
}
|
||||
|
||||
/* Using permissions doesn't make sense for symlinks. */
|
||||
if (S_ISLNK (sbuf->st_mode))
|
||||
{
|
||||
if (x->interactive != RMI_ALWAYS)
|
||||
/* Using permissions doesn't make sense for symlinks. */
|
||||
if (S_ISLNK (sbuf->st_mode) && x->interactive != RMI_ALWAYS)
|
||||
return RM_OK;
|
||||
write_protected = false;
|
||||
|
||||
if (S_ISDIR (sbuf->st_mode) && !x->recursive)
|
||||
write_protected = EISDIR;
|
||||
}
|
||||
|
||||
char const *quoted_name = quote (full_filename (filename));
|
||||
|
||||
if (0 < write_protected)
|
||||
{
|
||||
error (0, write_protected, _("cannot remove %s"), quoted_name);
|
||||
return RM_ERROR;
|
||||
}
|
||||
|
||||
/* Issue the prompt. */
|
||||
{
|
||||
char const *quoted_name = quote (full_filename (filename));
|
||||
|
||||
/* FIXME: use a variant of error (instead of fprintf) that doesn't
|
||||
append a newline. Then we won't have to declare program_name in
|
||||
this file. */
|
||||
if (S_ISDIR (sbuf->st_mode)
|
||||
&& x->recursive
|
||||
&& mode == PA_DESCEND_INTO_DIR
|
||||
&& ((*is_empty = (is_empty_dir (fd_cwd, filename) ? T_YES : T_NO))
|
||||
== T_NO))
|
||||
/* FIXME: use a variant of error (instead of fprintf) that doesn't
|
||||
append a newline. Then we won't have to declare program_name in
|
||||
this file. */
|
||||
if (S_ISDIR (sbuf->st_mode)
|
||||
&& x->recursive
|
||||
&& mode == PA_DESCEND_INTO_DIR
|
||||
&& ((*is_empty = (is_empty_dir (fd_cwd, filename) ? T_YES : T_NO))
|
||||
== T_NO))
|
||||
fprintf (stderr,
|
||||
(write_protected
|
||||
? _("%s: descend into write-protected directory %s? ")
|
||||
: _("%s: descend into directory %s? ")),
|
||||
program_name, quoted_name);
|
||||
else
|
||||
{
|
||||
/* TRANSLATORS: You may find it more convenient to translate
|
||||
the equivalent of _("%s: remove %s (write-protected) %s? ").
|
||||
It should avoid grammatical problems with the output
|
||||
of file_type. */
|
||||
fprintf (stderr,
|
||||
(write_protected
|
||||
? _("%s: descend into write-protected directory %s? ")
|
||||
: _("%s: descend into directory %s? ")),
|
||||
program_name, quoted_name);
|
||||
else
|
||||
{
|
||||
/* TRANSLATORS: You may find it more convenient to translate
|
||||
the equivalent of _("%s: remove %s (write-protected) %s? ").
|
||||
It should avoid grammatical problems with the output
|
||||
of file_type. */
|
||||
fprintf (stderr,
|
||||
(write_protected
|
||||
? _("%s: remove write-protected %s %s? ")
|
||||
: _("%s: remove %s %s? ")),
|
||||
program_name, file_type (sbuf), quoted_name);
|
||||
}
|
||||
? _("%s: remove write-protected %s %s? ")
|
||||
: _("%s: remove %s %s? ")),
|
||||
program_name, file_type (sbuf), quoted_name);
|
||||
}
|
||||
|
||||
if (!yesno ())
|
||||
return RM_USER_DECLINED;
|
||||
}
|
||||
if (!yesno ())
|
||||
return RM_USER_DECLINED;
|
||||
}
|
||||
return RM_OK;
|
||||
}
|
||||
|
||||
249
src/runcon.c
Normal file
249
src/runcon.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* runcon [ context |
|
||||
* ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] )
|
||||
* command [arg1 [arg2 ...] ]
|
||||
*
|
||||
* attempt to run the specified command with the specified context.
|
||||
*
|
||||
* -r role : use the current context with the specified role
|
||||
* -t type : use the current context with the specified type
|
||||
* -u user : use the current context with the specified user
|
||||
* -l level : use the current context with the specified level range
|
||||
* -c : compute process transition context before modifying
|
||||
*
|
||||
* Contexts are interpreted as follows:
|
||||
*
|
||||
* Number of MLS
|
||||
* components system?
|
||||
*
|
||||
* 1 - type
|
||||
* 2 - role:type
|
||||
* 3 Y role:type:range
|
||||
* 3 N user:role:type
|
||||
* 4 Y user:role:type:range
|
||||
* 4 N error
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/context.h>
|
||||
#ifdef HAVE_SELINUX_FLASK_H
|
||||
# include <selinux/flask.h>
|
||||
#else
|
||||
# define SECCLASS_PROCESS 0
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "runcon"
|
||||
|
||||
#define AUTHORS "Russell Coker"
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"role", required_argument, NULL, 'r'},
|
||||
{"type", required_argument, NULL, 't'},
|
||||
{"user", required_argument, NULL, 'u'},
|
||||
{"range", required_argument, NULL, 'l'},
|
||||
{"compute", no_argument, NULL, 'c'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* The name the program was run with. */
|
||||
char *program_name;
|
||||
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s CONTEXT COMMAND [args]\n\
|
||||
or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
|
||||
"), program_name, program_name);
|
||||
fputs (_("\
|
||||
Run a program in a different security context.\n\
|
||||
With neither CONTEXT nor COMMAND, print the current security context.\n\
|
||||
\n\
|
||||
CONTEXT Complete security context\n\
|
||||
-c, --compute compute process transition context before modifying\n\
|
||||
-t, --type=TYPE type (for same role as parent)\n\
|
||||
-u, --user=USER user identity\n\
|
||||
-r, --role=ROLE role\n\
|
||||
-l, --range=RANGE levelrange\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv, char **envp)
|
||||
{
|
||||
char *role = NULL;
|
||||
char *range = NULL;
|
||||
char *user = NULL;
|
||||
char *type = NULL;
|
||||
char *context = NULL;
|
||||
security_context_t cur_context = NULL;
|
||||
security_context_t file_context = NULL;
|
||||
security_context_t new_context = NULL;
|
||||
bool compute_trans = false;
|
||||
|
||||
context_t con;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int option_index = 0;
|
||||
int c = getopt_long (argc, argv, "+r:t:u:l:c", long_options,
|
||||
&option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
if (role)
|
||||
error (EXIT_FAILURE, 0, _("multiple roles"));
|
||||
role = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (type)
|
||||
error (EXIT_FAILURE, 0, _("multiple types"));
|
||||
type = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
if (user)
|
||||
error (EXIT_FAILURE, 0, _("multiple users"));
|
||||
user = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
if (range)
|
||||
error (EXIT_FAILURE, 0, _("multiple levelranges"));
|
||||
range = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
compute_trans = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind == 0)
|
||||
{
|
||||
if (getcon (&cur_context) < 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to get current context"));
|
||||
fputs (cur_context, stdout);
|
||||
fputc ('\n', stdout);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!(user || role || type || range || compute_trans))
|
||||
{
|
||||
if (optind >= argc)
|
||||
{
|
||||
error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
|
||||
usage (1);
|
||||
}
|
||||
context = argv[optind++];
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
{
|
||||
error (0, 0, _("no command specified"));
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (is_selinux_enabled () != 1)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("runcon may be used only on a SELinux kernel"));
|
||||
|
||||
if (context)
|
||||
{
|
||||
con = context_new (context);
|
||||
if (!con)
|
||||
error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
|
||||
quotearg_colon (context));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getcon (&cur_context) < 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to get current context"));
|
||||
|
||||
/* We will generate context based on process transition */
|
||||
if (compute_trans)
|
||||
{
|
||||
/* Get context of file to be executed */
|
||||
if (getfilecon (argv[optind], &file_context) == -1)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to get security context of %s"),
|
||||
quote (argv[optind]));
|
||||
/* compute result of process transition */
|
||||
if (security_compute_create (cur_context, file_context,
|
||||
SECCLASS_PROCESS, &new_context) != 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to compute a new context"));
|
||||
/* free contexts */
|
||||
freecon (file_context);
|
||||
freecon (cur_context);
|
||||
|
||||
/* set cur_context equal to new_context */
|
||||
cur_context = new_context;
|
||||
}
|
||||
|
||||
con = context_new (cur_context);
|
||||
if (!con)
|
||||
error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
|
||||
quotearg_colon (cur_context));
|
||||
if (user && context_user_set (con, user))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new user %s"), user);
|
||||
if (type && context_type_set (con, type))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new type %s"), type);
|
||||
if (range && context_range_set (con, range))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new range %s"), range);
|
||||
if (role && context_role_set (con, role))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new role %s"), role);
|
||||
}
|
||||
|
||||
if (security_check_context (context_str (con)) < 0)
|
||||
error (EXIT_FAILURE, errno, _("invalid context: %s"),
|
||||
quotearg_colon (context_str (con)));
|
||||
|
||||
if (setexeccon (context_str (con)) != 0)
|
||||
error (EXIT_FAILURE, errno, _("unable to set security context %s"),
|
||||
quote (context_str (con)));
|
||||
if (cur_context != NULL)
|
||||
freecon (cur_context);
|
||||
|
||||
execvp (argv[optind], argv + optind);
|
||||
|
||||
{
|
||||
int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
|
||||
error (0, errno, "%s", argv[optind]);
|
||||
exit (exit_status);
|
||||
}
|
||||
}
|
||||
51
src/stat.c
51
src/stat.c
@@ -1,5 +1,5 @@
|
||||
/* stat.c -- display file or file system status
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation.
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 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
|
||||
@@ -54,6 +54,7 @@
|
||||
#elif HAVE_OS_H /* BeOS */
|
||||
# include <fs_info.h>
|
||||
#endif
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
|
||||
@@ -158,6 +159,7 @@ enum
|
||||
};
|
||||
|
||||
static struct option const long_options[] = {
|
||||
{"context", no_argument, 0, 'Z'},
|
||||
{"dereference", no_argument, NULL, 'L'},
|
||||
{"file-system", no_argument, NULL, 'f'},
|
||||
{"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */
|
||||
@@ -171,6 +173,9 @@ static struct option const long_options[] = {
|
||||
|
||||
char *program_name;
|
||||
|
||||
/* Whether to follow symbolic links; True for --dereference (-L). */
|
||||
static bool follow_links;
|
||||
|
||||
/* Whether to interpret backslash-escape sequences.
|
||||
True for --printf=FMT, not for --format=FMT (-c). */
|
||||
static bool interpret_backslash_escapes;
|
||||
@@ -394,6 +399,26 @@ out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
|
||||
printf (pformat, arg);
|
||||
}
|
||||
|
||||
/* Very specialized function (modifies FORMAT), just so as to avoid
|
||||
duplicating this code between both print_statfs and print_stat. */
|
||||
static void
|
||||
out_file_context (char const *filename, char *pformat, size_t prefix_len)
|
||||
{
|
||||
char *scontext;
|
||||
if ((follow_links
|
||||
? getfilecon (filename, &scontext)
|
||||
: lgetfilecon (filename, &scontext)) < 0)
|
||||
{
|
||||
error (0, errno, _("failed to get security context of %s"),
|
||||
quote (filename));
|
||||
scontext = NULL;
|
||||
}
|
||||
strcpy (pformat + prefix_len, "s");
|
||||
printf (pformat, (scontext ? scontext : "?"));
|
||||
if (scontext)
|
||||
freecon (scontext);
|
||||
}
|
||||
|
||||
/* print statfs info */
|
||||
static void
|
||||
print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
|
||||
@@ -472,7 +497,9 @@ print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
|
||||
case 'd':
|
||||
out_int (pformat, prefix_len, statfsbuf->f_ffree);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
out_file_context (filename, pformat, prefix_len);
|
||||
break;
|
||||
default:
|
||||
fputc ('?', stdout);
|
||||
break;
|
||||
@@ -497,7 +524,7 @@ print_stat (char *pformat, size_t prefix_len, char m,
|
||||
out_string (pformat, prefix_len, quote (filename));
|
||||
if (S_ISLNK (statbuf->st_mode))
|
||||
{
|
||||
char *linkname = xreadlink (filename, statbuf->st_size);
|
||||
char *linkname = xreadlink_with_size (filename, statbuf->st_size);
|
||||
if (linkname == NULL)
|
||||
{
|
||||
error (0, errno, _("cannot read symbolic link %s"),
|
||||
@@ -595,6 +622,9 @@ print_stat (char *pformat, size_t prefix_len, char m,
|
||||
else
|
||||
out_uint (pformat, prefix_len, statbuf->st_ctime);
|
||||
break;
|
||||
case 'C':
|
||||
out_file_context (filename, pformat, prefix_len);
|
||||
break;
|
||||
default:
|
||||
fputc ('?', stdout);
|
||||
break;
|
||||
@@ -774,8 +804,7 @@ do_statfs (char const *filename, bool terse, char const *format)
|
||||
|
||||
/* stat the file and print what we find */
|
||||
static bool
|
||||
do_stat (char const *filename, bool follow_links, bool terse,
|
||||
char const *format)
|
||||
do_stat (char const *filename, bool terse, char const *format)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
@@ -853,6 +882,7 @@ The valid format sequences for files (without --file-system):\n\
|
||||
%A Access rights in human readable form\n\
|
||||
%b Number of blocks allocated (see %B)\n\
|
||||
%B The size in bytes of each block reported by %b\n\
|
||||
%C SELinux security context string\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
%d Device number in decimal\n\
|
||||
@@ -892,6 +922,7 @@ Valid format sequences for file systems:\n\
|
||||
%c Total file nodes in file system\n\
|
||||
%d Free file nodes in file system\n\
|
||||
%f Free blocks in file system\n\
|
||||
%C SELinux security context string\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
%i File System ID in hex\n\
|
||||
@@ -913,7 +944,6 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
bool follow_links = false;
|
||||
bool fs = false;
|
||||
bool terse = false;
|
||||
char *format = NULL;
|
||||
@@ -927,7 +957,7 @@ main (int argc, char *argv[])
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
|
||||
while ((c = getopt_long (argc, argv, "c:fLtZ", long_options, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -955,6 +985,11 @@ main (int argc, char *argv[])
|
||||
terse = true;
|
||||
break;
|
||||
|
||||
case 'Z': /* FIXME: remove in 2008, warn in 2007 */
|
||||
/* Ignored, for compatibility with distributions
|
||||
that implemented this before upstream. */
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
@@ -973,7 +1008,7 @@ main (int argc, char *argv[])
|
||||
for (i = optind; i < argc; i++)
|
||||
ok &= (fs
|
||||
? do_statfs (argv[i], terse, format)
|
||||
: do_stat (argv[i], follow_links, terse, format));
|
||||
: do_stat (argv[i], terse, format));
|
||||
|
||||
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -399,6 +399,8 @@ enum
|
||||
"help", no_argument, NULL, GETOPT_HELP_CHAR
|
||||
#define GETOPT_VERSION_OPTION_DECL \
|
||||
"version", no_argument, NULL, GETOPT_VERSION_CHAR
|
||||
#define GETOPT_SELINUX_CONTEXT_OPTION_DECL \
|
||||
"context", required_argument, NULL, 'Z'
|
||||
|
||||
#define case_GETOPT_HELP_CHAR \
|
||||
case GETOPT_HELP_CHAR: \
|
||||
|
||||
@@ -18,7 +18,7 @@ EXTRA_DIST = \
|
||||
$(TESTS) Coreutils.pm Makefile.am.in README acl envvar-check \
|
||||
expensive group-names input-tty lang-default mk-script \
|
||||
other-fs-tmpdir priv-check \
|
||||
rwx-to-mode sample-test setgid-check sparse-file \
|
||||
rwx-to-mode sample-test selinux setgid-check sparse-file \
|
||||
umask-check very-expensive
|
||||
|
||||
## N O T E :: Please do not add new tests/ directories.
|
||||
@@ -30,7 +30,7 @@ SUBDIRS = \
|
||||
tsort unexpand uniq wc
|
||||
## N O T E :: Please do not add new directories.
|
||||
|
||||
all_t = t1 t2 t3 t4 t5 t6 t7
|
||||
all_t = t1 t2 t3 t4 t5 t6 t7 t8 t9
|
||||
.PHONY: check-root $(all_t)
|
||||
check-root: $(all_t)
|
||||
|
||||
@@ -48,6 +48,10 @@ t6:
|
||||
cd rm && $(MAKE) check TESTS=one-file-system
|
||||
t7:
|
||||
cd ls && $(MAKE) check TESTS=nameless-uid
|
||||
t8:
|
||||
cd misc && $(MAKE) check TESTS=chcon
|
||||
t9:
|
||||
cd cp && $(MAKE) check TESTS=cp-a-selinux
|
||||
|
||||
check-recursive: root-hint
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/bin/sh
|
||||
# make sure chgrp is reasonable
|
||||
|
||||
# Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 2000-2007 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
|
||||
@@ -79,7 +78,11 @@ test `stat --printf=%g f` = $g1 || fail=1
|
||||
# This should not change the group of f.
|
||||
chgrp -h $g2 symlink
|
||||
test `stat --printf=%g f` = $g1 || fail=1
|
||||
test `stat --printf=%g symlink` = $g2 || fail=1
|
||||
|
||||
# Don't fail if chgrp failed to set the group of a symlink.
|
||||
# Some systems don't support that.
|
||||
test `stat --printf=%g symlink` = $g2 ||
|
||||
echo 'info: failed to set group of symlink' 1>&2
|
||||
|
||||
chown --from=:$g1 :$g2 f; test `stat --printf=%g f` = $g2 || fail=1
|
||||
|
||||
@@ -110,15 +113,19 @@ sleep 1
|
||||
chgrp $g1 f
|
||||
|
||||
# The following no-change chgrp command is supposed to update f's ctime,
|
||||
# but on OpenBSD, it appears to be a no-op for some file system types
|
||||
# (at least NFS) so g's ctime is more recent. This is not a big deal;
|
||||
# but on OpenBSD and Darwin 7.9.0 and 8.8.0 (aka MacOS X 10.3.9 and 10.4),
|
||||
# it appears to be a no-op for some file system types (at least NFS) so g's
|
||||
# ctime is more recent. This is not a big deal;
|
||||
# this test works fine when the files are on a local file system (/tmp).
|
||||
chgrp '' f
|
||||
test "`ls -C -c -t f g`" = 'f g' || \
|
||||
{
|
||||
case $host_triplet in
|
||||
*openbsd*) echo ignoring known OpenBSD-specific chgrp failure 1>&2 ;;
|
||||
*) echo no-change chgrp failed to update ctime 1>&2; fail=1 ;;
|
||||
*openbsd*) echo ignoring known OpenBSD-specific chgrp failure 1>&2 ;;
|
||||
*darwin7.9.*|*darwin8.8.*)
|
||||
echo ignoring known MacOS X-specific chgrp failure 1>&2 ;;
|
||||
*) echo $host_triplet: no-change chgrp failed to update ctime 1>&2;
|
||||
fail=1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ for src in u g o; do
|
||||
for dest in u g o; do
|
||||
test $dest = $src && continue
|
||||
chmod a=,$src=rwx,$dest=$src,$src= f || fail=1
|
||||
set _ `ls -l f`; shift; actual_perms=$1
|
||||
actual_perms=`ls -l f|cut -b-10`
|
||||
expected_perms=`eval 'echo \$expected_'$dest`
|
||||
test "$actual_perms" = "$expected_perms" || fail=1
|
||||
done
|
||||
@@ -59,7 +59,7 @@ done
|
||||
|
||||
umask 027
|
||||
chmod a=,u=rwx,=u f || fail=1
|
||||
set _ `ls -l f`; shift; actual_perms=$1
|
||||
actual_perms=`ls -l f|cut -b-10`
|
||||
test "$actual_perms" = "-rwxr-x---" || fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
TESTS = \
|
||||
cp-a-selinux \
|
||||
file-perm-race parent-perm-race \
|
||||
backup-dir \
|
||||
src-base-dot \
|
||||
|
||||
94
tests/cp/cp-a-selinux
Executable file
94
tests/cp/cp-a-selinux
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
# Ensure that cp -a and cp --preserve=context work properly.
|
||||
# In particular, test on a writable NFS partition.
|
||||
|
||||
# Copyright (C) 2007 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
cp --version
|
||||
fi
|
||||
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
. $srcdir/../selinux
|
||||
PRIV_CHECK_ARG=require-root . $srcdir/../priv-check
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd "$pwd"; umount $tmp/mnt; chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
# Create a file system, then mount it with the context=... option.
|
||||
dd if=/dev/zero of=blob bs=8192 count=200 > /dev/null 2>&1 \
|
||||
|| framework_failure=1
|
||||
mkdir mnt || framework_failure=1
|
||||
mkfs -t ext2 -F blob > /dev/null 2>&1 || framework_failure=1
|
||||
mount -oloop,context=system_u:object_r:removable_t blob mnt \
|
||||
|| framework_failure=1
|
||||
cd mnt || framework_failure=1
|
||||
|
||||
echo > f || framework_failure=1
|
||||
echo > g || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# /bin/cp from coreutils-6.7-3.fc7 would fail this test by letting cp
|
||||
# succeed (giving no diagnostics), yet leaving the destination file empty.
|
||||
cp -a f g 2>err || fail=1
|
||||
test -s g || fail=1 # The destination file must not be empty.
|
||||
test -s err && fail=1 # There must be no stderr output.
|
||||
|
||||
rm -f g err
|
||||
echo > g
|
||||
|
||||
# =====================================================
|
||||
# Here, we expect cp to fail, because it cannot set the SELinux
|
||||
# security context through NFS or a mount with fixed context.
|
||||
cp --preserve=context f g 2> out && fail=1
|
||||
|
||||
# Here, we *do* expect the destination to be empty.
|
||||
test -s g && fail=1
|
||||
|
||||
# An alternative to the current approach would be to run in a confined
|
||||
# domain (maybe creating/loading it) that lacks the required permissions
|
||||
# to the file type.
|
||||
# Note: this test could also be run by a regular (non-root) user in an
|
||||
# NFS mounted directory. When doing that, I get this diagnostic:
|
||||
# cp: failed to set the security context of `g' to `system_u:object_r:nfs_t': \
|
||||
# Operation not supported
|
||||
sed "s/ .g' to .*//" out > k
|
||||
mv k out
|
||||
|
||||
cat <<\EOF > exp || fail=1
|
||||
cp: failed to set the security context of
|
||||
EOF
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
@@ -75,8 +75,8 @@ test -d d/f && fail=1
|
||||
# Check that re_protect works.
|
||||
chmod go=w d/a
|
||||
cp -a --parents d/a/b/c e || fail=1
|
||||
p=`ls -ld e/d|sed 's/ .*//'`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a|sed 's/ .*//'`; case $p in drwx-w--w-);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a/b/c|sed 's/ .*//'`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
p=`ls -ld e/d|cut -b-10`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a|cut -b-10`; case $p in drwx-w--w-);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a/b/c|cut -b-10`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -52,9 +52,8 @@ cp -pR D DD > /dev/null 2>&1 && fail=1
|
||||
|
||||
# Permissions on DD must be `dr-x------'
|
||||
|
||||
set X `ls -ld DD`
|
||||
shift
|
||||
test "$1" = dr-x------ || fail=1
|
||||
mode=`ls -ld DD|cut -b-10`
|
||||
test "$mode" = dr-x------ || fail=1
|
||||
|
||||
chmod 0 D
|
||||
ln -s D/D symlink
|
||||
|
||||
@@ -98,7 +98,7 @@ rm -rf a b c d
|
||||
touch a; chmod 731 a
|
||||
umask 077
|
||||
cp -a --no-preserve=mode a b
|
||||
set _ `ls -l b`; shift; mode=$1
|
||||
mode=`ls -l b|cut -b-10`
|
||||
test "$mode" = "-rwx------" || fail=1
|
||||
umask 022
|
||||
# --------------------------------------
|
||||
|
||||
@@ -52,6 +52,6 @@ fail=0
|
||||
cp --sparse=always sparse copy || fail=1
|
||||
|
||||
# Ensure that the copy has the same block count as the original.
|
||||
test `stat --printf %b sparse` = `stat --printf %b copy` || fail=1
|
||||
test `stat --printf %b copy` -le `stat --printf %b sparse` || fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Compare actual numbers from du, assuming block size matches mine.
|
||||
|
||||
# Copyright (C) 2003, 2006 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003, 2006-2007 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
|
||||
@@ -80,20 +80,23 @@ EOF
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff -u out exp 2> /dev/null
|
||||
|
||||
rm -f out exp
|
||||
du --block-size=$B -a d | sort -r -k2,2 > out || fail=1
|
||||
echo === >> out
|
||||
du --block-size=$B -S d | sort -r -k2,2 >> out || fail=1
|
||||
# Perform this test only if "." is on a local file system.
|
||||
# Otherwise, it would fail e.g., on an NFS-mounted Solaris ZFS file system.
|
||||
if df --local . >/dev/null 2>&1; then
|
||||
rm -f out exp
|
||||
du --block-size=$B -a d | sort -r -k2,2 > out || fail=1
|
||||
echo === >> out
|
||||
du --block-size=$B -S d | sort -r -k2,2 >> out || fail=1
|
||||
|
||||
t2=`stat --format=%b d/sub/2`
|
||||
ts=`stat --format=%b d/sub`
|
||||
t1=`stat --format=%b d/1`
|
||||
td=`stat --format=%b d`
|
||||
tot=`expr $t1 + $t2 + $ts + $td`
|
||||
d1=`expr $td + $t1`
|
||||
s2=`expr $ts + $t2`
|
||||
t2=`stat --format=%b d/sub/2`
|
||||
ts=`stat --format=%b d/sub`
|
||||
t1=`stat --format=%b d/1`
|
||||
td=`stat --format=%b d`
|
||||
tot=`expr $t1 + $t2 + $ts + $td`
|
||||
d1=`expr $td + $t1`
|
||||
s2=`expr $ts + $t2`
|
||||
|
||||
cat <<EOF | sed 's/ *#.*//' > exp
|
||||
cat <<EOF | sed 's/ *#.*//' > exp
|
||||
$t2 d/sub/2
|
||||
$s2 d/sub
|
||||
$t1 d/1
|
||||
@@ -103,7 +106,8 @@ $s2 d/sub
|
||||
$d1 d # d + d/1; don't count the dir. entry for d/sub
|
||||
EOF
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
fi
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
# Make sure all these programs work properly
|
||||
# when invoked with --help or --version.
|
||||
|
||||
# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 2000-2007 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
|
||||
@@ -72,6 +71,8 @@ for lang in C fr da; do
|
||||
|
||||
# Skip `test'; it doesn't accept --help or --version.
|
||||
test $i = test && continue;
|
||||
test $i = chcon && continue;
|
||||
test $i = runcon && continue;
|
||||
|
||||
# false fails even when invoked with --help or --version.
|
||||
if test $i = false; then
|
||||
@@ -197,7 +198,7 @@ lbracket_args=": ]"
|
||||
|
||||
for i in $all_programs; do
|
||||
# Skip these.
|
||||
case $i in chroot|stty|tty|false) continue;; esac
|
||||
case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac
|
||||
|
||||
rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out
|
||||
echo > $tmp_in
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Basic tests for "install".
|
||||
|
||||
# Copyright (C) 1998, 2000, 2001, 2002, 2004, 2005, 2006 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 1998, 2000-2002, 2004-2007 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
|
||||
@@ -99,9 +98,8 @@ ginstall -s -c -m 555 $dd $dir || fail=1
|
||||
test -f $dd || fail=1
|
||||
|
||||
# Make sure that the destination file has the requested permissions.
|
||||
set X `ls -l $dir/$dd`
|
||||
shift
|
||||
test "$1" = -r-xr-xr-x || fail=1
|
||||
mode=`ls -l $dir/$dd|cut -b-10`
|
||||
test "$mode" = -r-xr-xr-x || fail=1
|
||||
|
||||
# These failed in coreutils CVS from 2004-06-25 to 2004-08-11.
|
||||
ginstall -d . || fail=1
|
||||
@@ -131,8 +129,8 @@ test -d xx/rel && fail=1
|
||||
# Test that we can install from an unreadable directory with an
|
||||
# inaccessible parent. coreutils 5.97 fails this test.
|
||||
mkdir -p sub1/d || fail=1
|
||||
(cd sub1/d && chmod a-rx .. && chmod a-r . &&
|
||||
ginstall -d "$abs/xx/zz" rel/a rel/b 2> /dev/null) || fail=1
|
||||
(cd sub1/d && chmod a-r . && chmod a-rx .. &&
|
||||
ginstall -d "$abs/xx/zz" rel/a rel/b) || fail=1
|
||||
chmod 755 sub1 sub1/d || fail=1
|
||||
test -d xx/zz || fail=1
|
||||
test -d sub1/d/rel/a || fail=1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Make miscellaneous coreutils tests. -*-Makefile-*-
|
||||
|
||||
# Copyright (C) 200-2007 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2007 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
|
||||
@@ -30,6 +30,7 @@ TESTS_ENVIRONMENT = \
|
||||
PATH="$(VG_PATH_PREFIX)`pwd`/../../src$(PATH_SEPARATOR)$$PATH" \
|
||||
CONFIG_HEADER=$(CONFIG_HEADER) \
|
||||
REPLACE_GETCWD=$(REPLACE_GETCWD) \
|
||||
host_os=$(host_os) \
|
||||
PROG=`../../src/basename -- "$$tst"`
|
||||
|
||||
# Do not choose a name that is a shell keyword like 'if', or a
|
||||
@@ -39,7 +40,12 @@ TESTS_ENVIRONMENT = \
|
||||
# will execute the test script rather than the standard utility.
|
||||
|
||||
TESTS = \
|
||||
pr \
|
||||
df-P \
|
||||
pwd-unreadable-parent \
|
||||
chcon \
|
||||
chcon-fail \
|
||||
selinux \
|
||||
cut \
|
||||
wc-files0-from \
|
||||
wc-files0 \
|
||||
@@ -67,6 +73,7 @@ TESTS = \
|
||||
printf \
|
||||
printf-hex \
|
||||
pwd-long \
|
||||
runcon-no-reorder \
|
||||
sha224sum \
|
||||
sha256sum \
|
||||
sha384sum \
|
||||
|
||||
73
tests/misc/chcon
Executable file
73
tests/misc/chcon
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
# exercise chcon
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
chcon --version
|
||||
fi
|
||||
|
||||
. $srcdir/../lang-default
|
||||
PRIV_CHECK_ARG=require-root . $srcdir/../priv-check
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
mkdir -p d/sub/s2 || framework_failure=1
|
||||
touch f g d/sub/1 d/sub/2 || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# Set to a specified context.
|
||||
u1=root
|
||||
r1=object_r
|
||||
t1=tmp_t
|
||||
ctx=$u1:$r1:$t1
|
||||
chcon $ctx f || fail=1
|
||||
stat --printf='f|%C\n' f > out || fail=1
|
||||
|
||||
# Use --reference.
|
||||
chcon --ref=f g || fail=1
|
||||
stat --printf='g|%C\n' g >> out || fail=1
|
||||
|
||||
# Change the individual parts of the context, one by one.
|
||||
u2=user_u
|
||||
r2=object_r
|
||||
t2=file_t
|
||||
l2=SystemLow-SystemHigh
|
||||
for i in --user=$u2 --role=$r2 --type=$t2 --range=$l2; do
|
||||
chcon $i f || fail=1
|
||||
stat --printf="f|$i|"'%C\n' f >> out || fail=1
|
||||
done
|
||||
|
||||
# Same, but change back using the short-named options.
|
||||
for i in -u$u1 -r$r1 -t$t1; do
|
||||
chcon $i f || fail=1
|
||||
stat --printf="f|$i|"'%C\n' f >> out || fail=1
|
||||
done
|
||||
|
||||
cat <<EOF > exp || fail=1
|
||||
f|$ctx
|
||||
g|$ctx
|
||||
f|--user=$u2|$u2:$r1:$t1
|
||||
f|--role=$r2|$u2:$r2:$t1
|
||||
f|--type=$t2|$u2:$r2:$t2
|
||||
f|--range=$l2|$u2:$r2:$t2:$l2
|
||||
f|-uroot|root:object_r:file_t:SystemLow-SystemHigh
|
||||
f|-robject_r|root:object_r:file_t:SystemLow-SystemHigh
|
||||
f|-ttmp_t|root:object_r:tmp_t:SystemLow-SystemHigh
|
||||
EOF
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
41
tests/misc/chcon-fail
Executable file
41
tests/misc/chcon-fail
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
# Ensure that chcon fails when it should.
|
||||
# These tests don't use any actual SE Linux syscalls.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
chcon --version
|
||||
fi
|
||||
|
||||
. $srcdir/../lang-default
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# neither context nor file
|
||||
chcon 2> /dev/null && fail=1
|
||||
|
||||
# No file
|
||||
chcon CON 2> /dev/null && fail=1
|
||||
|
||||
# No file
|
||||
touch f
|
||||
chcon --reference=f 2> /dev/null && fail=1
|
||||
|
||||
# No file
|
||||
chcon -u anyone 2> /dev/null && fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
60
tests/misc/df-P
Executable file
60
tests/misc/df-P
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
# Ensure that df -P is not affected by BLOCK_SIZE settings
|
||||
|
||||
# Copyright (C) 2007 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
df --version
|
||||
fi
|
||||
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd "$pwd" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
df -P . > t1 || fail=1
|
||||
BLOCK_SIZE=1M df -P . > t2 || fail=1
|
||||
|
||||
# Since disk utilization may be changing, compare only df's header line.
|
||||
# That records the block size. E.g., for "1M", it would be:
|
||||
# Filesystem 1048576-blocks Used Available Capacity Mounted on
|
||||
# while for 1K, it would be
|
||||
# Filesystem 1024-blocks Used Available Capacity Mounted on
|
||||
|
||||
head -n1 t1 > exp || fail=1
|
||||
head -n1 t2 > out || fail=1
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
@@ -42,15 +42,15 @@ fail=0
|
||||
umask 777
|
||||
|
||||
mknod -m 734 f1 p || fail=1
|
||||
set _ `ls -dgo f1`; shift; mode=$1
|
||||
mode=`ls -dgo f1|cut -b-10`
|
||||
test $mode = prwx-wxr-- || fail=1
|
||||
|
||||
mkfifo -m 734 f2 || fail=1
|
||||
set _ `ls -dgo f2`; shift; mode=$1
|
||||
mode=`ls -dgo f2|cut -b-10`
|
||||
test $mode = prwx-wxr-- || fail=1
|
||||
|
||||
mkdir -m 734 f3 || fail=1
|
||||
set _ `ls -dgo f3`; shift; mode=$1
|
||||
mode=`ls -dgo f3|cut -b-10`
|
||||
test $mode = drwx-wxr-- || test $mode = drwx-wsr-- || fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
61
tests/misc/pr
Executable file
61
tests/misc/pr
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
# -*- perl -*-
|
||||
# Exercise a bug with pr -m -s
|
||||
|
||||
# Copyright (C) 2007 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
: ${PERL=perl}
|
||||
: ${srcdir=.}
|
||||
|
||||
. $srcdir/../envvar-check
|
||||
|
||||
$PERL -e 1 > /dev/null 2>&1 || {
|
||||
echo 1>&2 "$0: configure didn't find a usable version of Perl," \
|
||||
"so can't run this test"
|
||||
exit 77
|
||||
}
|
||||
|
||||
exec $PERL -w -I$srcdir/.. -MCoreutils -- - <<\EOF
|
||||
#/
|
||||
require 5.003;
|
||||
use strict;
|
||||
|
||||
(my $program_name = $0) =~ s|.*/||;
|
||||
|
||||
$ENV{PROG} = 'pr';
|
||||
my $ME = $ENV{PROG};
|
||||
|
||||
# Turn off localization of executable's ouput.
|
||||
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
|
||||
|
||||
my @Tests =
|
||||
(
|
||||
['merge-w-tabs', '-m -s -t',
|
||||
{IN=>{1=>"a\tb\tc\n"}},
|
||||
{IN=>{2=>"m\tn\to\n"}},
|
||||
{IN=>{3=>"x\ty\tz\n"}},
|
||||
{OUT=>join("\t", qw(a b c m n o x y z)) . "\n"} ],
|
||||
);
|
||||
|
||||
my $save_temps = $ENV{DEBUG};
|
||||
my $verbose = $ENV{VERBOSE};
|
||||
|
||||
my $prog = $ENV{PROG} || die "$0: \$PROG not specified in environment\n";
|
||||
my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
|
||||
exit $fail;
|
||||
EOF
|
||||
@@ -97,7 +97,7 @@ until (++$i == $n);
|
||||
my $build_src_dir = $ENV{BUILD_SRC_DIR};
|
||||
$build_src_dir
|
||||
or die "$ME: envvar BUILD_SRC_DIR not defined\n";
|
||||
if ($build_src_dir !~ m!^([-.:/\w]+)$!)
|
||||
if ($build_src_dir !~ m!^([-+.:/\w]+)$!)
|
||||
{
|
||||
warn "$0: skipping this test; odd build source directory name:\n"
|
||||
. "$build_src_dir\n";
|
||||
|
||||
@@ -26,17 +26,17 @@ if test "$VERBOSE" = yes; then
|
||||
readlink --version
|
||||
fi
|
||||
|
||||
skip=1
|
||||
# Run this test IFF:
|
||||
# if REPLACE_GETCWD is 0 (system getcwd is good enough)
|
||||
# or HAVE_PARTLY_WORKING_GETCWD is defined
|
||||
test $REPLACE_GETCWD = 0 && skip=0
|
||||
test $skip = 1 &&
|
||||
grep '^#define HAVE_PARTLY_WORKING_GETCWD ' $CONFIG_HEADER > /dev/null &&
|
||||
skip=0
|
||||
test $skip = 1 &&
|
||||
test $host_os != linux-gnu &&
|
||||
{
|
||||
echo 1>&2 "$0: inadequate system getcwd; skipping this test"
|
||||
echo 1>&2 "$0: vendor getcwd may be inadequate; skipping this test"
|
||||
(exit 77); exit 77
|
||||
}
|
||||
|
||||
# Linux ia64 has the gl_FUNC_GETCWD_ABORT_BUG, so we can't use
|
||||
# the system getcwd.
|
||||
test $REPLACE_GETCWD = 1 &&
|
||||
{
|
||||
echo 1>&2 "$0: can't use buggy system getcwd; skipping this test"
|
||||
(exit 77); exit 77
|
||||
}
|
||||
|
||||
|
||||
57
tests/misc/runcon-no-reorder
Executable file
57
tests/misc/runcon-no-reorder
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# Ensure that runcon does not reorder its arguments.
|
||||
|
||||
# Copyright (C) 2007 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
runcon --version
|
||||
fi
|
||||
|
||||
. $srcdir/../lang-default
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd "$pwd" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
cat <<\EOF > exp || framework_failure=1
|
||||
runcon: runcon may be used only on a SELinux kernel
|
||||
EOF
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# This test works even on systems without SELinux.
|
||||
# On such a system it fails with the above diagnostic, which is fine.
|
||||
# Before the no-reorder change, it would have failed with a diagnostic
|
||||
# about -j being an invalid option.
|
||||
runcon -t unconfined_t true -j 2> out && : > exp
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
61
tests/misc/selinux
Executable file
61
tests/misc/selinux
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
# Test SELinux-related options.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
chcon --version
|
||||
cp --version
|
||||
ls --version
|
||||
mv --version
|
||||
stat --version
|
||||
fi
|
||||
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
. $srcdir/../selinux
|
||||
PRIV_CHECK_ARG=require-non-root . $srcdir/../priv-check
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
# Create a regular file, dir, fifo.
|
||||
touch f || framework_failure=1
|
||||
mkdir d s1 s2 || framework_failure=1
|
||||
mkfifo p || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
ctx=root:object_r:tmp_t
|
||||
# FIXME, what if $ctx is no different from the default. Not likely.
|
||||
# give each a different context, via chcon
|
||||
chcon $ctx f d p || fail=1
|
||||
# inspect that context with both ls -Z and stat.
|
||||
for i in d f p; do
|
||||
c=`ls -dogZ $i|cut -d' ' -f3`; test x$c = x$ctx || fail=1
|
||||
c=`stat --printf %C $i`; test x$c = x$ctx || fail=1
|
||||
done
|
||||
|
||||
# Copy each to a new directory and ensure that context is preserved.
|
||||
cp -r --preserve=all d f p s1 || fail=1
|
||||
for i in d f p; do
|
||||
c=`stat --printf %C s1/$i`; test x$c = x$ctx || fail=1
|
||||
done
|
||||
|
||||
# Now, move each to a new directory and ensure that context is preserved.
|
||||
mv d f p s2 || fail=1
|
||||
for i in d f p; do
|
||||
c=`stat --printf %C s2/$i`; test x$c = x$ctx || fail=1
|
||||
done
|
||||
|
||||
(exit $fail); exit $fail
|
||||
@@ -67,6 +67,7 @@ $@ and (warn "$ME: this script requires Perl's Expect package >=1.11\n"),
|
||||
sha256sum
|
||||
sha384sum
|
||||
sha512sum
|
||||
shuf
|
||||
sort
|
||||
sum
|
||||
tac
|
||||
|
||||
@@ -65,12 +65,12 @@ d_mode_arg=`"$abs_srcdir/../rwx-to-mode" $d_mode_str`
|
||||
mkdir -p -m $d_mode_arg a/b/c/d
|
||||
|
||||
# Make sure the permissions of `a' haven't been changed.
|
||||
p=`ls -ld a|sed 's/ .*//'`; case $p in $mode_str);; *) fail=1;; esac
|
||||
p=`ls -ld a|cut -b-10`; case $p in $mode_str);; *) fail=1;; esac
|
||||
# `b's and `c's should reflect the umask
|
||||
p=`ls -ld a/b|sed 's/ .*//'`; case $p in drwx------);; *) fail=1;; esac
|
||||
p=`ls -ld a/b/c|sed 's/ .*//'`; case $p in drwx------);; *) fail=1;; esac
|
||||
p=`ls -ld a/b|cut -b-10`; case $p in drwx------);; *) fail=1;; esac
|
||||
p=`ls -ld a/b/c|cut -b-10`; case $p in drwx------);; *) fail=1;; esac
|
||||
|
||||
# `d's perms are determined by the -m argument.
|
||||
p=`ls -ld a/b/c/d|sed 's/ .*//'`; case $p in $d_mode_str);; *) fail=1;; esac
|
||||
p=`ls -ld a/b/c/d|cut -b-10`; case $p in $d_mode_str);; *) fail=1;; esac
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -33,8 +33,8 @@ output_mode_string=drwxr-x-wT
|
||||
mkdir -m$set_mode_string $tmp || fail=1
|
||||
|
||||
test -d $tmp || fail=1
|
||||
set -- `ls -ld $tmp`
|
||||
case "$1" in
|
||||
mode=`ls -ld $tmp|cut -b-10`
|
||||
case "$mode" in
|
||||
$output_mode_string) ;;
|
||||
*) fail=1 ;;
|
||||
esac
|
||||
@@ -49,8 +49,8 @@ mkdir -m$set_mode_string $tmp2 2> /dev/null && fail=1
|
||||
mkdir --parents -m$set_mode_string $tmp2 || fail=1
|
||||
|
||||
test -d $tmp2 || fail=1
|
||||
set -- `ls -ld $tmp2`
|
||||
case "$1" in
|
||||
mode=`ls -ld $tmp2|cut -b-10`
|
||||
case "$mode" in
|
||||
$output_mode_string) ;;
|
||||
*) fail=1 ;;
|
||||
esac
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Test both cp and mv for their behavior with -if and -fi
|
||||
# The standards (POSIX and SuS) dictate annoyingly inconsistent behavior.
|
||||
|
||||
# Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2000, 2001, 2006, 2007 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
|
||||
@@ -61,7 +61,7 @@ cp -if e f < y > out 2>&1 || fail=1
|
||||
|
||||
# Make sure out contains the prompt.
|
||||
case "`cat out`" in
|
||||
"cp: overwrite \`f', overriding mode 0000?"*) ;;
|
||||
"cp: try to overwrite \`f', overriding mode 0000 (---------)?"*) ;;
|
||||
*) fail=1 ;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ test -f file && fail=1
|
||||
test -f $other_partition_tmpdir/file || fail=1
|
||||
|
||||
# This would have failed with the mv from fileutils-4.0i.
|
||||
set _ `ls -l $other_partition_tmpdir/file`; shift; mode=$1
|
||||
mode=`ls -l $other_partition_tmpdir/file|cut -b-10`
|
||||
test "$mode" = "-rwxrwxrwx" || fail=1
|
||||
|
||||
exit $fail
|
||||
|
||||
24
tests/selinux
Normal file
24
tests/selinux
Normal file
@@ -0,0 +1,24 @@
|
||||
# Is a test expensive?
|
||||
# Copyright (C) 2007 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
test "`ls -Zd .`" = '? .' &&
|
||||
{
|
||||
echo "$0: skipping this test; this system (or maybe just" 1>&2
|
||||
echo " the current file system) lacks SELinux support" 1>&2
|
||||
(exit 77); exit 77
|
||||
}
|
||||
Reference in New Issue
Block a user