@@ -35,6 +35,7 @@ struct restore_opts {
unsigned int ignore_noent;
unsigned int ignore_mounts;
unsigned int conflict_error;
+ unsigned int count_errors;
/* restorecon_flags holds | of above for restore_init() */
unsigned int restorecon_flags;
char *rootpath;
@@ -49,7 +50,8 @@ struct restore_opts {
void restore_init(struct restore_opts *opts);
void restore_finish(void);
void add_exclude(const char *directory);
-int process_glob(char *name, struct restore_opts *opts, size_t nthreads);
+int process_glob(char *name, struct restore_opts *opts, size_t nthreads,
+ long unsigned *skipped_errors);
extern char **exclude_list;
#endif
@@ -41,7 +41,8 @@ void restore_init(struct restore_opts *opts)
opts->xdev | opts->abort_on_error |
opts->syslog_changes | opts->log_matches |
opts->ignore_noent | opts->ignore_mounts |
- opts->mass_relabel | opts->conflict_error;
+ opts->mass_relabel | opts->conflict_error |
+ opts->count_errors;
/* Use setfiles, restorecon and restorecond own handles */
selinux_restorecon_set_sehandle(opts->hnd);
@@ -72,7 +73,8 @@ void restore_finish(void)
}
}
-int process_glob(char *name, struct restore_opts *opts, size_t nthreads)
+int process_glob(char *name, struct restore_opts *opts, size_t nthreads,
+ long unsigned *skipped_errors)
{
glob_t globbuf;
size_t i = 0;
@@ -96,6 +98,8 @@ int process_glob(char *name, struct restore_opts *opts, size_t nthreads)
nthreads);
if (rc < 0)
errors = rc;
+ else if (opts->restorecon_flags & SELINUX_RESTORECON_COUNT_ERRORS)
+ *skipped_errors += selinux_restorecon_get_skipped_errors();
}
globfree(&globbuf);
@@ -40,8 +40,8 @@ static __attribute__((__noreturn__)) void usage(const char *const name)
name, name);
} else {
fprintf(stderr,
- "usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n"
- "usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n"
+ "usage: %s [-diIDlmnpqvCEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n"
+ "usage: %s [-diIDlmnpqvCEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n"
"usage: %s -s [-diIDlmnpqvFWT] spec_file\n",
name, name, name);
}
@@ -150,9 +150,10 @@ int main(int argc, char **argv)
const char *base;
int errors = 0;
const char *ropts = "e:f:hiIDlmno:pqrsvFRW0xT:";
- const char *sopts = "c:de:f:hiIDlmno:pqr:svEFR:W0T:";
+ const char *sopts = "c:de:f:hiIDlmno:pqr:svCEFR:W0T:";
const char *opts;
union selinux_callback cb;
+ long unsigned skipped_errors;
/* Initialize variables */
memset(&r_opts, 0, sizeof(r_opts));
@@ -161,6 +162,7 @@ int main(int argc, char **argv)
warn_no_match = 0;
request_digest = 0;
policyfile = NULL;
+ skipped_errors = 0;
if (!argv[0]) {
fprintf(stderr, "Called without required program name!\n");
@@ -288,6 +290,9 @@ int main(int argc, char **argv)
r_opts.syslog_changes =
SELINUX_RESTORECON_SYSLOG_CHANGES;
break;
+ case 'C':
+ r_opts.count_errors = SELINUX_RESTORECON_COUNT_ERRORS;
+ break;
case 'E':
r_opts.conflict_error =
SELINUX_RESTORECON_CONFLICT_ERROR;
@@ -447,13 +452,15 @@ int main(int argc, char **argv)
buf[len - 1] = 0;
if (!strcmp(buf, "/"))
r_opts.mass_relabel = SELINUX_RESTORECON_MASS_RELABEL;
- errors |= process_glob(buf, &r_opts, nthreads) < 0;
+ errors |= process_glob(buf, &r_opts, nthreads,
+ &skipped_errors) < 0;
}
if (strcmp(input_filename, "-") != 0)
fclose(f);
} else {
for (i = optind; i < argc; i++)
- errors |= process_glob(argv[i], &r_opts, nthreads) < 0;
+ errors |= process_glob(argv[i], &r_opts, nthreads,
+ &skipped_errors) < 0;
}
maybe_audit_mass_relabel(r_opts.mass_relabel, errors);
@@ -467,5 +474,5 @@ int main(int argc, char **argv)
if (r_opts.progress)
fprintf(stdout, "\n");
- exit(errors ? -1 : 0);
+ exit(errors ? -1 : skipped_errors ? 1 : 0);
}
@@ -6,6 +6,7 @@ setfiles \- set SELinux file security contexts.
.B setfiles
.RB [ \-c
.IR policy ]
+.RB [ \-C ]
.RB [ \-d ]
.RB [ \-l ]
.RB [ \-m ]
@@ -58,6 +59,13 @@ option will force a replacement of the entire context.
.B \-c
check the validity of the contexts against the specified binary policy.
.TP
+.B \-C
+If only relabeling errors are encountered during the file tree walks,
+exit with status
+.B 1
+rather than
+.BR 255 .
+.TP
.B \-d
show what specification matched each file.
.TP
@@ -219,6 +227,20 @@ or the
.B \-s
option is used.
+.SH "EXIT STATUS"
+.B setfiles
+exits with status
+.B 0
+if it encounters no errors. Fatal errors result in status
+.BR 255 .
+Labeling errors encountered during file tree walk(s) result in status
+.B 1
+if the
+.B -C
+option is specified and no other kind of error is encountered, and in status
+.B 255
+otherwise.
+
.SH "NOTES"
.IP "1." 4
.B setfiles
setfiles(8) exits with status 255 if it encounters any error. Introduce the "-C" option: if the only errors that setfiles(8) encounters are labeling errors seen during the file tree walk(s), then let setfiles(8) exit with status 1. Cc: "Richard W.M. Jones" <rjones@redhat.com> Cc: Petr Lautrbach <plautrba@redhat.com> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1794518 Signed-off-by: Laszlo Ersek <lersek@redhat.com> --- policycoreutils/setfiles/restore.h | 4 +++- policycoreutils/setfiles/restore.c | 8 +++++-- policycoreutils/setfiles/setfiles.c | 19 +++++++++++------ policycoreutils/setfiles/setfiles.8 | 22 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 9 deletions(-)