setfiles,restorecon: new SELinux applets by Yuichi Nakamura <ynakam@hitachisoft.jp>

This commit is contained in:
Denis Vlasenko 2007-07-23 14:03:30 +00:00
parent 845db2acf3
commit 397137b815
5 changed files with 773 additions and 0 deletions

View File

@ -270,6 +270,7 @@ USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot))
USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER, restorecon))
USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm)) USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm))
USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir)) USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir))
USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
@ -288,6 +289,7 @@ USE_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_NEVER, seq))
USE_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_NEVER))
USE_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
USE_SETFILES(APPLET(setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER))
USE_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) USE_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
USE_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_NEVER))

View File

@ -2783,6 +2783,22 @@
#define resize_full_usage \ #define resize_full_usage \
"Resize the screen" "Resize the screen"
#define restorecon_trivial_usage \
"[-iFnrRv] [-e excludedir]... [-o filename] [-f filename | pathname]"
#define restorecon_full_usage \
"Reset security contexts of files in pathname\n" \
"\n -i Ignore files that do not exist" \
"\n -f filename File with list of files to process. Use - for stdin" \
"\n -e directory Directory to exclude" \
"\n -R,-r Recurse directories" \
"\n -n Don't change any file labels" \
"\n -o filename Save list of files with incorrect context" \
"\n -v Verbose" \
"\n -vv Show changed labels" \
"\n -F Force reset of context to match file_context" \
"\n for customizable files, or the user section," \
"\n if it has changed"
#define rm_trivial_usage \ #define rm_trivial_usage \
"[OPTION]... FILE..." "[OPTION]... FILE..."
#define rm_full_usage \ #define rm_full_usage \
@ -2947,6 +2963,31 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
"[Enforcing | Permissive | 1 | 0]" "[Enforcing | Permissive | 1 | 0]"
#define setenforce_full_usage #define setenforce_full_usage
#define setfiles_trivial_usage \
"[-dnpqsvW] [-e dir]... [-o filename] [-r alt_root_path]" \
USE_FEATURE_SETFILES_CHECK_OPTION( \
" [-c policyfile] spec_file" \
) \
" pathname"
#define setfiles_full_usage \
"Reset file contexts under pathname according to spec_file" \
USE_FEATURE_SETFILES_CHECK_OPTION( \
"\n -c file Check the validity of the contexts against the specified binary policy" \
) \
"\n -d Show which specification matched each file" \
"\n -l Log changes in file labels to syslog" \
"\n -n Don't change any file labels" \
"\n -q Suppress no-error output" \
"\n -r dir Use an altenate root path" \
"\n -e dir Exclude directory" \
"\n -F Force reset of context to match file_context for customizable files" \
"\n -o file Save list of files with incorrect context" \
"\n -s Take a list of files from standard input (instead of command line)" \
"\n -v Show changes in file labels, if type or role are changing" \
"\n -vv Show changes in file labels, if type, role, or user are changing" \
"\n -W Display warnings about entries that had no matching files"
#define setkeycodes_trivial_usage \ #define setkeycodes_trivial_usage \
"SCANCODE KEYCODE ..." "SCANCODE KEYCODE ..."
#define setkeycodes_full_usage \ #define setkeycodes_full_usage \

View File

