1#include <unistd.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <errno.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fts.h>
8#include <selinux/selinux.h>
9#include <selinux/label.h>
10#include <selinux/android.h>
11
12static struct selabel_handle *sehandle;
13static const char *progname;
14static int nochange;
15static int verbose;
16
17static void usage(void)
18{
19    fprintf(stderr, "usage:  %s [-nrRv] pathname...\n", progname);
20    exit(1);
21}
22
23static int restore(const char *pathname, const struct stat *sb)
24{
25    char *oldcontext, *newcontext;
26
27    if (lgetfilecon(pathname, &oldcontext) < 0) {
28        fprintf(stderr, "Could not get context of %s:  %s\n",
29                pathname, strerror(errno));
30        return -1;
31    }
32    if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) {
33        fprintf(stderr, "Could not lookup context for %s:  %s\n", pathname,
34                strerror(errno));
35        return -1;
36    }
37    if (strcmp(newcontext, "<<none>>") &&
38        strcmp(oldcontext, newcontext)) {
39        if (verbose)
40            printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext);
41        if (!nochange) {
42            if (lsetfilecon(pathname, newcontext) < 0) {
43                fprintf(stderr, "Could not label %s with %s:  %s\n",
44                        pathname, newcontext, strerror(errno));
45                return -1;
46            }
47        }
48    }
49    freecon(oldcontext);
50    freecon(newcontext);
51    return 0;
52}
53
54int restorecon_main(int argc, char **argv)
55{
56    int ch, recurse = 0, ftsflags = FTS_PHYSICAL;
57    int i = 0;
58
59    progname = argv[0];
60
61    do {
62        ch = getopt(argc, argv, "nrRv");
63        if (ch == EOF)
64            break;
65        switch (ch) {
66        case 'n':
67            nochange = 1;
68            break;
69        case 'r':
70        case 'R':
71            recurse = 1;
72            break;
73        case 'v':
74            verbose = 1;
75            break;
76        default:
77            usage();
78        }
79    } while (1);
80
81    argc -= optind;
82    argv += optind;
83    if (!argc)
84        usage();
85
86    sehandle = selinux_android_file_context_handle();
87
88    if (!sehandle) {
89        fprintf(stderr, "Could not load file_contexts:  %s\n",
90                strerror(errno));
91        return -1;
92    }
93
94    if (recurse) {
95        FTS *fts;
96        FTSENT *ftsent;
97        fts = fts_open(argv, ftsflags, NULL);
98        if (!fts) {
99            fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n",
100                    argv[0], strerror(errno));
101            return -1;
102        }
103        while ((ftsent = fts_read(fts))) {
104            switch (ftsent->fts_info) {
105            case FTS_DP:
106                break;
107            case FTS_DNR:
108            case FTS_ERR:
109            case FTS_NS:
110                fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path,
111                        strerror(errno));
112                fts_set(fts, ftsent, FTS_SKIP);
113                break;
114            default:
115                if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
116                    fts_set(fts, ftsent, FTS_SKIP);
117                break;
118            }
119        }
120    } else {
121        int i, rc;
122        struct stat sb;
123
124        for (i = 0; i < argc; i++) {
125            rc = lstat(argv[i], &sb);
126            if (rc < 0) {
127                fprintf(stderr, "Could not stat %s:  %s\n", argv[i],
128                        strerror(errno));
129                continue;
130            }
131            restore(argv[i], &sb);
132        }
133    }
134
135    return 0;
136}
137