lsscsi: fix xchdir("..") from symlink in /sys/bus/scsi/devices
[oweals/busybox.git] / selinux / chcon.c
index f0590b5b0258305652786df54a8470258153056b..3ddb2dd46d21bdee59d3c64b79858b7edd8ac62d 100644 (file)
@@ -4,8 +4,42 @@
  * Port to busybox: KaiGai Kohei <kaigai@kaigai.gr.jp>
  *
  * Copyright (C) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
  */
-#include <getopt.h>
+//config:config CHCON
+//config:      bool "chcon (8.9 kb)"
+//config:      default n
+//config:      depends on SELINUX
+//config:      help
+//config:      Enable support to change the security context of file.
+
+//applet:IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_CHCON) += chcon.o
+
+//usage:#define chcon_trivial_usage
+//usage:       "[OPTIONS] CONTEXT FILE..."
+//usage:       "\n     chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..."
+//usage:       IF_LONG_OPTS(
+//usage:       "\n     chcon [OPTIONS] --reference=RFILE FILE..."
+//usage:       )
+//usage:
+//usage:#define chcon_full_usage "\n\n"
+//usage:       "Change the security context of each FILE to CONTEXT\n"
+//usage:     "\n       -v      Verbose"
+//usage:     "\n       -c      Report changes made"
+//usage:     "\n       -h      Affect symlinks instead of their targets"
+//usage:     "\n       -f      Suppress most error messages"
+//usage:       IF_LONG_OPTS(
+//usage:     "\n       --reference RFILE Use RFILE's group instead of using a CONTEXT value"
+//usage:       )
+//usage:     "\n       -u USER Set user/role/type/range in the target security context"
+//usage:     "\n       -r ROLE"
+//usage:     "\n       -t TYPE"
+//usage:     "\n       -l RNG"
+//usage:     "\n       -R      Recurse"
+
 #include <selinux/context.h>
 
 #include "libbb.h"
@@ -19,7 +53,7 @@
 #define OPT_TYPE               (1<<6)  /* 't' */
 #define OPT_RANGE              (1<<7)  /* 'l' */
 #define OPT_VERBOSE            (1<<8)  /* 'v' */
-#define OPT_REFERENCE          ((1<<9) * ENABLE_FEATURE_CHCON_LONG_OPTIONS)
+#define OPT_REFERENCE          ((1<<9) * ENABLE_LONG_OPTS)
 #define OPT_COMPONENT_SPECIFIED        (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE)
 
 static char *user = NULL;
@@ -28,7 +62,11 @@ static char *type = NULL;
 static char *range = NULL;
 static char *specified_context = NULL;
 
-static int change_filedir_context(const char *fname, struct stat *stbuf, void *userData, int depth)
+static int FAST_FUNC change_filedir_context(
+               const char *fname,
+               struct stat *stbuf UNUSED_PARAM,
+               void *userData UNUSED_PARAM,
+               int depth UNUSED_PARAM)
 {
        context_t context = NULL;
        security_context_t file_context = NULL;
@@ -43,20 +81,20 @@ static int change_filedir_context(const char *fname, struct stat *stbuf, void *u
        }
        if (status < 0 && errno != ENODATA) {
                if ((option_mask32 & OPT_QUIET) == 0)
-                       bb_error_msg("cannot obtain security context: %s", fname);
+                       bb_error_msg("can't obtain security context: %s", fname);
                goto skip;
        }
 
        if (file_context == NULL && specified_context == NULL) {
-               bb_error_msg("cannot apply partial context to unlabeled file %s", fname);
+               bb_error_msg("can't apply partial context to unlabeled file %s", fname);
                goto skip;
        }
 
        if (specified_context == NULL) {
                context = set_security_context_component(file_context,
-                                                        user, role, type, range);
+                                                       user, role, type, range);
                if (!context) {
-                       bb_error_msg("cannot compute security context from %s", file_context);
+                       bb_error_msg("can't compute security context from %s", file_context);
                        goto skip;
                }
        } else {
@@ -69,7 +107,7 @@ static int change_filedir_context(const char *fname, struct stat *stbuf, void *u
 
        context_string = context_str(context);
        if (!context_string) {
-               bb_error_msg("cannot obtain security context in text expression");
+               bb_error_msg("can't obtain security context in text expression");
                goto skip;
        }
 
@@ -83,15 +121,15 @@ static int change_filedir_context(const char *fname, struct stat *stbuf, void *u
                }
                if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) {
                        printf(!fail
-                              ? "context of %s changed to %s\n"
-                              : "failed to change context of %s to %s\n",
-                              fname, context_string);
+                               ? "context of %s changed to %s\n"
+                               : "can't change context of %s to %s\n",
+                               fname, context_string);
                }
                if (!fail) {
                        rc = TRUE;
                } else if ((option_mask32 & OPT_QUIET) == 0) {
-                       bb_error_msg("failed to change context of %s to %s",
-                                    fname, context_string);
+                       bb_error_msg("can't change context of %s to %s",
+                                       fname, context_string);
                }
        } else if (option_mask32 & OPT_VERBOSE) {
                printf("context of %s retained as %s\n", fname, context_string);
@@ -104,7 +142,7 @@ skip:
        return rc;
 }
 
-#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
+#if ENABLE_LONG_OPTS
 static const char chcon_longopts[] ALIGN1 =
        "recursive\0"      No_argument       "R"
        "changes\0"        No_argument       "c"
@@ -120,30 +158,31 @@ static const char chcon_longopts[] ALIGN1 =
        ;
 #endif
 
-int chcon_main(int argc, char **argv);
-int chcon_main(int argc, char **argv)
+int chcon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chcon_main(int argc UNUSED_PARAM, char **argv)
 {
        char *reference_file;
        char *fname;
        int i, errors = 0;
 
-#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
-       applet_long_options = chcon_longopts;
-#endif
-       opt_complementary = "-1"  /* at least 1 param */
-               ":?"  /* error if exclusivity constraints are violated */
-#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
+       getopt32long(argv, "^"
+               "Rchfu:r:t:l:v"
+               "\0"
+               "-1" /* at least 1 arg */
+               ":?" /* error if exclusivity constraints are violated */
+#if ENABLE_LONG_OPTS
                ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff"
 #endif
-               ":f--v:v--f";  /* 'verbose' and 'quiet' are exclusive */
-       getopt32(argv, "Rchf:u:r:t:l:v",
-               &user, &role, &type, &range, &reference_file);
+               ":f--v:v--f"  /* 'verbose' and 'quiet' are exclusive */
+               , chcon_longopts,
+               &user, &role, &type, &range, &reference_file
+       );
        argv += optind;
 
-#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
+#if ENABLE_LONG_OPTS
        if (option_mask32 & OPT_REFERENCE) {
                /* FIXME: lgetfilecon() should be used when '-h' is specified.
-                  But current implementation follows the original one. */
+                * But current implementation follows the original one. */
                if (getfilecon(reference_file, &specified_context) < 0)
                        bb_perror_msg_and_die("getfilecon('%s') failed", reference_file);
        } else
@@ -163,10 +202,10 @@ int chcon_main(int argc, char **argv)
                fname[fname_len] = '\0';
 
                if (recursive_action(fname,
-                                    1<<option_mask32 & OPT_RECURSIVE,
-                                    change_filedir_context,
-                                    change_filedir_context,
-                                    NULL, 0) != TRUE)
+                                       1<<option_mask32 & OPT_RECURSIVE,
+                                       change_filedir_context,
+                                       change_filedir_context,
+                                       NULL, 0) != TRUE)
                        errors = 1;
        }
        return errors;