#include <getopt.h>
#include <errno.h>
#include <libgen.h>
+#include <dirent.h>
+
#include "config.h"
static const char usage[] =
"Options:\n"
" -v --version output version information and exit\n"
" -h --help output usage information and exit\n"
- " -a --access set/remove "XATTR_NAME_SMACK"\n"
- " -e --exec set/remove "XATTR_NAME_SMACKEXEC"\n"
- " -m --mmap set/remove "XATTR_NAME_SMACKMMAP"\n"
- " -t --transmute set/remove "XATTR_NAME_SMACKTRANSMUTE"\n"
+ " -a --access set "XATTR_NAME_SMACK"\n"
+ " -e --exec set "XATTR_NAME_SMACKEXEC"\n"
+ " -m --mmap set "XATTR_NAME_SMACKMMAP"\n"
+ " -t --transmute set "XATTR_NAME_SMACKTRANSMUTE"\n"
" -L --dereference tell to follow the symbolic links\n"
" -D --drop remove unset attributes\n"
" -A --drop-access remove "XATTR_NAME_SMACK"\n"
" -E --drop-exec remove "XATTR_NAME_SMACKEXEC"\n"
" -M --drop-mmap remove "XATTR_NAME_SMACKMMAP"\n"
" -T --drop-transmute remove "XATTR_NAME_SMACKTRANSMUTE"\n"
+ " -r --recursive list or modify also files in subdirectories\n"
"Obsolete option:\n"
" -d --remove tell to remove the attribute\n"
;
-static const char shortoptions[] = "vha::e::m::tdLDAEMT";
+static const char shortoptions[] = "vha::e::m::tdLDAEMTr";
static struct option options[] = {
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"drop-exec", no_argument, 0, 'E'},
{"drop-mmap", no_argument, 0, 'M'},
{"drop-transmute", no_argument, 0, 'T'},
+ {"recursive", no_argument, 0, 'r'},
{"remove", no_argument, 0, 'd'},
{NULL, 0, 0, 0}
};
static struct labelset mmap_set = { unset, NULL }; /* for option "mmap" */
static enum state transmute_flag = unset; /* for option "transmute" */
static enum state follow_flag = unset; /* for option "dereference" */
+static enum state recursive_flag = unset; /* for option "recursive" */
/* get the option for the given char */
static struct option *option_by_char(int car)
int rc;
switch (transmute_flag) {
case positive:
- rc = follow_flag ? stat(path, &st) : lstat(path, &st);
+ rc = follow_flag ? stat(path, &st) : lstat(path, &st);
if (rc < 0)
perror(path);
else if (!S_ISDIR(st.st_mode)) {
- fprintf(stderr, "%s: transmute: not a directory\n",
- path);
+ if (!recursive_flag) {
+ fprintf(stderr,
+ "%s: transmute: not a directory\n",
+ path);
+ }
}
else {
rc = smack_set_label_for_path(path,
{
int rc;
char *label;
+ int n = 0;
/* Print file path. */
printf("%s", path);
if (rc > 0) {
printf(" access=\"%s\"", label);
free(label);
- }
- else if (errno != 0) {
- printf(": %s", strerror(errno));
+ n = 1;
}
rc = (int)smack_new_label_from_path(path,
if (rc > 0) {
printf(" execute=\"%s\"", label);
free(label);
+ n = 1;
}
rc = (int)smack_new_label_from_path(path,
if (rc > 0) {
printf(" mmap=\"%s\"", label);
free(label);
+ n = 1;
}
rc = (int)smack_new_label_from_path(path,
if (rc > 0) {
printf(" transmute=\"%s\"", label);
free(label);
+ n = 1;
}
- printf("\n");
+ printf(n ? "\n" : ": No smack property found\n");
+}
+
+static void explore(const char *path, void (*fun)(const char*), int follow)
+{
+ struct stat st;
+ int rc;
+ char *file;
+ size_t last, length, l;
+ DIR *dir;
+ struct dirent dent, *pent;
+
+ /* type of the path */
+ rc = (follow ? stat : lstat)(path ? path : ".", &st);
+ if (rc < 0) {
+ perror(path);
+ return;
+ }
+
+ /* no a directory, skip */
+ if (!S_ISDIR(st.st_mode))
+ return;
+
+ /* open the directory */
+ dir = opendir(path ? path : ".");
+ if (dir == NULL) {
+ perror(path);
+ return;
+ }
+
+ /* iterate ove the directory's entries */
+ last = path ? strlen(path) : 0;
+ length = last + 100;
+ file = malloc(length);
+ if (file == NULL) {
+ fprintf(stderr, "error: out of memory.\n");
+ exit(1);
+ }
+ if (last != 0) {
+ memcpy(file, path, last);
+ file[last++] = '/';
+ }
+ for(;;) {
+ rc = readdir_r(dir, &dent, &pent);
+ if (rc != 0 || pent == NULL) {
+ free(file);
+ closedir(dir);
+ return;
+ }
+ l = strlen(dent.d_name);
+ if (l && dent.d_name[0] == '.'
+ && (l == 1 || l == 2 && dent.d_name[1] == '.'))
+ continue;
+ if (last + l >= length) {
+ file = realloc(file, last + l + 20);
+ if (file == NULL) {
+ fprintf(stderr, "error: out of memory.\n");
+ exit(1);
+ }
+ length = last + l + 20;
+ }
+ memcpy(file + last, dent.d_name, l + 1);
+ fun(file);
+ if (recursive_flag)
+ explore(file, fun, 0);
+ }
}
/* set the state to to */
case 'L':
set_state(&follow_flag, positive, c, 0);
break;
+ case 'r':
+ set_state(&recursive_flag, positive, c, 0);
+ break;
case 'v':
printf("%s (libsmack) version " PACKAGE_VERSION "\n",
basename(argv[0]));
/* process */
fun = modify ? modify_file : print_file;
- for (i = optind; i < argc; i++)
- fun(argv[i]);
+ if (optind == argc) {
+ explore(NULL, fun, 0);
+ }
+ else {
+ for (i = optind; i < argc; i++) {
+ fun(argv[i]);
+ if (recursive_flag)
+ explore(argv[i], fun, 1);
+ }
+ }
exit(0);
}