diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c index e9ae33ad..6131f46a 100644 --- a/policycoreutils/setfiles/restore.c +++ b/policycoreutils/setfiles/restore.c @@ -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); diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h index bb35a1db..a5af81fe 100644 --- a/policycoreutils/setfiles/restore.h +++ b/policycoreutils/setfiles/restore.h @@ -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 diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8 index 19b59a2c..bf26e161 100644 --- a/policycoreutils/setfiles/setfiles.8 +++ b/policycoreutils/setfiles/setfiles.8 @@ -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 diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c index aeec1fdc..4dd0d0dc 100644 --- a/policycoreutils/setfiles/setfiles.c +++ b/policycoreutils/setfiles/setfiles.c @@ -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); }