diff -ru policycoreutils-1.30.10.orig/restorecon/restorecon.c policycoreutils-1.30.10/restorecon/restorecon.c --- policycoreutils-1.30.10.orig/restorecon/restorecon.c 2006-05-23 20:20:02.000000000 +1000 +++ policycoreutils-1.30.10/restorecon/restorecon.c 2006-07-30 23:26:21.000000000 +1000 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,15 @@ #define STAT_BLOCK_SIZE 1 static int pipe_fds[2] = { -1, -1 }; +#define WORKER_SUCCESS 'g' +#define WORKER_FAILURE 'b' +int *worker_send_fds = NULL; +int *worker_recv_fds = NULL; +int num_workers = 0; +int max_worker_handle = 0; +int *worker_use_count = NULL; +#define MAX(XA, XB) ((XA) > (XB)) ? (XA) : (XB) + #define MAX_EXCLUDES 100 static int excludeCtr=0; struct edir { @@ -241,32 +251,244 @@ return 0; } +void get_worker_data(int finishing) +{ + int i, count; + fd_set read_set; + struct timeval tv; + tv.tv_sec = finishing ? 1 : 0; + tv.tv_usec = 0; + + FD_ZERO(&read_set); + for(i = 0; i < num_workers; i++) + FD_SET(worker_recv_fds[i], &read_set); + + count = select(max_worker_handle, &read_set, NULL, NULL, &tv); + if(count == 0) + return; + if(count == -1) + { + perror("Worker select error"); + exit(1); + } + for(i = 0; i < num_workers; i++) + { + if(FD_ISSET(worker_recv_fds[i], &read_set)) + { + char c; + int rc = read(worker_recv_fds[i], &c, 1); + if(rc != 1) + { + fprintf(stderr, "Error reading result from worker %d, aborting.\n", i); + exit(1); + } + if(c != WORKER_SUCCESS) + errors++; + worker_use_count[i]--; + count--; + } + } + if(count != 0) + { + fprintf(stderr, "Count should be 0!\n"); + exit(1); + } +} + static int apply_spec(const char *file, const struct stat *sb_unused __attribute__((unused)), int flag, struct FTW *s_unused __attribute__((unused))) { - char buf[STAT_BLOCK_SIZE]; - if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) - { - fprintf(stderr, "Read error on pipe.\n"); - pipe_fds[0] = -1; - } - if (flag == FTW_DNR) { - fprintf(stderr, "%s: unable to read directory %s\n", - progname, file); - return 0; - } - errors=errors+restore(file); - return 0; + char buf[STAT_BLOCK_SIZE]; + + if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) + { + fprintf(stderr, "Read error on pipe.\n"); + pipe_fds[0] = -1; + } + if (flag == FTW_DNR) { + fprintf(stderr, "%s: unable to read directory %s\n", + progname, file); + return 0; + } + if(num_workers) + { + int i, rc; + get_worker_data(0); + for(i = 0; i < num_workers; i++) + { + /* Have two entries in the queue for each worker so that if the master + starts doing some regex work the workers don't starve */ + if(worker_use_count[i] < 2) + { + int offset = 0, len = strlen(file) + 1; + + worker_use_count[i]++; + /* Could hurt performance if FILE_MAX*2 > the max pipe buffer */ + while(1) + { + rc = write(worker_send_fds[i], &file[offset], len - offset); + if(rc == -1) + { + fprintf(stderr, "Can't write to worker %d\n", i); + exit(1); + } + offset += rc; + if(offset == len) + return 0; + } + } + } + } + errors=errors+restore(file); + return 0; } + +int num_cpus() +{ + FILE *fp = fopen("/proc/cpuinfo", "r"); + char buf[1024]; + int num = 0; + + if(!fp) + return 1; + while(fgets(buf, sizeof(buf), fp)) + { + if(!strncmp(buf, "processor", 9)) + num++; + } + fclose(fp); + if(num < 1) + return 1; + return num; +} + +void worker_restore(int id, const char * const file, int fd_out) +{ + char res = WORKER_SUCCESS; + if(restore(file)) + { + res = WORKER_FAILURE; + } + if(write(fd_out, &res, 1) != 1) + { + fprintf(stderr, "Worker %d can't write to result pipe, aborting.\n", id); + exit(1); + } +} + +void worker(int id, int fd_in, int fd_out) +{ + char buf[PATH_MAX+1]; + int len = 0; + + while(1) + { + while(len == 0 || buf[len - 1] != '\0') + { + int string_len; + int rc = read(fd_in, buf + len, PATH_MAX - len); + if(rc == -1) + { + fprintf(stderr, "Worker %d exiting on read error.\n", id); + exit(1); + } + if(rc == 0) + exit(0); /* parent has exited */ + len += rc; + buf[len] = '\0'; + string_len = strlen(buf); + while(string_len != len) + { + worker_restore(id, buf, fd_out); + len = len - string_len - 1; + memmove(buf, buf + string_len + 1, len + 1); + string_len = strlen(buf); + } + if(len >= PATH_MAX) + { + fprintf(stderr, "Worker %d received excess data from parent.\n", id); + exit(1); + } + } + worker_restore(id, buf, fd_out); + len = 0; + } + if(len != 0) + { + fprintf(stderr, "Worker %d can't read from pipe, aborting.\n", id); + exit(1); + } + exit(0); +} + +void start_workers() +{ + int send_fds[2], recv_fds[2], i; + + num_workers = num_cpus() - 1; + if(!num_workers) + return; + worker_send_fds = malloc(sizeof(int) * num_workers); + worker_recv_fds = malloc(sizeof(int) * num_workers); + worker_use_count = malloc(sizeof(int) * num_workers); + if(!worker_send_fds || !worker_recv_fds || !worker_use_count) + { + fprintf(stderr, "Malloc failure.\n"); + exit(1); + } + + matchpathcon_init(NULL); + + for(i = 0; i < num_workers; i++) + { + int rc; + + if(pipe(send_fds) || pipe(recv_fds)) + { + fprintf(stderr, "Can't create pipe.\n"); + exit(1); + } + worker_send_fds[i] = send_fds[1]; + worker_recv_fds[i] = recv_fds[0]; + worker_use_count[i] = 0; + max_worker_handle = MAX(max_worker_handle, MAX(worker_send_fds[i], worker_recv_fds[i])); + rc = fork(); + if(rc == -1) + { + fprintf(stderr, "fork error\n"); + exit(1); + } + if(!rc) + { + int j; + for(j = i - 1; j >= 0; j--) + { + close(worker_send_fds[j]); + close(worker_recv_fds[j]); + } + close(send_fds[1]); + close(recv_fds[0]); + worker(i, send_fds[0], recv_fds[1]); + exit(2); /* should never reach this code */ + } + close(send_fds[0]); + close(recv_fds[1]); + } + max_worker_handle++; +} + void process(char *buf) { int rc; + if (recurse) { if(pipe(pipe_fds) == -1) - rc = -1; - else - rc = fork(); + { + fprintf(stderr, "Can't create pipe.\n"); + exit(1); + } + rc = fork(); if(rc == 0) { close(pipe_fds[0]); @@ -276,10 +498,25 @@ if(rc > 0) close(pipe_fds[1]); if(rc == -1 || rc > 0) { + start_workers(); if (nftw(buf, apply_spec, 1024, FTW_PHYS)) { fprintf(stderr, "%s: error while labeling files under %s\n", progname, buf); errors++; + } + if(rc > 0) + wait(&rc); + if(num_workers) + { + int i; + for(i = 0; i < num_workers; i++) + { + while(worker_use_count[i]) + get_worker_data(1); + close(worker_send_fds[i]); + close(worker_recv_fds[i]); + wait(&rc); + } } } } diff -ru policycoreutils-1.30.10.orig/setfiles/setfiles.c policycoreutils-1.30.10/setfiles/setfiles.c --- policycoreutils-1.30.10.orig/setfiles/setfiles.c 2006-05-23 20:20:03.000000000 +1000 +++ policycoreutils-1.30.10/setfiles/setfiles.c 2006-07-30 23:29:07.000000000 +1000 @@ -75,6 +75,7 @@ #include #include #include +#include static int add_assoc = 1; static FILE *outfile=NULL; @@ -82,6 +83,15 @@ #define STAT_BLOCK_SIZE 1 static int pipe_fds[2] = { -1, -1 }; +#define WORKER_SUCCESS 'g' +#define WORKER_FAILURE 'b' +int *worker_send_fds = NULL; +int *worker_recv_fds = NULL; +int num_workers = 0; +int max_worker_handle = 0; +int *worker_use_count = NULL; +#define MAX(XA, XB) ((XA) > (XB)) ? (XA) : (XB) + #define MAX_EXCLUDES 100 static int excludeCtr=0; struct edir { @@ -232,27 +242,57 @@ return (strcmp(rest_a, rest_b) == 0); } -/* - * Apply the last matching specification to a file. - * This function is called by nftw on each file during - * the directory traversal. - */ -static int apply_spec(const char *file, - const struct stat *sb_unused __attribute__((unused)), - int flag, - struct FTW *s_unused __attribute__((unused))) +void get_worker_data(int finishing) +{ + int i, count; + fd_set read_set; + struct timeval tv; + tv.tv_sec = finishing ? 1 : 0; + tv.tv_usec = 0; + + FD_ZERO(&read_set); + for(i = 0; i < num_workers; i++) + FD_SET(worker_recv_fds[i], &read_set); + + count = select(max_worker_handle, &read_set, NULL, NULL, &tv); + if(count == 0) + return; + if(count == -1) + { + perror("Worker select error"); + exit(1); + } + for(i = 0; i < num_workers; i++) + { + if(FD_ISSET(worker_recv_fds[i], &read_set)) + { + char c; + int rc = read(worker_recv_fds[i], &c, 1); + if(rc != 1) + { + fprintf(stderr, "Error reading result from worker %d, aborting.\n", i); + exit(1); + } +/* if(c != WORKER_SUCCESS) + errors++;*/ + worker_use_count[i]--; + count--; + } + } + if(count != 0) + { + fprintf(stderr, "Count should be 0!\n"); + exit(1); + } +} + +static int set_context(const char *file) { const char *my_file; struct stat my_sb; int i, j, ret; char *context, *newcon; int user_only_changed=0; - char buf[STAT_BLOCK_SIZE]; - if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) - { - fprintf(stderr, "Read error on pipe.\n"); - pipe_fds[0] = -1; - } /* Skip the extra slash at the beginning, if present. */ if (file[0] == '/' && file[1] == '/') @@ -260,12 +300,6 @@ else my_file = file; - if (flag == FTW_DNR) { - fprintf(stderr, "%s: unable to read directory %s\n", - progname, my_file); - return 0; - } - i = match(my_file, &my_sb, &newcon); if (i < 0) /* No matching specification. */ @@ -382,6 +416,198 @@ return -1; } +/* + * Apply the last matching specification to a file. + * This function is called by nftw on each file during + * the directory traversal. + */ +static int apply_spec(const char *file, + const struct stat *sb_unused __attribute__((unused)), + int flag, + struct FTW *s_unused __attribute__((unused))) +{ + char buf[STAT_BLOCK_SIZE]; + if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) + { + fprintf(stderr, "Read error on pipe.\n"); + pipe_fds[0] = -1; + } + + if (flag == FTW_DNR) + { + fprintf(stderr, "%s: unable to read directory %s\n", + progname, file); + return 0; + } + + if(num_workers) + { + int i, rc; + get_worker_data(0); + for(i = 0; i < num_workers; i++) + { + /* Have two entries in the queue for each worker so that if the master + starts doing some regex work the workers don't starve */ + if(worker_use_count[i] < 2) + { + int offset = 0, len = strlen(file) + 1; + + worker_use_count[i]++; + /* Could hurt performance if FILE_MAX*2 > the max pipe buffer */ + while(1) + { + rc = write(worker_send_fds[i], &file[offset], len - offset); + if(rc == -1) + { + fprintf(stderr, "Can't write to worker %d\n", i); + exit(1); + } + offset += rc; + if(offset == len) + return 0; + } + } + } + } + return set_context(file); +} + +int num_cpus() +{ + FILE *fp = fopen("/proc/cpuinfo", "r"); + char buf[1024]; + int num = 0; + + if(!fp) + return 1; + while(fgets(buf, sizeof(buf), fp)) + { + if(!strncmp(buf, "processor", 9)) + num++; + } + fclose(fp); + if(num < 1) + return 1; + return num; +} + +void worker_restore(int id, const char * const file, int fd_out) +{ + char res = WORKER_SUCCESS; + if(set_context(file)) + { + res = WORKER_FAILURE; + } + if(write(fd_out, &res, 1) != 1) + { + fprintf(stderr, "Worker %d can't write to result pipe, aborting.\n", id); + exit(1); + } +} + +void worker(int id, int fd_in, int fd_out) +{ + char buf[PATH_MAX+1]; + int len = 0; + + while(1) + { + while(len == 0 || buf[len - 1] != '\0') + { + int string_len; + int rc = read(fd_in, buf + len, PATH_MAX - len); + if(rc == -1) + { + fprintf(stderr, "Worker %d exiting on read error.\n", id); + exit(1); + } + if(rc == 0) + exit(0); /* parent has exited */ + len += rc; + buf[len] = '\0'; + string_len = strlen(buf); + while(string_len != len) + { + worker_restore(id, buf, fd_out); + len = len - string_len - 1; + memmove(buf, buf + string_len + 1, len + 1); + string_len = strlen(buf); + } + if(len >= PATH_MAX) + { + fprintf(stderr, "Worker %d received excess data from parent.\n", id); + exit(1); + } + } + worker_restore(id, buf, fd_out); + len = 0; + } + if(len != 0) + { + fprintf(stderr, "Worker %d can't read from pipe, aborting.\n", id); + exit(1); + } + exit(0); +} + +void start_workers() +{ + int send_fds[2], recv_fds[2], i; + + if(add_assoc) + return; + num_workers = num_cpus() - 1; + if(!num_workers) + return; + worker_send_fds = malloc(sizeof(int) * num_workers); + worker_recv_fds = malloc(sizeof(int) * num_workers); + worker_use_count = malloc(sizeof(int) * num_workers); + if(!worker_send_fds || !worker_recv_fds || !worker_use_count) + { + fprintf(stderr, "Malloc failure.\n"); + exit(1); + } + + matchpathcon_init(NULL); + + for(i = 0; i < num_workers; i++) + { + int rc; + + if(pipe(send_fds) || pipe(recv_fds)) + { + fprintf(stderr, "Can't create pipe.\n"); + exit(1); + } + worker_send_fds[i] = send_fds[1]; + worker_recv_fds[i] = recv_fds[0]; + worker_use_count[i] = 0; + max_worker_handle = MAX(max_worker_handle, MAX(worker_send_fds[i], worker_recv_fds[i])); + rc = fork(); + if(rc == -1) + { + fprintf(stderr, "fork error\n"); + exit(1); + } + if(!rc) + { + int j; + for(j = i - 1; j >= 0; j--) + { + close(worker_send_fds[j]); + close(worker_recv_fds[j]); + } + close(send_fds[1]); + close(recv_fds[0]); + worker(i, send_fds[0], recv_fds[1]); + exit(2); /* should never reach this code */ + } + close(send_fds[0]); + close(recv_fds[1]); + } + max_worker_handle++; +} + void set_rootpath(const char *arg) { int len; @@ -454,7 +680,7 @@ set_matchpathcon_flags(MATCHPATHCON_VALIDATE); /* Process any options. */ - while ((opt = getopt(argc, argv, "Fc:dlnqrsvWe:o:")) > 0) { + while ((opt = getopt(argc, argv, "aFc:dlnqrsvWe:o:")) > 0) { switch (opt) { case 'c': { @@ -529,6 +755,7 @@ break; case 's': use_stdin = 1; + case 'a': add_assoc = 0; break; case 'v': @@ -641,6 +868,7 @@ close(pipe_fds[1]); if(rc == -1 || rc > 0) { + start_workers(); /* Walk the file tree, calling apply_spec on each file. */ if (nftw (argv[optind], apply_spec, 1024, @@ -650,6 +878,20 @@ argv[0], argv[optind]); exit(1); } + if(rc > 0) + wait(&rc); + if(num_workers) + { + int i; + for(i = 0; i < num_workers; i++) + { + while(worker_use_count[i]) + get_worker_data(1); + close(worker_send_fds[i]); + close(worker_recv_fds[i]); + wait(&rc); + } + } } /*