@ -49,6 +49,14 @@ config MATCHPATHCON
Enable support to get default security context of the Enable support to get default security context of the
specified path from the file contexts configuration. specified path from the file contexts configuration.
config RESTORECON
bool "restorecon"
default n
depends on SELINUX
help
Enable support to relabel files. The feature is almost
the same as setfiles, but usage is a little different.
config RUNCON config RUNCON
bool "runcon" bool "runcon"
default n default n
@ -78,5 +86,23 @@ config SETENFORCE
help help
Enable support to modify the mode SELinux is running in. Enable support to modify the mode SELinux is running in.
config SETFILES
bool "setfiles"
default n
depends on SELINUX
help
Enable support to modify to relabel files.
Notice: If you built libselinux with -D_FILE_OFFSET_BITS=64,
(It is default in libselinux's Makefile), you _must_ enable
CONFIG_LFS.
config FEATURE_SETFILES_CHECK_OPTION
bool "Enable check option"
default n
depends on SETFILES
help
Support "-c" option (check the validity of the contexts against
the specified binary policy) for setfiles. Requires libsepol.
endmenu endmenu

View File

@ -14,3 +14,5 @@ lib-$(CONFIG_MATCHPATHCON) += matchpathcon.o
lib-$(CONFIG_RUNCON) += runcon.o lib-$(CONFIG_RUNCON) += runcon.o
lib-$(CONFIG_SELINUXENABLED) += selinuxenabled.o lib-$(CONFIG_SELINUXENABLED) += selinuxenabled.o
lib-$(CONFIG_SETENFORCE) += setenforce.o lib-$(CONFIG_SETENFORCE) += setenforce.o
lib-$(CONFIG_SETFILES) += setfiles.o
lib-$(CONFIG_RESTORECON) += setfiles.o

702
selinux/setfiles.c Normal file
View File

@ -0,0 +1,702 @@
/*
setfiles: based on policycoreutils 2.0.19
policycoreutils was released under GPL 2.
Port to BusyBox by 2007 Yuichi Nakamura <ynakam@hitachisoft.jp>
*/
#include "libbb.h"
#if ENABLE_FEATURE_SETFILES_CHECK_OPTION
#include <sepol/sepol.h>
#endif
#define MAX_EXCLUDES 50
struct edir {
char *directory;
size_t size;
};
struct globals {
FILE *outfile;
char *policyfile;
char *rootpath;
int rootpathlen;
unsigned count;
int excludeCtr;
int errors;
int verbose; /* getopt32 uses it, has to be int */
//smallint force;
//smallint progress;
//smallint debug;
//smallint dry_run;
//smallint quiet;
//smallint ignore_enoent;
//smallint take_log;
//smallint warn_no_match;
smallint recurse; /* Recursive descent */
smallint follow_mounts;
/* Behavior flags determined based on setfiles vs. restorecon */
smallint expand_realpath; /* Expand paths via realpath */
smallint abort_on_error; /* Abort the file tree walk upon an error */
int add_assoc; /* Track inode associations for conflict detection */
int matchpathcon_flags; /* Flags to matchpathcon */
dev_t dev_id; /* Device id where target file exists */
int nerr;
struct edir excludeArray[MAX_EXCLUDES];
};
#define G (*(struct globals*)&bb_common_bufsiz1)
void BUG_setfiles_globals_too_big(void);
#define INIT_G() do { \
if (sizeof(G) > COMMON_BUFSIZE) \
BUG_setfiles_globals_too_big(); \
/* memset(&G, 0, sizeof(G)); - already is */ \
} while (0)
#define outfile (G.outfile )
#define policyfile (G.policyfile )
#define rootpath (G.rootpath )
#define rootpathlen (G.rootpathlen )
#define count (G.count )
#define excludeCtr (G.excludeCtr )
#define errors (G.errors )
#define verbose (G.verbose )
//#define force (G.force )
//#define progress (G.progress )
//#define debug (G.debug )
//#define dry_run (G.dry_run )
//#define quiet (G.quiet )
//#define ignore_enoent (G.ignore_enoent )
//#define take_log (G.take_log )
//#define warn_no_match (G.warn_no_match )
#define recurse (G.recurse )
#define follow_mounts (G.follow_mounts )
#define expand_realpath (G.expand_realpath )
#define abort_on_error (G.abort_on_error )
#define add_assoc (G.add_assoc )
#define matchpathcon_flags (G.matchpathcon_flags)
#define dev_id (G.dev_id )
#define nerr (G.nerr )
#define excludeArray (G.excludeArray )
/* Must match getopt32 string! */
enum {
OPT_d = (1 << 0),
OPT_e = (1 << 1),
OPT_f = (1 << 2),
OPT_i = (1 << 3),
OPT_l = (1 << 4),
OPT_n = (1 << 5),
OPT_p = (1 << 6),
OPT_q = (1 << 7),
OPT_r = (1 << 8),
OPT_s = (1 << 9),
OPT_v = (1 << 10),
OPT_o = (1 << 11),
OPT_F = (1 << 12),
OPT_W = (1 << 13),
OPT_c = (1 << 14), /* c only for setfiles */
OPT_R = (1 << 14), /* R only for restorecon */
};
#define FLAG_d_debug (option_mask32 & OPT_d)
#define FLAG_e (option_mask32 & OPT_e)
#define FLAG_f (option_mask32 & OPT_f)
#define FLAG_i_ignore_enoent (option_mask32 & OPT_i)
#define FLAG_l_take_log (option_mask32 & OPT_l)
#define FLAG_n_dry_run (option_mask32 & OPT_n)
#define FLAG_p_progress (option_mask32 & OPT_p)
#define FLAG_q_quiet (option_mask32 & OPT_q)
#define FLAG_r (option_mask32 & OPT_r)
#define FLAG_s (option_mask32 & OPT_s)
#define FLAG_v (option_mask32 & OPT_v)
#define FLAG_o (option_mask32 & OPT_o)
#define FLAG_F_force (option_mask32 & OPT_F)
#define FLAG_W_warn_no_match (option_mask32 & OPT_W)
#define FLAG_c (option_mask32 & OPT_c)
#define FLAG_R (option_mask32 & OPT_R)
static void qprintf(const char *fmt, ...)
{
/* quiet, do nothing */
}
static void inc_err(void)
{
nerr++;
if (nerr > 9 && !FLAG_d_debug) {
bb_error_msg_and_die("exiting after 10 errors");
}
}
static int add_exclude(const char *directory)
{
struct stat sb;
size_t len = 0;
if (directory == NULL || directory[0] != '/') {
bb_error_msg("full path required for exclude: %s", directory);
return 1;
}
if (lstat(directory, &sb)) {
bb_error_msg("directory \"%s\" not found, ignoring", directory);
return 0;
}
if ((sb.st_mode & S_IFDIR) == 0) {
bb_error_msg("\"%s\" is not a directory: mode %o, ignoring",
directory, sb.st_mode);
return 0;
}
if (excludeCtr == MAX_EXCLUDES) {
bb_error_msg("maximum excludes %d exceeded", MAX_EXCLUDES);
return 1;
}
len = strlen(directory);
while (len > 1 && directory[len - 1] == '/') {
len--;
}
excludeArray[excludeCtr].directory = xstrndup(directory, len);
excludeArray[excludeCtr++].size = len;
return 0;
}
static int exclude(const char *file)
{
int i = 0;
for (i = 0; i < excludeCtr; i++) {
if (strncmp(file, excludeArray[i].directory,
excludeArray[i].size) == 0) {
if (file[excludeArray[i].size] == '\0'
|| file[excludeArray[i].size] == '/') {
return 1;
}
}
}
return 0;
}
static int match(const char *name, struct stat *sb, char **con)
{
int ret;
char path[PATH_MAX + 1];
char *tmp_path = xstrdup(name);
if (excludeCtr > 0) {
if (exclude(name)) {
goto err;
}
}
ret = lstat(name, sb);
if (ret) {
if (FLAG_i_ignore_enoent && errno == ENOENT) {
free(tmp_path);
return 0;
}
bb_error_msg("stat(%s)", name);
goto err;
}
if (expand_realpath) {
if (S_ISLNK(sb->st_mode)) {
char *p = NULL;
char *file_sep;
size_t len = 0;
if (verbose > 1)
bb_error_msg("warning! %s refers to a symbolic link, not following last component", name);
file_sep = strrchr(tmp_path, '/');
if (file_sep == tmp_path) {
file_sep++;
p[0] = '\0';
p = path;
} else if (file_sep) {
*file_sep++ = '\0';
p = realpath(tmp_path, path);
} else {
file_sep = tmp_path;
p = realpath("./", path);
}
if (p)
len = strlen(p);
if (!p || len + strlen(file_sep) + 2 > PATH_MAX) {
bb_perror_msg("realpath(%s) failed", name);
goto err;
}
p += len;
/* ensure trailing slash of directory name */
if (len == 0 || p[-1] != '/') {
*p++ = '/';
}
strcpy(p, file_sep);
name = path;
if (excludeCtr > 0 && exclude(name))
goto err;
} else {
char *p;
p = realpath(name, path);
if (!p) {
bb_perror_msg("realpath(%s)", name);
goto err;
}
name = p;
if (excludeCtr > 0 && exclude(name))
goto err;
}
}
/* name will be what is matched in the policy */
if (NULL != rootpath) {
if (0 != strncmp(rootpath, name, rootpathlen)) {
bb_error_msg("%s is not located in %s",
name, rootpath);
goto err;
}
name += rootpathlen;
}
free(tmp_path);
if (rootpath != NULL && name[0] == '\0')
/* this is actually the root dir of the alt root */
return matchpathcon_index("/", sb->st_mode, con);
return matchpathcon_index(name, sb->st_mode, con);
err:
free(tmp_path);
return -1;
}
/* Compare two contexts to see if their differences are "significant",
* or whether the only difference is in the user. */
static int only_changed_user(const char *a, const char *b)
{
if (FLAG_F_force)
return 0;
if (!a || !b)
return 0;
a = strchr(a, ':'); /* Rest of the context after the user */
b = strchr(b, ':');
if (!a || !b)
return 0;
return (strcmp(a, b) == 0);
}
static int restore(const char *file)
{
char *my_file = xstrdup(file);
char *my_file_orig = my_file;
struct stat my_sb;
int i, j, ret;
char *context = NULL;
char *newcon = NULL;
int user_only_changed = 0;
size_t len = strlen(my_file);
int retval = 0;
/* Skip the extra slashes at the beginning and end, if present. */
if (file[0] == '/' && file[1] == '/')
my_file++;
if (len > 1 && my_file[len - 1] == '/')
my_file[len - 1] = '\0';
i = match(my_file, &my_sb, &newcon);
if (i < 0) /* No matching specification. */
goto out;
if (FLAG_p_progress) {
count++;
if (count % 0x400 == 0) { /* every 1024 times */
count = (count % (80*0x400));
if (count == 0)
fputc('\n', stdout);
fputc('*', stdout);
fflush(stdout);
}
}
/*
* Try to add an association between this inode and
* this specification. If there is already an association
* for this inode and it conflicts with this specification,
* then use the last matching specification.
*/
if (add_assoc) {
j = matchpathcon_filespec_add(my_sb.st_ino, i, my_file);
if (j < 0)
goto err;
if (j != i) {
/* There was already an association and it took precedence. */
goto out;
}
}
if (FLAG_d_debug)
printf("%s: %s matched by %s\n", applet_name, my_file, newcon);
/* Get the current context of the file. */
ret = lgetfilecon_raw(my_file, &context);
if (ret < 0) {
if (errno == ENODATA) {
context = NULL; /* paranoia */
} else {
bb_perror_msg("lgetfilecon_raw on %s", my_file);
goto err;
}
user_only_changed = 0;
} else
user_only_changed = only_changed_user(context, newcon);
/*
* Do not relabel the file if the matching specification is
* <<none>> or the file is already labeled according to the
* specification.
*/
if ((strcmp(newcon, "<<none>>") == 0)
|| (context && (strcmp(context, newcon) == 0) && !FLAG_F_force)) {
goto out;
}
if (!FLAG_F_force && context && (is_context_customizable(context) > 0)) {
if (verbose > 1) {
bb_error_msg("skipping %s. %s is customizable_types",
my_file, context);
}
goto out;
}
if (verbose) {
/* If we're just doing "-v", trim out any relabels where
* the user has changed but the role and type are the
* same. For "-vv", emit everything. */
if (verbose > 1 || !user_only_changed) {
bb_info_msg("%s: reset %s context %s->%s",
applet_name, my_file, context ?: "", newcon);
}
}
if (FLAG_l_take_log && !user_only_changed) {
if (context)
bb_info_msg("relabeling %s from %s to %s", my_file, context, newcon);
else
bb_info_msg("labeling %s to %s", my_file, newcon);
}
if (outfile && !user_only_changed)
fprintf(outfile, "%s\n", my_file);
/*
* Do not relabel the file if -n was used.
*/
if (FLAG_n_dry_run || user_only_changed)
goto out;
/*
* Relabel the file to the specified context.
*/
ret = lsetfilecon(my_file, newcon);
if (ret) {
bb_perror_msg("lsetfileconon(%s,%s)", my_file, newcon);
goto err;
}
out:
freecon(context);
freecon(newcon);
free(my_file_orig);
return retval;
err:
retval--; /* -1 */
goto out;
}
/*
* Apply the last matching specification to a file.
* This function is called by recursive_action on each file during
* the directory traversal.
*/
static int apply_spec(const char *file,
struct stat *sb, void *userData, int depth)
{
if (!follow_mounts) {
/* setfiles does not process across different mount points */
if (sb->st_dev != dev_id) {
return SKIP;
}
}
errors |= restore(file);
if (abort_on_error && errors)
return FALSE;
return TRUE;
}
static int canoncon(const char *path, unsigned lineno, char **contextp)
{
static const char err_msg[] = "%s: line %u has invalid context %s";
char *tmpcon;
char *context = *contextp;
int invalid = 0;
#if ENABLE_FEATURE_SETFILES_CHECK_OPTION
if (policyfile) {
if (sepol_check_context(context) >= 0)
return 0;
/* Exit immediately if we're in checking mode. */
bb_error_msg_and_die(err_msg, path, lineno, context);
}
#endif
if (security_canonicalize_context_raw(context, &tmpcon) < 0) {
if (errno != ENOENT) {
invalid = 1;
inc_err();
}
} else {
free(context);
*contextp = tmpcon;
}
if (invalid) {
bb_error_msg(err_msg, path, lineno, context);
}
return invalid;
}
static int process_one(char *name)
{
struct stat sb;
int rc;
rc = lstat(name, &sb);
if (rc < 0) {
if (FLAG_i_ignore_enoent && errno == ENOENT)
return 0;
bb_perror_msg("stat(%s)", name);
goto err;
}
dev_id = sb.st_dev;
if (S_ISDIR(sb.st_mode) && recurse) {
if (recursive_action(name,
ACTION_RECURSE,
apply_spec,
apply_spec,
NULL, 0) != TRUE) {
bb_error_msg("error while labeling %s", name);
goto err;
}
} else {
rc = restore(name);
if (rc)
goto err;
}
out:
if (add_assoc) {
if (FLAG_q_quiet)
set_matchpathcon_printf(&qprintf);
matchpathcon_filespec_eval();
set_matchpathcon_printf(NULL);
matchpathcon_filespec_destroy();
}
return rc;
err:
rc = -1;
goto out;
}
int setfiles_main(int argc, char **argv);
int setfiles_main(int argc, char **argv)
{
struct stat sb;
int rc, i = 0;
const char *input_filename = NULL;
int use_input_file = 0;
char *buf = NULL;
size_t buf_len;
int flags;
llist_t *exclude_dir = NULL;
char *out_filename = NULL;
INIT_G();
if (applet_name[0] == 's') { /* "setfiles" */
/*
* setfiles:
* Recursive descent,
* Does not expand paths via realpath,
* Aborts on errors during the file tree walk,
* Try to track inode associations for conflict detection,
* Does not follow mounts,
* Validates all file contexts at init time.
*/
recurse = 1;
abort_on_error = 1;
add_assoc = 1;
/* follow_mounts = 0; - already is */
matchpathcon_flags = MATCHPATHCON_VALIDATE | MATCHPATHCON_NOTRANS;
} else {
/*
* restorecon:
* No recursive descent unless -r/-R,
* Expands paths via realpath,
* Do not abort on errors during the file tree walk,
* Do not try to track inode associations for conflict detection,
* Follows mounts,
* Does lazy validation of contexts upon use.
*/
expand_realpath = 1;
follow_mounts = 1;
matchpathcon_flags = MATCHPATHCON_NOTRANS;
/* restorecon only */
selinux_or_die();
}
set_matchpathcon_flags(matchpathcon_flags);
opt_complementary = "e::vv:v--p:p--v";
/* Option order must match OPT_x definitions! */
if (applet_name[0] == 'r') { /* restorecon */
flags = getopt32(argc, argv, "de:f:ilnpqrsvo:FWR",
&exclude_dir, &input_filename, &out_filename, &verbose);
} else { /* setfiles */
flags = getopt32(argc, argv, "de:f:ilnpqr:svo:FW"
USE_FEATURE_SETFILES_CHECK_OPTION("c:"),
&exclude_dir, &input_filename, &rootpath, &out_filename,
USE_FEATURE_SETFILES_CHECK_OPTION(&policyfile,)
&verbose);
}
#if ENABLE_FEATURE_SETFILES_CHECK_OPTION
if ((applet_name[0] == 's') && (flags & OPT_c)) {
FILE *policystream;
policystream = xfopen(policyfile, "r");
if (sepol_set_policydb_from_file(policystream) < 0) {
bb_error_msg_and_die("sepol_set_policydb_from_file on %s", policyfile);
}
fclose(policystream);
/* Only process the specified file_contexts file, not
any .homedirs or .local files, and do not perform
context translations. */
set_matchpathcon_flags(MATCHPATHCON_BASEONLY |
MATCHPATHCON_NOTRANS |
MATCHPATHCON_VALIDATE);
}
#endif
//if (flags & OPT_d) {
// debug = 1;
//}
if (flags & OPT_e) {
if (exclude_dir == NULL) {
bb_show_usage();
}
while (exclude_dir) {
if (add_exclude(llist_pop(&exclude_dir)))
exit(1);
}
}
//if (flags & OPT_i) {
// ignore_enoent = 1;
//}
//if (flags & OPT_l) {
// take_log = 1;
//}
//if (flags & OPT_F) {
// force = 1;
//}
//if (flags & OPT_n) {
// dry_run = 1;
//}
if (flags & OPT_o) {
outfile = stdout;
if (NOT_LONE_CHAR(out_filename, '-')) {
outfile = xfopen(out_filename, "w");
}
}
//if (flags & OPT_q) {
// quiet = 1;
//}
if (applet_name[0] == 'r') { /* restorecon */
if (flags & (OPT_r | OPT_R))
recurse = 1;
} else { /* setfiles */
if (flags & OPT_r)
rootpathlen = strlen(rootpath);
}
if (flags & OPT_s) {
use_input_file = 1;
input_filename = "-";
add_assoc = 0;
}
//if (flags & OPT_p) {
// progress = 1;
//}
//if (flags & OPT_W) {
// warn_no_match = 1;
//}
if (applet_name[0] == 's') { /* setfiles */
/* Use our own invalid context checking function so that
we can support either checking against the active policy or
checking against a binary policy file. */
set_matchpathcon_canoncon(&canoncon);
if (argc == 1)
bb_show_usage();
if (stat(argv[optind], &sb) < 0) {
bb_perror_msg_and_die("%s", argv[optind]);
}
if (!S_ISREG(sb.st_mode)) {
bb_error_msg_and_die("spec file %s is not a regular file", argv[optind]);
}
/* Load the file contexts configuration and check it. */
rc = matchpathcon_init(argv[optind]);
if (rc < 0) {
bb_perror_msg_and_die("%s", argv[optind]);
}
optind++;
if (nerr)
exit(1);
}
if (use_input_file) {
ssize_t len;
FILE *f = stdin;
if (NOT_LONE_CHAR(input_filename, '-'))
f = xfopen(input_filename, "r");
while ((len = getline(&buf, &buf_len, f)) > 0) {
buf[len - 1] = '\0';
errors |= process_one(buf);
}
if (ENABLE_FEATURE_CLEAN_UP)
fclose_if_not_stdin(f);
} else {
if (optind >= argc)
bb_show_usage();
for (i = optind; i < argc; i++) {
errors |= process_one(argv[i]);
}
}
if (FLAG_W_warn_no_match)
matchpathcon_checkmatches(argv[0]);
if (ENABLE_FEATURE_CLEAN_UP && outfile)
fclose(outfile);
return errors;
}