Only in policycoreutils-1.30.10/restorecon: restorecon 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 01:05:36.000000000 +1000 @@ -50,6 +50,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 +250,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 +497,22 @@ 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(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]); + } + } } } } Only in policycoreutils-1.30.10/restorecon: restorecon.o