aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2014-05-18 04:27:39 +0200
committerMattias Andrée <maandree@operamail.com>2014-05-18 04:27:39 +0200
commitadc148d8a2fb538a3466d8483cc2315c1ab10955 (patch)
tree1fecaddd946bea84a9cf4cf859c7dd434f00650e
parentzealous use of * sizeof(char) when using mem* functions (diff)
downloadmds-adc148d8a2fb538a3466d8483cc2315c1ab10955.tar.gz
mds-adc148d8a2fb538a3466d8483cc2315c1ab10955.tar.bz2
mds-adc148d8a2fb538a3466d8483cc2315c1ab10955.tar.xz
reduce code complexity
Signed-off-by: Mattias Andrée <maandree@operamail.com>
-rw-r--r--src/mds-server/mds-server.c617
-rw-r--r--src/mds-server/mds-server.h9
-rw-r--r--src/mds.c212
-rw-r--r--src/mds.h21
4 files changed, 391 insertions, 468 deletions
diff --git a/src/mds-server/mds-server.c b/src/mds-server/mds-server.c
index 5b81222..8bb7b83 100644
--- a/src/mds-server/mds-server.c
+++ b/src/mds-server/mds-server.c
@@ -137,7 +137,6 @@ static pthread_cond_t modify_cond;
static hash_table_t modify_map;
-
/**
* Entry point of the server
*
@@ -160,24 +159,21 @@ 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())
- {
- perror(*argv);
- return 1;
- }
+ goto pfail;
/* Sanity check the number of command line arguments. */
- if (argc > ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT)
- {
- eprint("that number of arguments is ridiculous, I will not allow it.");
- return 1;
- }
+ exit_if (argc > ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT,
+ eprint("that number of arguments is ridiculous, I will not allow it."););
/* Parse command line arguments. */
@@ -187,26 +183,18 @@ int main(int argc_, char** argv_)
int v;
if ((v = strequals(arg, "--initial-spawn")) || /* Initial spawn? */
strequals(arg, "--respawn")) /* Respawning after crash? */
- if (is_respawn == v)
- {
- eprintf("conflicting arguments %s and %s cannot be combined.",
- "--initial-spawn", "--respawn");
- return 1;
- }
- else
+ {
+ exit_if (is_respawn == v,
+ eprintf("conflicting arguments %s and %s cannot be combined.",
+ "--initial-spawn", "--respawn"););
is_respawn = !v;
+ }
else if (startswith(arg, "--socket-fd=")) /* Socket file descriptor. */
{
- if (socket_fd != -1)
- {
- eprintf("duplicate declaration of %s.", "--socket-fd");
- return 1;
- }
- if (strict_atoi(arg += strlen("--socket-fd="), &socket_fd, 0, INT_MAX) < 0)
- {
- eprintf("invalid value for %s: %s.", "--socket-fd", arg);
- return 1;
- }
+ exit_if (socket_fd != -1,
+ eprintf("duplicate declaration of %s.", "--socket-fd"););
+ exit_if (strict_atoi(arg += strlen("--socket-fd="), &socket_fd, 0, INT_MAX) < 0,
+ eprintf("invalid value for %s: %s.", "--socket-fd", arg););
}
else if (strequals(arg, "--re-exec")) /* Re-exec state-marshal. */
reexec = 1;
@@ -223,17 +211,14 @@ int main(int argc_, char** argv_)
/* Check that manditory arguments have been specified. */
- if (is_respawn < 0)
- {
- eprintf("missing state argument, require either %s or %s.",
- "--initial-spawn", "--respawn");
- return 1;
- }
- if (socket_fd < 0)
- {
- eprint("missing socket file descriptor argument.");
- return 1;
- }
+ exit_if (is_respawn < 0,
+ eprintf("missing state argument, require either %s or %s.",
+ "--initial-spawn", "--respawn"););
+ exit_if (socket_fd < 0,
+ eprint("missing socket file descriptor argument."););
+
+
+#undef exit_if
/* Run mdsinitrc. */
@@ -241,16 +226,13 @@ int main(int argc_, char** argv_)
{
pid_t pid = fork();
if (pid == (pid_t)-1)
- {
- perror(*argv);
- return 1;
- }
+ goto pfail;
if (pid == 0) /* Child process exec:s, the parent continues without waiting for it. */
{
/* Close all files except stdin, stdout and stderr. */
close_files((fd > 2) || (fd == socket_fd));
- /* Run initrc */
+ /* Run mdsinitrc. */
run_initrc(unparsed_args);
return 1;
}
@@ -265,78 +247,36 @@ 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
+
/* Create list and table of clients. */
if (reexec == 0)
{
- if (fd_table_create(&client_map))
- {
- perror(*argv);
- __free(0);
- return 1;
- }
- if (linked_list_create(&client_list, 32))
- {
- perror(*argv);
- __free(1);
- return 1;
- }
+ if (fd_table_create(&client_map)) { __error(0); }
+ if (linked_list_create(&client_list, 32)) { __error(1); }
}
/* 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)
- {
- perror(*argv);
- __free(1);
- return 1;
- }
+ if (xsigaction(SIGUSR1, sigusr1_trap) < 0) { __error(1); }
/* Implement clean exit on SIGTERM. */
- if (xsigaction(SIGTERM, sigterm_trap) < 0)
- {
- perror(*argv);
- __free(1);
- return 1;
- }
+ if (xsigaction(SIGTERM, sigterm_trap) < 0) { __error(1); }
/* Create mutex and condition for slave counter. */
- if ((errno = pthread_mutex_init(&slave_mutex, NULL)) != 0)
- {
- perror(*argv);
- __free(1);
- return 1;
- }
- if ((errno = pthread_cond_init(&slave_cond, NULL)) != 0)
- {
- perror(*argv);
- __free(2);
- return 1;
- }
+ if ((errno = pthread_mutex_init(&slave_mutex, NULL))) { __error(1); }
+ if ((errno = pthread_cond_init(&slave_cond, NULL))) { __error(2); }
/* Create mutex, condition and map for message modification. */
- if ((errno = pthread_mutex_init(&modify_mutex, NULL)) != 0)
- {
- perror(*argv);
- __free(3);
- return 1;
- }
- if ((errno = pthread_cond_init(&modify_cond, NULL)) != 0)
- {
- perror(*argv);
- __free(4);
- return 1;
- }
- if (hash_table_create(&modify_map))
- {
- perror(*argv);
- __free(5);
- return 1;
- }
+ 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
/* Unmarshal the state of the server. */
@@ -400,15 +340,7 @@ int main(int argc_, char** argv_)
with_mutex(slave_mutex, running_slaves++;);
/* Start slave thread. */
- errno = pthread_create(&slave_thread, NULL, slave_loop, (void*)(intptr_t)client_fd);
- if (errno)
- {
- perror(*argv);
- with_mutex(slave_mutex, running_slaves--;);
- }
- errno = pthread_detach(slave_thread);
- if (errno)
- perror(*argv);
+ create_slave(&slave_thread, client_fd);
}
terminate:
@@ -424,10 +356,10 @@ int main(int argc_, char** argv_)
/* Release resources. */
__free(9999);
-#undef __free
-
return 0;
+#undef __free
+
reexec:
{
@@ -452,10 +384,7 @@ int main(int argc_, char** argv_)
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)
- {
- perror(*argv);
- return 1;
- }
+ goto pfail;
if (marshal_server(reexec_fd) < 0)
goto reexec_fail;
close(reexec_fd);
@@ -482,6 +411,10 @@ int main(int argc_, char** argv_)
be respawn if the re-exec fails. */
return 1;
}
+
+ pfail:
+ perror(*argv);
+ return 1;
}
@@ -507,10 +440,7 @@ void* slave_loop(void* data)
{
/* Create information table. */
if (xmalloc(information, 1, client_t))
- {
- perror(*argv);
- goto fail;
- }
+ goto pfail;
/* NULL-out pointers and initialisation markers. */
information->interception_conditions = NULL;
@@ -550,10 +480,7 @@ void* slave_loop(void* data)
information->send_pending_size = 0;
information->multicasts_count = 0;
if (mds_message_initialise(&(information->message)))
- {
- perror(*argv);
- goto fail;
- }
+ goto pfail;
}
@@ -561,129 +488,102 @@ 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)) != 0)
- {
- perror(*argv);
- goto fail;
- }
+ if ((errno = pthread_mutex_init(&(information->mutex), NULL))) goto pfail;
information->mutex_created = 1;
/* Create mutex and codition for multicast interception replies. */
- if ((errno = pthread_mutex_init(&(information->modify_mutex), NULL)) != 0)
- {
- perror(*argv);
- goto fail;
- }
+ if ((errno = pthread_mutex_init(&(information->modify_mutex), NULL))) goto pfail;
information->modify_mutex_created = 1;
- if ((errno = pthread_cond_init(&(information->modify_cond), NULL)) != 0)
- {
- perror(*argv);
- goto fail;
- }
+ if ((errno = pthread_cond_init(&(information->modify_cond), NULL))) goto pfail;
information->modify_cond_created = 1;
/* Make the server update without all slaves dying on SIGUSR1. */
- if (xsigaction(SIGUSR1, sigusr1_trap) < 0)
- {
- perror(*argv);
- goto fail;
- }
+ if (xsigaction(SIGUSR1, sigusr1_trap) < 0) goto pfail;
/* Implement clean exit on SIGTERM. */
- if (xsigaction(SIGTERM, sigterm_trap) < 0)
- {
- perror(*argv);
- goto fail;
- }
+ if (xsigaction(SIGTERM, sigterm_trap) < 0) goto pfail;
/* Fetch messages from the slave. */
- if (information->open)
- while (terminating == 0)
- {
- /* Send queued multicast messages. */
- if (information->multicasts_count > 0)
+ while ((terminating == 0) && (information->open == 0))
+ {
+ /* Send queued multicast messages. */
+ 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;
+ }
+ }
+ );
+ multicast_message(&multicast);
+ multicast_destroy(&multicast);
+ }
+
+ /* Send queued messages. */
+ if (information->send_pending_size > 0)
+ {
+ char* sendbuf = information->send_pending;
+ char* sendbuf_ = sendbuf;
+ size_t sent;
+ 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);
+ );
+ }
+
+ /* Fetch message. */
+ r = mds_message_read(&(information->message), socket_fd);
+ if (r == 0)
+ {
+ if (message_received(information) == 1)
+ goto terminate;
+ }
+ else
+ if (r == -2)
{
- multicast_t multicast;
- with_mutex(information->mutex,
- if (information->multicasts_count > 0)
- {
- size_t c = information->multicasts_count -= 1;
- c *= 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);
+ eprint("corrupt message received.");
+ goto fail;
}
-
- /* Send queued messages. */
- if (information->send_pending_size > 0)
+ else if (errno == ECONNRESET)
{
- char* sendbuf = information->send_pending;
- char* sendbuf_ = sendbuf;
- size_t sent;
- 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);
- );
+ r = mds_message_read(&(information->message), socket_fd);
+ if ((r == 0) && message_received(information))
+ goto terminate;
+ information->open = 0;
+ /* Connection closed. */
}
-
- /* Fetch message. */
- r = mds_message_read(&(information->message), socket_fd);
- if (r == 0)
+ else if (errno == EINTR)
{
- if (message_received(information) == 1)
+ /* Stop the thread if we are re-exec:ing the server. */
+ if (terminating)
goto terminate;
}
else
- if (r == -2)
- {
- eprint("corrupt message received.");
- goto fail;
- }
- else if (errno == ECONNRESET)
- {
- r = mds_message_read(&(information->message), socket_fd);
- if (r == 0)
- if (message_received(information))
- goto terminate;
- information->open = 0;
- /* Connection closed. */
- break;
- }
- else if (errno == EINTR)
- {
- /* Stop the thread if we are re-exec:ing the server. */
- if (terminating)
- goto terminate;
- }
- else
- {
- perror(*argv);
- goto fail;
- }
- }
+ goto pfail;
+ }
/* Stop the thread if we are re-exec:ing the server. */
if (terminating)
goto terminate;
@@ -725,6 +625,11 @@ void* slave_loop(void* data)
return NULL;
+ pfail:
+ perror(*argv);
+ goto fail;
+
+
reexec:
/* Tell the master thread that the slave has closed,
this is done because re-exec causes a race-condition
@@ -1037,46 +942,46 @@ void add_intercept_condition(client_t* client, char* condition, int64_t priority
with for optimisation. */
for (i = 0; i < n; i++)
{
- if (conds[i].header_hash == hash)
- if (strequals(conds[i].condition, condition))
- {
- if (stop)
- {
- /* Remove the condition from the list. */
- memmove(conds + i, conds + i + 1, --n - i);
- client->interception_conditions_count--;
- /* Shrink the list. */
- if (n == 0)
- {
- free(conds);
- client->interception_conditions = NULL;
- }
+ if ((conds[i].header_hash == hash) && strequals(conds[i].condition, condition))
+ {
+ if (stop)
+ {
+ /* Remove the condition from the list. */
+ memmove(conds + i, conds + i + 1, --n - i);
+ client->interception_conditions_count--;
+ /* Shrink the list. */
+ if (n == 0)
+ {
+ free(conds);
+ client->interception_conditions = NULL;
+ }
+ else
+ if ((conds = realloc(conds, n * sizeof(interception_condition_t))) == NULL)
+ perror(*argv);
else
- if ((conds = realloc(conds, n * sizeof(interception_condition_t))) == NULL)
- perror(*argv);
- else
- client->interception_conditions = conds;
- }
- else
- {
- /* Update parameters. */
- conds[i].priority = priority;
- conds[i].modifying = modifying;
- if (modifying && (nonmodifying >= 0))
- {
- /* Optimisation: put conditions that are modifying
- at the beginning. When a client is intercepting
- we most know if any satisfying condition is
- modifying. With this optimisation the first
- satisfying condition will tell us if there is
- any satisfying condition that is modifying. */
- interception_condition_t temp = conds[nonmodifying];
- conds[nonmodifying] = conds[i];
- conds[i] = temp;
- }
- }
- return;
- }
+ client->interception_conditions = conds;
+ }
+ else
+ {
+ /* Update parameters. */
+ conds[i].priority = priority;
+ conds[i].modifying = modifying;
+
+ if (modifying && (nonmodifying >= 0))
+ {
+ /* Optimisation: put conditions that are modifying
+ at the beginning. When a client is intercepting
+ we most know if any satisfying condition is
+ modifying. With this optimisation the first
+ satisfying condition will tell us if there is
+ any satisfying condition that is modifying. */
+ interception_condition_t temp = conds[nonmodifying];
+ conds[nonmodifying] = conds[i];
+ conds[i] = temp;
+ }
+ }
+ return;
+ }
/* Look for the first non-modifying, this is a part of the
optimisation where we put all modifying conditions at the
beginning. */
@@ -1411,79 +1316,79 @@ void multicast_message(multicast_t* multicast)
continue;
}
- /* Wait for a reply and act upon it. */
- if ((n == 0) && client_.modifying)
+ /* Do not wait for a reply if it is non-modifying. */
+ if (client_.modifying)
{
- /* pthread_cond_timedwait is required to handle re-exec because
- pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */
- struct timespec timeout =
- {
- .tv_sec = 1,
- .tv_nsec = 0
- };
- int modifying = 0;
- char* old_buf;
- size_t i;
- 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)
- {
- for (;;)
- {
- pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout);
- if ((client->modify_message != NULL) && terminating)
- break;
- }
- if (terminating == 0)
- hash_table_remove(&modify_map, (size_t)modify_id);
- }
- );
- if (terminating)
- return;
-
- /* Act upon the reply. */
- if (client->modify_message != NULL)
- {
- mod = client->modify_message;
- for (i = 0; i < mod->header_count; i++)
- if (!strcmp(mod->headers[i], "Modify: yes"))
- {
- modifying = 1;
- break;
- }
- if (modifying)
- {
- old_buf = multicast->message;
- n = mod->payload_size;
- multicast->message = realloc(old_buf, (multicast->message_prefix + n) * sizeof(char));
- if (multicast->message == NULL)
- {
- perror(*argv);
- multicast->message = old_buf;
- }
- else
- memcpy(multicast->message + multicast->message_prefix, mod->payload, n);
- }
-
- /* Free the reply. */
- mds_message_destroy(client->modify_message);
- }
+ /* Reset how much of the message has been sent before we continue with next recipient. */
+ multicast->message_ptr = 0;
+ continue;
}
- /* Reset how much of the message has been sent before we continue with next recipient. */
- multicast->message_ptr = 0;
+ /* Wait for a reply and act upon it. */
+ {
+ /* pthread_cond_timedwait is required to handle re-exec because
+ pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */
+ struct timespec timeout =
+ {
+ .tv_sec = 1,
+ .tv_nsec = 0
+ };
+ int modifying = 0;
+ char* old_buf;
+ size_t i;
+ 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);
+ }
+ );
+ if (terminating)
+ return;
+
+ /* Act upon the reply. */
+ mod = client->modify_message;
+ for (i = 0; i < mod->header_count; i++)
+ if (!strcmp(mod->headers[i], "Modify: yes"))
+ {
+ modifying = 1;
+ break;
+ }
+ if (modifying)
+ {
+ old_buf = multicast->message;
+ n = mod->payload_size;
+ multicast->message = realloc(old_buf, (multicast->message_prefix + n) * sizeof(char));
+ if (multicast->message == NULL)
+ {
+ perror(*argv);
+ multicast->message = old_buf;
+ }
+ else
+ memcpy(multicast->message + multicast->message_prefix, mod->payload, n);
+ }
+
+ /* Free the reply. */
+ mds_message_destroy(client->modify_message);
+
+ /* Reset how much of the message has been sent before we continue with next recipient. */
+ multicast->message_ptr = 0;
+ }
}
}
@@ -1809,18 +1714,12 @@ int unmarshal_server(int fd)
/* Unmarshal the client list. */
if (linked_list_unmarshal(&client_list, state_buf_))
- {
- perror(*argv);
- abort(); /* Critical. */
- }
+ goto critical_fail;
state_buf_ += list_size / sizeof(char);
/* Unmarshal the client map. */
if (fd_table_unmarshal(&client_map, state_buf_, unmarshal_remapper))
- {
- perror(*argv);
- abort(); /* Critical. */
- }
+ goto critical_fail;
/* Release the raw data. */
free(state_buf);
@@ -1851,15 +1750,7 @@ int unmarshal_server(int fd)
with_mutex(slave_mutex, running_slaves++;);
/* Start slave thread. */
- errno = pthread_create(&slave_thread, NULL, slave_loop, (void*)(intptr_t)socket_fd);
- if (errno)
- {
- perror(*argv);
- with_mutex(slave_mutex, running_slaves--;);
- }
- errno = pthread_detach(slave_thread);
- if (errno)
- perror(*argv);
+ create_slave(&slave_thread, socket_fd);
}
}
@@ -1867,5 +1758,33 @@ int unmarshal_server(int fd)
hash_table_destroy(&unmarshal_remap_map, NULL, NULL);
return -with_error;
+
+ critical_fail:
+ perror(*argv);
+ abort();
+}
+
+
+/**
+ * Create, start and detache a slave thread
+ *
+ * @param thread The address at where to store the thread
+ * @param socket_fd The file descriptor of the slave's socket
+ * @return Zero on success, -1 on error, error message will have been printed
+ */
+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--;);
+ return -1;
+ }
+ if ((errno = pthread_detach(*thread_slot)))
+ {
+ perror(*argv);
+ return -1;
+ }
+ return 0;
}
diff --git a/src/mds-server/mds-server.h b/src/mds-server/mds-server.h
index 43662d7..08f7fd4 100644
--- a/src/mds-server/mds-server.h
+++ b/src/mds-server/mds-server.h
@@ -116,6 +116,15 @@ int marshal_server(int fd);
*/
int unmarshal_server(int fd);
+/**
+ * Create, start and detache a slave thread
+ *
+ * @param thread The address at where to store the thread
+ * @param socket_fd The file descriptor of the slave's socket
+ * @return Zero on success, -1 on error, error message will have been printed
+ */
+int create_slave(pthread_t* thread_slot, int socket_fd);
+
#endif
diff --git a/src/mds.c b/src/mds.c
index 16d6275..c466846 100644
--- a/src/mds.c
+++ b/src/mds.c
@@ -69,9 +69,12 @@ int main(int argc_, char** argv_)
char pathname[PATH_MAX];
char piddata[64];
unsigned int display;
- FILE *f;
+ FILE* f;
int rc;
- int j;
+ int j, r;
+
+
+#define exit_if(CONDITION, INSTRUCTION) if (CONDITION) { INSTRUCTION return 1; }
argc = argc_;
@@ -79,11 +82,8 @@ int main(int argc_, char** argv_)
/* Sanity check the number of command line arguments. */
- if (argc > ARGC_LIMIT)
- {
- eprint("that number of arguments is ridiculous, I will not allow it.");
- return 1;
- }
+ exit_if (argc > ARGC_LIMIT,
+ eprint("that number of arguments is ridiculous, I will not allow it."););
/* Parse command line arguments. */
for (j = 1; j < argc; j++)
@@ -91,29 +91,20 @@ int main(int argc_, char** argv_)
char* arg = argv[j];
if (startswith(arg, "--master-server=")) /* Master server. */
{
- if (got_master_server)
- {
- eprintf("duplicate declaration of %s.", "--master-server");
- return 1;
- }
+ exit_if (got_master_server,
+ eprintf("duplicate declaration of %s.", "--master-server"););
got_master_server = 1;
master_server = arg + strlen("--master-server=");
}
}
/* Stymied if the effective user is not root. */
- if (geteuid() != ROOT_USER_UID)
- {
- eprint("the effective user is not root, cannot continue.");
- return 1;
- }
+ exit_if (geteuid() != ROOT_USER_UID,
+ eprint("the effective user is not root, cannot continue."););
/* Set up to ignore SIGUSR1, used in mds for re-exec, but we cannot re-exec. */
if (xsigaction(SIGUSR1, SIG_IGN) < 0)
- {
- perror(*argv);
- eprint("while ignoring the SIGUSR1 signal.");
- }
+ perror(*argv);
/* Create directory for socket files, PID files and such. */
if (create_directory_root(MDS_RUNTIME_ROOT_DIRECTORY))
@@ -127,88 +118,42 @@ int main(int argc_, char** argv_)
fd = open(pathname, O_CREAT | O_EXCL);
if (fd == -1)
{
- /* Reuse display index not no longer used. */
- size_t read_len;
+ /* Reuse display index if no longer used. */
f = fopen(pathname, "r");
if (f == NULL) /* Race, or error? */
{
perror(*argv);
- eprintf("while opening the file: %s", pathname);
continue;
}
- read_len = fread(piddata, 1, sizeof(piddata) / sizeof(char), f);
- if (ferror(f)) /* Failed to read. */
- {
- perror(*argv);
- eprintf("while reading the file: %s", pathname);
- }
- else if (feof(f) == 0) /* Did not read everything. */
- eprint("the content of a PID file is longer than expected.");
- else
- {
- pid_t pid = 0;
- size_t i, n = read_len - 1;
- for (i = 0; i < n; i++)
- {
- char c = piddata[i];
- if (('0' <= c) && (c <= '9'))
- pid = pid * 10 + (c & 15);
- else
- {
- eprint("the content of a PID file is invalid.");
- goto bad;
- }
- }
- if (piddata[n] != '\n')
- {
- eprint("the content of a PID file is invalid.");
- goto bad;
- }
- if (kill(pid, 0) < 0) /* Check if the PID is still allocated to any process. */
- if (errno == ESRCH) /* PID is not used. */
- {
- fclose(f);
- close(fd);
- break;
- }
- }
- bad:
+ r = is_pid_file_reusable(f);
fclose(f);
- continue;
+ if (r == 0)
+ continue;
}
close(fd);
break;
}
- if (display == DISPLAY_MAX)
- {
- eprint("sorry, too many displays on the system.");
- return 1;
- /* Yes, the directory could have been removed, but it probably was not. */
- }
+ exit_if (display == DISPLAY_MAX,
+ 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. */
- f = fopen(pathname, "w");
- if (f == NULL)
- {
- perror(*argv);
- eprintf("while opening the file: %s", pathname);
- return 1;
- }
+ if ((f = fopen(pathname, "w")) == NULL)
+ goto pfail;
xsnprintf(piddata, "%u\n", getpid());
if (fwrite(piddata, 1, strlen(piddata), f) < strlen(piddata))
{
fclose(f);
if (unlink(pathname) < 0)
perror(*argv);
- return -1;
+ return 1;
}
fflush(f);
fclose(f);
if (chmod(pathname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
- {
- perror(*argv);
- eprintf("while setting permissions for PID file: %s", pathname);
- }
+ perror(*argv);
/* Create data storage directory. */
if (create_directory_root(MDS_STORAGE_ROOT_DIRECTORY))
@@ -228,32 +173,13 @@ 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)
- {
- perror(*argv);
- eprint("while making anonymous socket private to its owner.");
- goto fail;
- }
- if (bind(fd, (struct sockaddr*)(&address), sizeof(address)) < 0)
- {
- perror(*argv);
- eprintf("while binding socket to file: %s", pathname);
- goto fail;
- }
- if (chown(pathname, getuid(), NOBODY_GROUP_GID) < 0)
- {
- perror(*argv);
- eprint("while making socket private to the real user.");
- goto fail;
- }
+ 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;
/* Start listening on socket. */
if (listen(fd, SOMAXCONN) < 0)
- {
- perror(*argv);
- eprintf("while setting up listening on socket: %s", pathname);
- goto fail;
- }
+ goto pfail;
/* Start master server and respawn it if it crashes. */
rc = spawn_and_respawn_server(fd);
@@ -279,6 +205,8 @@ int main(int argc_, char** argv_)
return rc;
+ pfail:
+ perror(*argv);
fail:
rc = 1;
goto done;
@@ -286,6 +214,64 @@ int main(int argc_, char** argv_)
/**
+ * Read a PID-file and determine whether it refers to an non-existing process
+ *
+ * @param f The PID-file
+ * @return Whether the PID-file is not longer used
+ */
+int is_pid_file_reusable(FILE* f)
+{
+ char piddata[64];
+ size_t read_len;
+
+ read_len = fread(piddata, 1, sizeof(piddata) / sizeof(char), f);
+ if (ferror(f)) /* Failed to read. */
+ perror(*argv);
+ else if (feof(f) == 0) /* Did not read everything. */
+ eprint("the content of a PID file is larger than expected.");
+ else
+ {
+ pid_t pid = parse_pid_t(piddata, read_len - 1);
+ if (pid == (pid_t)-1)
+ eprint("the content of a PID file is invalid.");
+ else
+ if (kill(pid, 0) < 0) /* Check if the PID is still allocated to any process. */
+ return errno == ESRCH; /* PID is not used. */
+ }
+
+ return 0;
+}
+
+
+/**
+ * Parse an LF-terminated string as a non-negative `pid_t`
+ *
+ * @param str The string
+ * @param n The length of the string, excluding LF-termination
+ * @return The pid, `(pid_t)-1` if malformated
+ */
+pid_t parse_pid_t(const char* str, size_t n)
+{
+ pid_t pid = 0;
+ size_t i;
+
+ for (i = 0; i < n; i++)
+ {
+ char c = str[i];
+ if (('0' <= c) && (c <= '9'))
+ pid = pid * 10 + (c & 15);
+ else
+ return (pid_t)-1;
+ }
+
+ if (str[n] != '\n')
+ return (pid_t)-1;
+
+ return pid;
+}
+
+
+/**
* Start master server and respawn it if it crashes
*
* @param fd The file descriptor of the socket
@@ -322,7 +308,6 @@ int spawn_and_respawn_server(int fd)
if (pid == (pid_t)-1)
{
perror(*argv);
- eprint("while forking.");
goto fail;
}
@@ -331,16 +316,12 @@ int spawn_and_respawn_server(int fd)
/* Get the current time. (Start of child process.) */
time_error = (monotone(&time_start) < 0);
if (time_error)
- {
- perror(*argv);
- eprint("while reading a monotonic clock.");
- }
+ perror(*argv);
/* Wait for master server to die. */
if (waitpid(pid, &status, 0) == (pid_t)-1)
{
perror(*argv);
- eprint("while waiting for child process to exit.");
goto fail;
}
@@ -376,7 +357,6 @@ int spawn_and_respawn_server(int fd)
if (child_args[argc + 0] == NULL)
{
perror(*argv);
- eprint("while duplicating string.");
goto fail;
}
}
@@ -389,14 +369,12 @@ int spawn_and_respawn_server(int fd)
if (drop_privileges())
{
perror(*argv);
- eprint("while dropping privileges.");
goto fail;
}
/* Start master server. */
execv(master_server, child_args);
perror(*argv);
- eprint("while changing execution image.");
goto fail;
}
}
@@ -440,7 +418,6 @@ int create_directory_root(const char* pathname)
if (errno != EEXIST) /* Unlikely race condition. */
{
perror(*argv);
- eprintf("while creating directory: %s", pathname);
return 1;
}
}
@@ -449,7 +426,6 @@ int create_directory_root(const char* pathname)
if (chown(pathname, ROOT_USER_UID, ROOT_GROUP_GID) < 0)
{
perror(*argv);
- eprintf("while changing owner of directory: %s", pathname);
return 1;
}
}
@@ -486,7 +462,6 @@ int create_directory_user(const char* pathname)
if (errno != EEXIST) /* Unlikely race condition. */
{
perror(*argv);
- eprintf("while creating directory: %s", pathname);
return 1;
}
}
@@ -495,7 +470,6 @@ int create_directory_user(const char* pathname)
if (chown(pathname, getuid(), NOBODY_GROUP_GID) < 0)
{
perror(*argv);
- eprintf("while changing owner of directory: %s", pathname);
return 1;
}
}
@@ -516,6 +490,7 @@ int unlink_recursive(const char* pathname)
int rc = 0;
struct dirent* file;
+ /* Check that we could examine the directory. */
if (dir == NULL)
{
int errno_ = errno;
@@ -524,10 +499,10 @@ int unlink_recursive(const char* pathname)
return 0;
errno = errno_;
perror(*argv);
- eprintf("while examining the content of directory: %s", pathname);
return 1;
}
+ /* 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)
@@ -537,17 +512,16 @@ int unlink_recursive(const char* pathname)
else
{
perror(*argv);
- eprintf("while unlinking file: %s", file->d_name);
rc = 1;
goto done;
}
eprint("pop");
}
+ /* Remvoe the drectory. */
if (rmdir(pathname) < 0)
{
perror(*argv);
- eprintf("while removing directory: %s", pathname);
rc = 1;
}
diff --git a/src/mds.h b/src/mds.h
index 20b5f66..b998f35 100644
--- a/src/mds.h
+++ b/src/mds.h
@@ -19,6 +19,27 @@
#define MDS_MDS_H
+#include <sys/types.h>
+#include <stdio.h>
+
+
+/**
+ * Read a PID-file and determine whether it refers to an non-existing process
+ *
+ * @param f The PID-file
+ * @return Whether the PID-file is not longer used
+ */
+int is_pid_file_reusable(FILE* f);
+
+/**
+ * Parse an LF-terminated string as a non-negative `pid_t`
+ *
+ * @param str The string
+ * @param n The length of the string, excluding LF-termination
+ * @return The pid, `(pid_t)-1` if malformated
+ */
+pid_t parse_pid_t(const char* str, size_t n) __attribute__((pure));
+
/**
* Start master server and respawn it if it crashes
*