|  | #include <unistd.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <errno.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fts.h> | 
|  | #include <selinux/selinux.h> | 
|  | #include <selinux/label.h> | 
|  |  | 
|  | #define FCPATH "/file_contexts" | 
|  |  | 
|  | static struct selabel_handle *sehandle; | 
|  | static const char *progname; | 
|  | static int nochange; | 
|  | static int verbose; | 
|  |  | 
|  | static void usage(void) | 
|  | { | 
|  | fprintf(stderr, "usage:  %s [-f file_contexts] [-nrRv] pathname...\n", progname); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | static int restore(const char *pathname, const struct stat *sb) | 
|  | { | 
|  | char *oldcontext, *newcontext; | 
|  |  | 
|  | if (lgetfilecon(pathname, &oldcontext) < 0) { | 
|  | fprintf(stderr, "Could not get context of %s:  %s\n", | 
|  | pathname, strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) { | 
|  | fprintf(stderr, "Could not lookup context for %s:  %s\n", pathname, | 
|  | strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | if (strcmp(newcontext, "<<none>>") && | 
|  | strcmp(oldcontext, newcontext)) { | 
|  | if (verbose) | 
|  | printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext); | 
|  | if (!nochange) { | 
|  | if (lsetfilecon(pathname, newcontext) < 0) { | 
|  | fprintf(stderr, "Could not label %s with %s:  %s\n", | 
|  | pathname, newcontext, strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | } | 
|  | freecon(oldcontext); | 
|  | freecon(newcontext); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int restorecon_main(int argc, char **argv) | 
|  | { | 
|  | struct selinux_opt seopts[] = { | 
|  | { SELABEL_OPT_PATH, FCPATH } | 
|  | }; | 
|  | int ch, recurse = 0, ftsflags = FTS_PHYSICAL; | 
|  |  | 
|  | progname = argv[0]; | 
|  |  | 
|  | do { | 
|  | ch = getopt(argc, argv, "f:nrRv"); | 
|  | if (ch == EOF) | 
|  | break; | 
|  | switch (ch) { | 
|  | case 'f': | 
|  | seopts[0].value = optarg; | 
|  | break; | 
|  | case 'n': | 
|  | nochange = 1; | 
|  | break; | 
|  | case 'r': | 
|  | case 'R': | 
|  | recurse = 1; | 
|  | break; | 
|  | case 'v': | 
|  | verbose = 1; | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | } | 
|  | } while (1); | 
|  |  | 
|  | argc -= optind; | 
|  | argv += optind; | 
|  | if (!argc) | 
|  | usage(); | 
|  |  | 
|  | sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); | 
|  | if (!sehandle) { | 
|  | fprintf(stderr, "Could not load file contexts from %s:  %s\n", seopts[0].value, | 
|  | strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (recurse) { | 
|  | FTS *fts; | 
|  | FTSENT *ftsent; | 
|  | fts = fts_open(argv, ftsflags, NULL); | 
|  | if (!fts) { | 
|  | fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n", | 
|  | argv[0], strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | while ((ftsent = fts_read(fts))) { | 
|  | switch (ftsent->fts_info) { | 
|  | case FTS_DP: | 
|  | break; | 
|  | case FTS_DNR: | 
|  | case FTS_ERR: | 
|  | case FTS_NS: | 
|  | fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path, | 
|  | strerror(errno)); | 
|  | fts_set(fts, ftsent, FTS_SKIP); | 
|  | break; | 
|  | default: | 
|  | if (restore(ftsent->fts_path, ftsent->fts_statp) < 0) | 
|  | fts_set(fts, ftsent, FTS_SKIP); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | int i, rc; | 
|  | struct stat sb; | 
|  |  | 
|  | for (i = 0; i < argc; i++) { | 
|  | rc = lstat(argv[i], &sb); | 
|  | if (rc < 0) { | 
|  | fprintf(stderr, "Could not stat %s:  %s\n", argv[i], | 
|  | strerror(errno)); | 
|  | continue; | 
|  | } | 
|  | restore(argv[i], &sb); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } |