diff options
-rw-r--r-- | src/libmdsserver/fd-table.c | 64 | ||||
-rw-r--r-- | src/libmdsserver/macros.h | 21 | ||||
-rw-r--r-- | src/mds-server/mds-server.c | 359 | ||||
-rw-r--r-- | src/mds.c | 260 |
4 files changed, 352 insertions, 352 deletions
diff --git a/src/libmdsserver/fd-table.c b/src/libmdsserver/fd-table.c index 9fe62ca..eb681f9 100644 --- a/src/libmdsserver/fd-table.c +++ b/src/libmdsserver/fd-table.c @@ -147,51 +147,53 @@ size_t fd_table_get(const fd_table_t* restrict this, int key) */ size_t fd_table_put(fd_table_t* restrict this, int key, size_t value) { + /* Override current value if the key is already used. */ if (fd_table_contains_key(this, key)) { size_t rc = fd_table_get(this, key); this->values[key] = value; return rc; } - else + + /* Grow the table if it is too small. */ + errno = 0; + if ((size_t)key >= this->capacity) { - errno = 0; - if ((size_t)key >= this->capacity) + size_t* old_values = this->values; + size_t old_bitcap, new_bitcap; + this->values = realloc(this->values, (this->capacity << 1) * sizeof(size_t)); + if (this->values == NULL) + { + this->values = old_values; + return 0; + } + + memset(this->values + this->capacity, 0, this->capacity * sizeof(size_t)); + + old_bitcap = (this->capacity + 63) / 64; + this->capacity <<= 1; + new_bitcap = (this->capacity + 63) / 64; + + if (new_bitcap > old_bitcap) { - size_t* old_values = this->values; - size_t old_bitcap, new_bitcap; - this->values = realloc(this->values, (this->capacity << 1) * sizeof(size_t)); - if (this->values == NULL) + uint64_t* old_used = this->used; + this->used = realloc(this->used, new_bitcap * sizeof(size_t)); + if (this->used == NULL) { - this->values = old_values; + this->used = old_used; + this->capacity >>= 1; return 0; } - memset(this->values + this->capacity, 0, this->capacity * sizeof(size_t)); - - old_bitcap = (this->capacity + 63) / 64; - this->capacity <<= 1; - new_bitcap = (this->capacity + 63) / 64; - - if (new_bitcap > old_bitcap) - { - uint64_t* old_used = this->used; - this->used = realloc(this->used, new_bitcap * sizeof(size_t)); - if (this->used == NULL) - { - this->used = old_used; - this->capacity >>= 1; - return 0; - } - - memset(this->used + old_bitcap, 0, (new_bitcap - old_bitcap) * sizeof(uint64_t)); - } + memset(this->used + old_bitcap, 0, (new_bitcap - old_bitcap) * sizeof(uint64_t)); } - this->used[key / 64] |= (uint64_t)1 << (key % 64); - this->values[key] = value; - this->size++; - return 0; } + + /* Store the entry. */ + this->used[key / 64] |= (uint64_t)1 << (key % 64); + this->values[key] = value; + this->size++; + return 0; } diff --git a/src/libmdsserver/macros.h b/src/libmdsserver/macros.h index d70afc9..1623950 100644 --- a/src/libmdsserver/macros.h +++ b/src/libmdsserver/macros.h @@ -276,7 +276,7 @@ * * @param var The variable to which to assign the allocation * @param elements The number of elements to allocate - * @parma type The data type of the elements for which to create an allocation + * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ #define xmalloc(var, elements, type) \ @@ -288,12 +288,29 @@ * * @param var The variable to which to assign the allocation * @param elements The number of elements to allocate - * @parma type The data type of the elements for which to create an allocation + * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ #define xcalloc(var, elements, type) \ ((var = calloc(elements, sizeof(type))) == NULL) +/** + * Go to the label `pfail` if a condition is met + * + * @param CONDITION The condition + */ +#define fail_if(CONDITION) if (CONDITION) goto pfail + + +/** + * Run a set of instructions and return 1 if a condition is met + * + * @param CONDITION The condition + * @param INSTRUCTIONS The instruction (semicolon-terminated) + */ +#define exit_if(CONDITION, INSTRUCTIONS) if (CONDITION) { INSTRUCTIONS return 1; } + + #endif diff --git a/src/mds-server/mds-server.c b/src/mds-server/mds-server.c index 8bb7b83..039a478 100644 --- a/src/mds-server/mds-server.c +++ b/src/mds-server/mds-server.c @@ -159,17 +159,12 @@ int main(int argc_, char** argv_) #endif -#define exit_if(CONDITION, INSTRUCTION) if (CONDITION) { INSTRUCTION return 1; } - - argc = argc_; argv = argv_; /* Drop privileges like it's hot. */ - if (drop_privileges()) - goto pfail; - + fail_if (drop_privileges()); /* Sanity check the number of command line arguments. */ exit_if (argc > ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT, @@ -218,15 +213,12 @@ int main(int argc_, char** argv_) eprint("missing socket file descriptor argument.");); -#undef exit_if - - /* Run mdsinitrc. */ if (is_respawn == 0) { pid_t pid = fork(); - if (pid == (pid_t)-1) - goto pfail; + fail_if (pid == (pid_t)-1); + if (pid == 0) /* Child process exec:s, the parent continues without waiting for it. */ { /* Close all files except stdin, stdout and stderr. */ @@ -247,36 +239,34 @@ int main(int argc_, char** argv_) if (I >= 5) pthread_cond_destroy(&modify_cond); \ if (I >= 6) hash_table_destroy(&modify_map, NULL, NULL) -#define __error(I) perror(*argv); __free(I); return 1 - +#define error_if(I, CONDITION) if (CONDITION) { perror(*argv); __free(I); return 1; } /* Create list and table of clients. */ if (reexec == 0) { - if (fd_table_create(&client_map)) { __error(0); } - if (linked_list_create(&client_list, 32)) { __error(1); } + error_if (0, fd_table_create(&client_map)); + error_if (1, linked_list_create(&client_list, 32)); } - /* Store the current thread so it can be killed from elsewhere. */ master_thread = pthread_self(); /* Make the server update without all slaves dying on SIGUSR1. */ - if (xsigaction(SIGUSR1, sigusr1_trap) < 0) { __error(1); } + error_if (1, xsigaction(SIGUSR1, sigusr1_trap) < 0); /* Implement clean exit on SIGTERM. */ - if (xsigaction(SIGTERM, sigterm_trap) < 0) { __error(1); } + error_if (1, xsigaction(SIGTERM, sigterm_trap) < 0); /* Create mutex and condition for slave counter. */ - if ((errno = pthread_mutex_init(&slave_mutex, NULL))) { __error(1); } - if ((errno = pthread_cond_init(&slave_cond, NULL))) { __error(2); } + error_if (1, (errno = pthread_mutex_init(&slave_mutex, NULL))); + error_if (2, (errno = pthread_cond_init(&slave_cond, NULL))); /* Create mutex, condition and map for message modification. */ - if ((errno = pthread_mutex_init(&modify_mutex, NULL))) { __error(3); } - if ((errno = pthread_cond_init(&modify_cond, NULL))) { __error(4); } - if (hash_table_create(&modify_map)) { __error(5); } - -#undef __error + error_if (3, (errno = pthread_mutex_init(&modify_mutex, NULL))); + error_if (4, (errno = pthread_cond_init(&modify_cond, NULL))); + error_if (5, hash_table_create(&modify_map)); + +#undef error_if /* Unmarshal the state of the server. */ @@ -289,11 +279,7 @@ int main(int argc_, char** argv_) /* Acquire access to marshalled data. */ xsnprintf(shm_path, SHM_PATH_PATTERN, (unsigned long int)pid); reexec_fd = shm_open(shm_path, O_RDONLY, S_IRWXU); - if (reexec_fd < 0) - { - perror(*argv); - abort(); /* Critical. */ - } + fail_if (reexec_fd < 0); /* Critical. */ /* Unmarshal state. */ r = unmarshal_server(reexec_fd); close(reexec_fd); @@ -337,7 +323,7 @@ int main(int argc_, char** argv_) } /* Increase number of running slaves. */ - with_mutex(slave_mutex, running_slaves++;); + with_mutex (slave_mutex, running_slaves++;); /* Start slave thread. */ create_slave(&slave_thread, client_fd); @@ -349,9 +335,9 @@ int main(int argc_, char** argv_) goto reexec; /* Join with all slaves threads. */ - with_mutex(slave_mutex, - while (running_slaves > 0) - pthread_cond_wait(&slave_cond, &slave_mutex);); + with_mutex (slave_mutex, + while (running_slaves > 0) + pthread_cond_wait(&slave_cond, &slave_mutex);); /* Release resources. */ __free(9999); @@ -369,9 +355,9 @@ int main(int argc_, char** argv_) ssize_t node; /* Join with all slaves threads. */ - with_mutex(slave_mutex, - while (running_slaves > 0) - pthread_cond_wait(&slave_cond, &slave_mutex);); + with_mutex (slave_mutex, + while (running_slaves > 0) + pthread_cond_wait(&slave_cond, &slave_mutex);); /* Release resources. */ pthread_mutex_destroy(&slave_mutex); @@ -383,8 +369,7 @@ int main(int argc_, char** argv_) /* Marshal the state of the server. */ xsnprintf(shm_path, SHM_PATH_PATTERN, (unsigned long int)pid); reexec_fd = shm_open(shm_path, O_RDWR | O_CREAT | O_EXCL, S_IRWXU); - if (reexec_fd < 0) - goto pfail; + fail_if (reexec_fd < 0); if (marshal_server(reexec_fd) < 0) goto reexec_fail; close(reexec_fd); @@ -439,8 +424,7 @@ void* slave_loop(void* data) if (information == NULL) { /* Create information table. */ - if (xmalloc(information, 1, client_t)) - goto pfail; + fail_if (xmalloc(information, 1, client_t)); /* NULL-out pointers and initialisation markers. */ information->interception_conditions = NULL; @@ -479,8 +463,7 @@ void* slave_loop(void* data) information->interception_conditions_count = 0; information->send_pending_size = 0; information->multicasts_count = 0; - if (mds_message_initialise(&(information->message))) - goto pfail; + fail_if (mds_message_initialise(&(information->message))); } @@ -488,21 +471,21 @@ void* slave_loop(void* data) information->thread = pthread_self(); /* Create mutex to make sure two thread to not try to send messages concurrently, and other slave local actions. */ - if ((errno = pthread_mutex_init(&(information->mutex), NULL))) goto pfail; + fail_if ((errno = pthread_mutex_init(&(information->mutex), NULL))); information->mutex_created = 1; /* Create mutex and codition for multicast interception replies. */ - if ((errno = pthread_mutex_init(&(information->modify_mutex), NULL))) goto pfail; + fail_if ((errno = pthread_mutex_init(&(information->modify_mutex), NULL))); information->modify_mutex_created = 1; - if ((errno = pthread_cond_init(&(information->modify_cond), NULL))) goto pfail; + fail_if ((errno = pthread_cond_init(&(information->modify_cond), NULL))); information->modify_cond_created = 1; /* Make the server update without all slaves dying on SIGUSR1. */ - if (xsigaction(SIGUSR1, sigusr1_trap) < 0) goto pfail; + fail_if (xsigaction(SIGUSR1, sigusr1_trap) < 0); /* Implement clean exit on SIGTERM. */ - if (xsigaction(SIGTERM, sigterm_trap) < 0) goto pfail; + fail_if (xsigaction(SIGTERM, sigterm_trap) < 0); /* Fetch messages from the slave. */ @@ -512,19 +495,19 @@ void* slave_loop(void* data) if (information->multicasts_count > 0) { multicast_t multicast; - with_mutex(information->mutex, - if (information->multicasts_count > 0) - { - size_t c = (information->multicasts_count -= 1) * sizeof(multicast_t); - multicast = information->multicasts[0]; - memmove(information->multicasts, information->multicasts + 1, c); - if (c == 0) - { - free(information->multicasts); - information->multicasts = NULL; - } - } - ); + with_mutex (information->mutex, + if (information->multicasts_count > 0) + { + size_t c = (information->multicasts_count -= 1) * sizeof(multicast_t); + multicast = information->multicasts[0]; + memmove(information->multicasts, information->multicasts + 1, c); + if (c == 0) + { + free(information->multicasts); + information->multicasts = NULL; + } + } + ); multicast_message(&multicast); multicast_destroy(&multicast); } @@ -538,20 +521,20 @@ void* slave_loop(void* data) n = information->send_pending_size; information->send_pending_size = 0; information->send_pending = NULL; - with_mutex(information->mutex, - while (n > 0) - { - sent = send_message(information->socket_fd, sendbuf_, n); - if ((sent < n) && (errno != EINTR)) /* Ignore EINTR */ - { - perror(*argv); - break; - } - n -= sent; - sendbuf_ += sent / sizeof(char); - } - free(sendbuf); - ); + with_mutex (information->mutex, + while (n > 0) + { + sent = send_message(information->socket_fd, sendbuf_, n); + if ((sent < n) && (errno != EINTR)) /* Ignore EINTR */ + { + perror(*argv); + break; + } + n -= sent; + sendbuf_ += sent / sizeof(char); + } + free(sendbuf); + ); } /* Fetch message. */ @@ -615,12 +598,12 @@ void* slave_loop(void* data) client_destroy(information); /* Unlist client and decrease the slave count. */ - with_mutex(slave_mutex, - fd_table_remove(&client_map, socket_fd); - if (entry != LINKED_LIST_UNUSED) - linked_list_remove(&client_list, entry); - running_slaves--; - pthread_cond_signal(&slave_cond);); + with_mutex (slave_mutex, + fd_table_remove(&client_map, socket_fd); + if (entry != LINKED_LIST_UNUSED) + linked_list_remove(&client_list, entry); + running_slaves--; + pthread_cond_signal(&slave_cond);); return NULL; @@ -635,9 +618,9 @@ void* slave_loop(void* data) this is done because re-exec causes a race-condition between the acception of a slave and the execution of the the slave thread. */ - with_mutex(slave_mutex, - running_slaves--; - pthread_cond_signal(&slave_cond);); + with_mutex (slave_mutex, + running_slaves--; + pthread_cond_signal(&slave_cond);); return NULL; } @@ -736,7 +719,7 @@ int message_received(client_t* client) } done: pthread_mutex_unlock(&(modify_mutex)); - with_mutex(client->modify_mutex, pthread_cond_signal(&(client->modify_cond));); + with_mutex (client->modify_mutex, pthread_cond_signal(&(client->modify_cond));); /* Do nothing more, not not even multicast this message. */ return 0; @@ -753,10 +736,10 @@ int message_received(client_t* client) if (assign_id && (client->id == 0)) { intercept |= 2; - with_mutex(slave_mutex, - client->id = next_id++; - if (next_id == 0) - { + with_mutex (slave_mutex, + client->id = next_id++; + if (next_id == 0) + { eprint("this is impossible, ID counter has overflowed."); /* If the program ran for a millennium it would take c:a 585 assignments per nanosecond. This @@ -764,8 +747,8 @@ int message_received(client_t* client) dedication by generations of ponies (or just an alicorn) to maintain the process and transfer it new hardware.) */ abort(); - } - ); + } + ); } /* Make the client listen for messages addressed to it. */ @@ -879,29 +862,29 @@ int message_received(client_t* client) /* Queue message to be sent when this function returns. This done to simplify `multicast_message` for re-exec. */ - with_mutex(client->mutex, - if (client->send_pending_size == 0) - { - /* Set the pending message. */ - client->send_pending = msgbuf; - client->send_pending_size = n; - } - else - { - /* Concatenate message to already pending messages. */ - size_t new_len = client->send_pending_size + n; - char* msg_new = realloc(client->send_pending, new_len * sizeof(char)); - if (msg_new != NULL) - { - memcpy(msg_new + client->send_pending_size, msgbuf, n * sizeof(char)); - client->send_pending = msg_new; - client->send_pending_size = new_len; - } - else - perror(*argv); - free(msgbuf); - } - ); + with_mutex (client->mutex, + if (client->send_pending_size == 0) + { + /* Set the pending message. */ + client->send_pending = msgbuf; + client->send_pending_size = n; + } + else + { + /* Concatenate message to already pending messages. */ + size_t new_len = client->send_pending_size + n; + char* msg_new = realloc(client->send_pending, new_len * sizeof(char)); + if (msg_new != NULL) + { + memcpy(msg_new + client->send_pending_size, msgbuf, n * sizeof(char)); + client->send_pending = msg_new; + client->send_pending_size = new_len; + } + else + perror(*argv); + free(msgbuf); + } + ); } return 0; @@ -1188,11 +1171,11 @@ void queue_message_multicast(char* message, size_t length, client_t* sender) qsort(interceptions, interceptions_count, sizeof(queued_interception_t), cmp_queued_interception); /* Add prefix to message with ‘Modify ID’ header. */ - with_mutex(slave_mutex, - modify_id = next_modify_id++; - if (next_modify_id == 0) - next_modify_id = 1; - ); + with_mutex (slave_mutex, + modify_id = next_modify_id++; + if (next_modify_id == 0) + next_modify_id = 1; + ); xsnprintf(modify_id_header, "Modify ID: %" PRIu64 "\n", modify_id); n = strlen(modify_id_header); old_buf = message; @@ -1213,24 +1196,24 @@ void queue_message_multicast(char* message, size_t length, client_t* sender) message = NULL; /* Queue message multicasting. */ - with_mutex(sender->mutex, - if (sender->multicasts == NULL) - { - if (xmalloc(sender->multicasts, 1, multicast_t)) - goto fail_queue; - } - else - { - multicast_t* new_buf; - new_buf = realloc(sender->multicasts, (sender->multicasts_count + 1) * sizeof(multicast_t)); - if (new_buf == NULL) - goto fail_queue; - sender->multicasts = new_buf; - } - sender->multicasts[sender->multicasts_count++] = *multicast; - multicast = NULL; - fail_queue: - ); + with_mutex (sender->mutex, + if (sender->multicasts == NULL) + { + if (xmalloc(sender->multicasts, 1, multicast_t)) + goto fail_queue; + } + else + { + multicast_t* new_buf; + new_buf = realloc(sender->multicasts, (sender->multicasts_count + 1) * sizeof(multicast_t)); + if (new_buf == NULL) + goto fail_queue; + sender->multicasts = new_buf; + } + sender->multicasts[sender->multicasts_count++] = *multicast; + multicast = NULL; + fail_queue: + ); errno = 0; fail: /* This is done before this function returns even if there was no error. */ @@ -1277,7 +1260,7 @@ void multicast_message(multicast_t* multicast) if (client == NULL) { size_t address; - with_mutex(slave_mutex, address = fd_table_get(&client_map, client_.socket_fd);); + with_mutex (slave_mutex, address = fd_table_get(&client_map, client_.socket_fd);); client_.client = client = (client_t*)(void*)address; } @@ -1289,23 +1272,23 @@ void multicast_message(multicast_t* multicast) } /* Send the message. */ - with_mutex(client->mutex, - errno = 0; - n *= sizeof(char); - if (client->open) - while (n > 0) - { - sent = send_message(client->socket_fd, msg + multicast->message_ptr, n); - if (sent < n) - { - if (errno != EINTR) - perror(*argv); - break; - } - n -= sent; - multicast->message_ptr += sent / sizeof(char); - } - ); + with_mutex (client->mutex, + errno = 0; + n *= sizeof(char); + if (client->open) + while (n > 0) + { + sent = send_message(client->socket_fd, msg + multicast->message_ptr, n); + if (sent < n) + { + if (errno != EINTR) + perror(*argv); + break; + } + n -= sent; + multicast->message_ptr += sent / sizeof(char); + } + ); /* Stop if we are re-exec:ing, or continue to next recipient on error. */ if (n > 0) @@ -1339,25 +1322,25 @@ void multicast_message(multicast_t* multicast) mds_message_t* mod; /* Wait for a reply. */ - with_mutex(modify_mutex, - if (client->modify_message == NULL) - { - if (hash_table_contains_key(&modify_map, (size_t)modify_id) == 0) - { - hash_table_put(&modify_map, (size_t)modify_id, (size_t)(void*)client); - pthread_cond_signal(&slave_cond); - } - } - ); - with_mutex(client->modify_mutex, - if (client->modify_message == NULL) - { - while ((client->modify_message == NULL) && (terminating == 0)) - pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); - if (terminating == 0) - hash_table_remove(&modify_map, (size_t)modify_id); - } - ); + with_mutex (modify_mutex, + if (client->modify_message == NULL) + { + if (hash_table_contains_key(&modify_map, (size_t)modify_id) == 0) + { + hash_table_put(&modify_map, (size_t)modify_id, (size_t)(void*)client); + pthread_cond_signal(&slave_cond); + } + } + ); + with_mutex (client->modify_mutex, + if (client->modify_message == NULL) + { + while ((client->modify_message == NULL) && (terminating == 0)) + pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); + if (terminating == 0) + hash_table_remove(&modify_map, (size_t)modify_id); + } + ); if (terminating) return; @@ -1457,7 +1440,7 @@ void run_initrc(char** args) /* Test /etc. */ __exec("%s/%s", SYSCONFDIR, INITRC_FILE); -#undef __exec +#undef __exec /* Everything failed. */ eprintf("unable to run %s file, you might as well kill me.", INITRC_FILE); @@ -1513,13 +1496,13 @@ void signal_all(int signo) if (pthread_equal(current_thread, master_thread) == 0) pthread_kill(master_thread, signo); - with_mutex(slave_mutex, - foreach_linked_list_node (client_list, node) - { - client_t* value = (client_t*)(void*)(client_list.values[node]); - if (pthread_equal(current_thread, value->thread) == 0) - pthread_kill(value->thread, signo); - }); + with_mutex (slave_mutex, + foreach_linked_list_node (client_list, node) + { + client_t* value = (client_t*)(void*)(client_list.values[node]); + if (pthread_equal(current_thread, value->thread) == 0) + pthread_kill(value->thread, signo); + }); } @@ -1691,6 +1674,7 @@ int unmarshal_server(int fd) if (errno) goto clients_fail; + /* Delayed seeking. */ state_buf_ += n / sizeof(char); @@ -1725,12 +1709,13 @@ int unmarshal_server(int fd) free(state_buf); /* Remove non-found elements from the fd table. */ +#define __bit(I, _OP_) client_map.used[I / 64] _OP_ ((uint64_t)1 << (I % 64)) if (with_error) for (i = 0; i < client_map.capacity; i++) - if (client_map.used[i / 64] & ((uint64_t)1 << (i % 64))) + if ((__bit(i, &)) && (client_map.values[i] == 0)) /* Lets not presume that fd-table actually initialise its allocations. */ - if (client_map.values[i] == 0) - client_map.used[i / 64] &= ~((uint64_t)1 << (i % 64)); + __bit(i, &= ~); +#undef __bit /* Remap the linked list and remove non-found elements, and start the clients. */ foreach_linked_list_node (client_list, node) @@ -1747,7 +1732,7 @@ int unmarshal_server(int fd) int socket_fd = client->socket_fd; /* Increase number of running slaves. */ - with_mutex(slave_mutex, running_slaves++;); + with_mutex (slave_mutex, running_slaves++;); /* Start slave thread. */ create_slave(&slave_thread, socket_fd); @@ -1777,7 +1762,7 @@ int create_slave(pthread_t* thread_slot, int socket_fd) if ((errno = pthread_create(thread_slot, NULL, slave_loop, (void*)(intptr_t)socket_fd))) { perror(*argv); - with_mutex(slave_mutex, running_slaves--;); + with_mutex (slave_mutex, running_slaves--;); return -1; } if ((errno = pthread_detach(*thread_slot))) @@ -74,9 +74,6 @@ int main(int argc_, char** argv_) int j, r; -#define exit_if(CONDITION, INSTRUCTION) if (CONDITION) { INSTRUCTION return 1; } - - argc = argc_; argv = argv_; @@ -110,6 +107,7 @@ int main(int argc_, char** argv_) if (create_directory_root(MDS_RUNTIME_ROOT_DIRECTORY)) return 1; + /* Determine display index. */ for (display = 0; display < DISPLAY_MAX; display++) { @@ -137,11 +135,8 @@ int main(int argc_, char** argv_) eprint("sorry, too many displays on the system.");); /* Yes, the directory could have been removed, but it probably was not. */ -#undef exit_if - /* Create PID file. */ - if ((f = fopen(pathname, "w")) == NULL) - goto pfail; + fail_if ((f = fopen(pathname, "w")) == NULL); xsnprintf(piddata, "%u\n", getpid()); if (fwrite(piddata, 1, strlen(piddata), f) < strlen(piddata)) { @@ -156,15 +151,15 @@ int main(int argc_, char** argv_) perror(*argv); /* Create data storage directory. */ - if (create_directory_root(MDS_STORAGE_ROOT_DIRECTORY)) - goto fail; xsnprintf(pathname, "%s/%u.data", MDS_STORAGE_ROOT_DIRECTORY, display); - if (unlink_recursive(pathname) || create_directory_user(pathname)) - goto fail; + fail_if (create_directory_root(MDS_STORAGE_ROOT_DIRECTORY)); + fail_if (unlink_recursive(pathname)); + fail_if (create_directory_user(pathname)); + /* Save MDS_DISPLAY environment variable. */ xsnprintf(pathname, /* Excuse the reuse without renaming. */ - ":%u", display); + ":%u", display); setenv(DISPLAY_ENV, pathname, 1); /* Create display socket. */ @@ -173,13 +168,12 @@ int main(int argc_, char** argv_) strcpy(address.sun_path, pathname); unlink(pathname); fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fchmod(fd, S_IRWXU) < 0) goto pfail; - if (bind(fd, (struct sockaddr*)(&address), sizeof(address)) < 0) goto pfail; - if (chown(pathname, getuid(), NOBODY_GROUP_GID) < 0) goto pfail; + fail_if (fchmod(fd, S_IRWXU) < 0); + fail_if (bind(fd, (struct sockaddr*)(&address), sizeof(address)) < 0); + fail_if (chown(pathname, getuid(), NOBODY_GROUP_GID) < 0); /* Start listening on socket. */ - if (listen(fd, SOMAXCONN) < 0) - goto pfail; + fail_if (listen(fd, SOMAXCONN) < 0); /* Start master server and respawn it if it crashes. */ rc = spawn_and_respawn_server(fd); @@ -207,7 +201,6 @@ int main(int argc_, char** argv_) pfail: perror(*argv); - fail: rc = 1; goto done; } @@ -271,6 +264,25 @@ pid_t parse_pid_t(const char* str, size_t n) } + +/** + * Drop privileges and change execution image into the master server's image. + * This function will only return on error. + * + * @param child_args Command line arguments for the new image + */ +static void exec_master_server(char** child_args) +{ + /* Drop privileges. They most not be propagated non-authorised components. */ + /* setgid should not be set, but just to be safe we are restoring both user and group. */ + if (drop_privileges()) + return; + + /* Start master server. */ + execv(master_server, child_args); +} + + /** * Start master server and respawn it if it crashes * @@ -302,83 +314,68 @@ int spawn_and_respawn_server(int fd) # error LIBEXEC_ARGC_EXTRA_LIMIT is too small, need at least 2. #endif - for (;;) + + respawn: + + pid = fork(); + if (pid == (pid_t)-1) + goto pfail; + + if (pid == 0) /* Child. */ { - pid = fork(); - if (pid == (pid_t)-1) - { - perror(*argv); - goto fail; - } - - if (pid) - { - /* Get the current time. (Start of child process.) */ - time_error = (monotone(&time_start) < 0); - if (time_error) - perror(*argv); - - /* Wait for master server to die. */ - if (waitpid(pid, &status, 0) == (pid_t)-1) - { - perror(*argv); - goto fail; - } - - /* If the server exited normally or SIGTERM, do not respawn. */ - if (WIFEXITED(status) || (WEXITSTATUS(status) && WTERMSIG(status))) - break; - - /* Get the current time. (End of child process.) */ - time_error |= (monotone(&time_end) < 0); - - /* Do not respawn if we could not read the time. */ - if (time_error) - { - perror(*argv); - eprintf("%s died abnormally, not respawning because we could not read the time.", master_server); - goto fail; - } - - /* Respawn if the server did not die too fast. */ - if (time_end.tv_sec - time_start.tv_sec >= RESPAWN_TIME_LIMIT_SECONDS) - eprintf("%s died abnormally, respawning.", master_server); - else - { - eprintf("%s died abnormally, died too fast, not respawning.", master_server); - goto fail; - } - - if (first_spawn) - { - first_spawn = 0; - free(child_args[argc + 0]); - child_args[argc + 0] = strdup("--respawn"); - if (child_args[argc + 0] == NULL) - { - perror(*argv); - goto fail; - } - } - } - else - { - rc++; - /* Drop privileges. They most not be propagated non-authorised components. */ - /* setgid should not be set, but just to be safe we are restoring both user and group. */ - if (drop_privileges()) - { - perror(*argv); - goto fail; - } - - /* Start master server. */ - execv(master_server, child_args); - perror(*argv); - goto fail; - } + rc++; + exec_master_server(child_args); + goto pfail; + } + + + /* Parent. */ + + /* Get the current time. (Start of child process.) */ + if ((time_error = (monotone(&time_start) < 0))) + perror(*argv); + + /* Wait for master server to die. */ + if (waitpid(pid, &status, 0) == (pid_t)-1) + goto pfail; + + /* If the server exited normally or SIGTERM, do not respawn. */ + if (WIFEXITED(status) || (WEXITSTATUS(status) && WTERMSIG(status))) + goto done; /* Child exited normally, stop. */ + + /* Get the current time. (End of child process.) */ + time_error |= (monotone(&time_end) < 0); + + /* Do not respawn if we could not read the time. */ + if (time_error) + { + perror(*argv); + eprintf("%s died abnormally, not respawning because we could not read the time.", master_server); + goto fail; + } + + /* Respawn if the server did not die too fast. */ + if (time_end.tv_sec - time_start.tv_sec >= RESPAWN_TIME_LIMIT_SECONDS) + eprintf("%s died abnormally, respawning.", master_server); + else + { + eprintf("%s died abnormally, died too fast, not respawning.", master_server); + goto fail; } + if (first_spawn) + { + first_spawn = 0; + free(child_args[argc + 0]); + child_args[argc + 0] = strdup("--respawn"); + if (child_args[argc + 0] == NULL) + goto pfail; + } + + goto respawn; + + + done: rc--; fail: rc++; @@ -387,6 +384,10 @@ int spawn_and_respawn_server(int fd) if (rc == 2) _exit(1); return rc; + + pfail: + perror(*argv); + goto fail; } @@ -411,26 +412,22 @@ int create_directory_root(const char* pathname) } } else - { - /* Directory is missing, create it. */ - if (mkdir(pathname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) - { - if (errno != EEXIST) /* Unlikely race condition. */ - { - perror(*argv); - return 1; - } - } - else - /* Set ownership. */ - if (chown(pathname, ROOT_USER_UID, ROOT_GROUP_GID) < 0) - { - perror(*argv); - return 1; - } - } + /* Directory is missing, create it. */ + if (mkdir(pathname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + { + if (errno != EEXIST) /* Unlikely race condition. */ + goto pfail; + } + else + /* Set ownership. */ + if (chown(pathname, ROOT_USER_UID, ROOT_GROUP_GID) < 0) + goto pfail; return 0; + + pfail: + perror(*argv); + return 1; } @@ -496,37 +493,36 @@ int unlink_recursive(const char* pathname) int errno_ = errno; struct stat _attr; if (stat(pathname, &_attr) < 0) - return 0; + return 0; /* Directory does not exist. */ errno = errno_; - perror(*argv); - return 1; + goto pfail; } /* Remove the content of the directory. */ while ((file = readdir(dir)) != NULL) - if (strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) - if (unlink(file->d_name) < 0) - { - if (errno == EISDIR) - unlink_recursive(file->d_name); - else - { - perror(*argv); - rc = 1; - goto done; - } - eprint("pop"); - } + if (strcmp(file->d_name, ".") && + strcmp(file->d_name, "..") && + (unlink(file->d_name) < 0)) + { + if (errno != EISDIR) + goto pfail; + unlink_recursive(file->d_name); + eprint("pop"); + } /* Remvoe the drectory. */ if (rmdir(pathname) < 0) - { - perror(*argv); - rc = 1; - } + goto pfail; - done: - closedir(dir); + done: + if (dir != NULL) + closedir(dir); return rc; + + + pfail: + perror(*argv); + rc = -1; + goto done; } |