#include "server.lsg.h"
#include "para.h"
#include "error.h"
+#include "lsu.h"
#include "crypt.h"
#include "sideband.h"
#include "command.h"
#include "string.h"
#include "afh.h"
#include "afs.h"
+#include "net.h"
#include "server.h"
#include "list.h"
#include "send.h"
#include "sched.h"
#include "vss.h"
-#include "net.h"
#include "daemon.h"
#include "fd.h"
#include "ipc.h"
extern int mmd_mutex;
extern struct misc_meta_data *mmd;
-extern struct sender senders[];
int send_afs_status(struct command_context *cc, int parser_friendly);
+static bool subcmd_should_die;
-static void dummy(__a_unused int s)
+static void command_handler_sighandler(int s)
{
+ if (s != SIGTERM)
+ return;
+ PARA_EMERG_LOG("terminating on signal %d\n", SIGTERM);
+ subcmd_should_die = true;
}
/*
return ret;
}
arg = lls_input(0, lpr);
- for (i = 0; senders[i].name; i++)
- if (!strcmp(senders[i].name, arg))
+ FOR_EACH_SENDER(i)
+ if (strcmp(senders[i]->name, arg) == 0)
break;
- if (!senders[i].name)
+ if (!senders[i])
return -E_COMMAND_SYNTAX;
scd->sender_num = i;
arg = lls_input(1, lpr);
if (i == NUM_SENDER_CMDS)
return -E_COMMAND_SYNTAX;
scd->cmd_num = i;
- if (!senders[scd->sender_num].client_cmds[scd->cmd_num])
+ if (!senders[scd->sender_num]->client_cmds[scd->cmd_num])
return -E_SENDER_CMD;
switch (scd->cmd_num) {
case SENDER_on:
struct sender_command_data scd;
if (lls_num_inputs(lpr) == 0) {
- for (i = 0; senders[i].name; i++) {
+ FOR_EACH_SENDER(i) {
char *tmp;
ret = xasprintf(&tmp, "%s%s\n", msg? msg : "",
- senders[i].name);
+ senders[i]->name);
free(msg);
msg = tmp;
}
if (scd.sender_num < 0)
return ret;
if (strcmp(lls_input(1, lpr), "status") == 0)
- msg = senders[scd.sender_num].status();
+ msg = senders[scd.sender_num]->status();
else
- msg = senders[scd.sender_num].help();
+ msg = senders[scd.sender_num]->help();
return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
}
switch (scd.cmd_num) {
case SENDER_add:
case SENDER_delete:
- assert(senders[scd.sender_num].resolve_target);
- ret = senders[scd.sender_num].resolve_target(lls_input(2, lpr),
+ assert(senders[scd.sender_num]->resolve_target);
+ ret = senders[scd.sender_num]->resolve_target(lls_input(2, lpr),
&scd);
if (ret < 0)
return ret;
bool parser_friendly = SERVER_CMD_OPT_GIVEN(STAT, PARSER_FRIENDLY,
lpr) > 0;
uint32_t num = SERVER_CMD_UINT32_VAL(STAT, NUM, lpr);
+ const struct timespec ts = {.tv_sec = 50, .tv_nsec = 0};
- para_sigaction(SIGUSR1, dummy);
+ para_sigaction(SIGINT, SIG_IGN);
+ para_sigaction(SIGUSR1, command_handler_sighandler);
+ para_sigaction(SIGTERM, command_handler_sighandler);
+ /*
+ * Simply checking subcmd_should_die is racy because a signal may
+ * arrive after the check but before the subsequent call to sleep(3).
+ * If this happens, sleep(3) would not be interrupted by the signal.
+ * To avoid this we block SIGTERM here and allow it to arrive only
+ * while we sleep.
+ */
+ para_block_signal(SIGTERM);
for (;;) {
+ sigset_t set;
/*
* Copy the mmd structure to minimize the time we hold the mmd
* lock.
ret = 1;
if (num > 0 && !--num)
goto out;
- sleep(50);
+ sigemptyset(&set); /* empty set means: unblock all signals */
+ /*
+ * pselect(2) allows to atomically unblock signals, then go to
+ * sleep. Calling sigprocmask(2) followed by sleep(3) would
+ * open a race window similar to the one described above.
+ */
+ pselect(1, NULL, NULL, NULL, &ts, &set);
+ if (subcmd_should_die)
+ goto out;
ret = -E_SERVER_CRASH;
if (getppid() == 1)
goto out;
}
EXPORT_SERVER_CMD_HANDLER(stat);
-/* fixed-length, human readable permission string */
-const char *server_cmd_perms_str(unsigned int perms)
+const char *aux_info_cb(unsigned cmd_num, bool verbose)
{
- static char result[5];
-
- result[0] = perms & AFS_READ? 'a' : '-';
- result[1] = perms & AFS_WRITE? 'A' : '-';
- result[2] = perms & VSS_READ? 'v' : '-';
- result[3] = perms & VSS_WRITE? 'V' : '-';
- result[4] = '\0';
- return result;
-}
+ static char result[80];
+ unsigned perms = server_command_perms[cmd_num];
-static int send_list_of_commands(struct command_context *cc)
-{
- int i;
- const struct lls_command *cmd;
- char *msg = para_strdup("");
-
- for (i = 1; (cmd = lls_cmd(i, server_cmd_suite)); i++) {
- const char *perms = server_cmd_perms_str(server_command_perms[i]);
- char *tmp = make_message("%s%s\t%s\t%s\n", msg,
- lls_command_name(cmd), perms, lls_purpose(cmd));
- free(msg);
- msg = tmp;
+ if (verbose) {
+ /* permissions: VSS_READ | VSS_WRITE */
+ sprintf(result, "permissions: %s",
+ server_command_perms_txt[cmd_num]);
+ } else {
+ result[0] = perms & AFS_READ? 'a' : '-';
+ result[1] = perms & AFS_WRITE? 'A' : '-';
+ result[2] = perms & VSS_READ? 'v' : '-';
+ result[3] = perms & VSS_WRITE? 'V' : '-';
+ result[4] = '\0';
}
- return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
+ return result;
}
static int com_help(struct command_context *cc, struct lls_parse_result *lpr)
{
- const char *perms;
- char *long_help, *buf, *errctx;
+ char *buf;
int ret;
- const struct lls_command *cmd;
+ unsigned n;
+ bool long_help = SERVER_CMD_OPT_GIVEN(HELP, LONG, lpr);
- ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx));
- if (ret < 0) {
- send_errctx(cc, errctx);
- return ret;
- }
- if (lls_num_inputs(lpr) == 0)
- return send_list_of_commands(cc);
- /* argument given for help */
- ret = lls(lls_lookup_subcmd(lls_input(0, lpr), server_cmd_suite,
- &errctx));
- if (ret < 0) {
- send_errctx(cc, errctx);
- return ret;
- }
- cmd = lls_cmd(ret, server_cmd_suite);
- perms = server_command_perms_txt[ret];
- long_help = lls_long_help(cmd);
- assert(long_help);
- ret = xasprintf(&buf, "%spermissions: %s\n", long_help, perms);
- free(long_help);
- return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
+ lsu_com_help(long_help, lpr, server_cmd_suite, aux_info_cb, &buf, &n);
+ ret = send_sb(&cc->scc, buf, n, SBD_OUTPUT, false);
+ return ret;
}
EXPORT_SERVER_CMD_HANDLER(help);
}
EXPORT_SERVER_CMD_HANDLER(nomore);
-static int com_ff(__a_unused struct command_context *cc,
- struct lls_parse_result *lpr)
+static int com_ff(struct command_context *cc, struct lls_parse_result *lpr)
{
long promille;
- int ret, backwards = 0;
- unsigned i;
+ int i, ret;
char c, *errctx;
ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx));
send_errctx(cc, errctx);
return ret;
}
- if (!(ret = sscanf(lls_input(0, lpr), "%u%c", &i, &c)))
- return -E_COMMAND_SYNTAX;
- if (ret > 1 && c == '-')
- backwards = 1; /* jmp backwards */
+ ret = para_atoi32(lls_input(0, lpr), &i);
+ if (ret < 0) {
+ if (ret != -E_ATOI_JUNK_AT_END)
+ return ret;
+ /*
+ * Compatibility code to keep the historic syntax (ff 30-)
+ * working. This can be removed after 0.7.0.
+ */
+ ret = sscanf(lls_input(0, lpr), "%i%c", &i, &c);
+ if (ret <= 0)
+ return -E_COMMAND_SYNTAX;
+ if (ret > 1 && c == '-') {
+ PARA_WARNING_LOG("use of obsolete syntax\n");
+ i = -i;
+ }
+ }
mutex_lock(mmd_mutex);
ret = -E_NO_AUDIO_FILE;
if (!mmd->afd.afhi.chunks_total || !mmd->afd.afhi.seconds_total)
goto out;
+ ret = 1;
promille = (1000 * mmd->current_chunk) / mmd->afd.afhi.chunks_total;
- if (backwards)
- promille -= 1000 * i / mmd->afd.afhi.seconds_total;
- else
- promille += 1000 * i / mmd->afd.afhi.seconds_total;
+ /*
+ * We need this cast because without it the expression on the right
+ * hand side is of unsigned type.
+ */
+ promille += 1000 * i / (int)mmd->afd.afhi.seconds_total;
if (promille < 0)
promille = 0;
if (promille > 1000) {
mmd->new_vss_status_flags |= VSS_REPOS;
mmd->new_vss_status_flags &= ~VSS_NEXT;
mmd->events++;
- ret = 1;
out:
mutex_unlock(mmd_mutex);
return ret;
}
EXPORT_SERVER_CMD_HANDLER(ff);
-static int com_jmp(__a_unused struct command_context *cc,
- struct lls_parse_result *lpr)
+static int com_jmp(struct command_context *cc, struct lls_parse_result *lpr)
{
long unsigned int i;
int ret;
int dummy; /* none at the moment */
};
-static int parse_auth_request(char *buf, int len, struct user **u,
+static int parse_auth_request(char *buf, int len, const struct user **u,
struct connection_features *cf)
{
int ret;
}
}
PARA_DEBUG_LOG("received auth request for user %s\n", username);
- *u = lookup_user(username);
+ *u = user_list_lookup(username);
ret = 1;
out:
free_argv(features);
* the function if the connection was not authenticated when the timeout
* expires.
*
+ * \return Standard.
+ *
* \sa alarm(2), \ref openssl.c, \ref crypt.h.
*/
-__noreturn void handle_connect(int fd)
+int handle_connect(int fd)
{
int ret;
unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
}
sc_free(cc->scc.recv);
sc_free(cc->scc.send);
- exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
+ return ret;
}