#include <netdb.h>
#include <lopsub.h>
-#include "server.lsg.h"
#include "para.h"
#include "error.h"
#include "lsu.h"
int send_afs_status(struct command_context *cc, int parser_friendly);
static bool subcmd_should_die;
+/*
+ * Don't call PARA_XXX_LOG() here as we might already hold the log mutex. See
+ * generic_signal_handler() for details.
+ */
static void command_handler_sighandler(int s)
{
- if (s != SIGTERM)
- return;
- PARA_EMERG_LOG("terminating on signal %d\n", SIGTERM);
- subcmd_should_die = true;
+ if (s == SIGTERM)
+ subcmd_should_die = true;
}
/*
*/
static char *vss_get_status_flags(unsigned int flags)
{
- char *msg = para_malloc(5 * sizeof(char));
+ char *msg = alloc(5 * sizeof(char));
msg[0] = (flags & VSS_PLAYING)? 'P' : '_';
msg[1] = (flags & VSS_NOMORE)? 'O' : '_';
"server_pid: %d\n"
"afs_pid: %d\n"
"connections (active/accepted/total): %u/%u/%u\n"
- "current loglevel: %s\n"
"supported audio formats: %s\n",
ut, mmd->num_played,
(int)getppid(),
mmd->active_connections,
mmd->num_commands,
mmd->num_connects,
- ENUM_STRING_VAL(LOGLEVEL),
AUDIO_FORMAT_HANDLERS
);
mutex_unlock(mmd_mutex);
* while we sleep.
*/
para_block_signal(SIGTERM);
+ para_block_signal(SIGUSR1);
for (;;) {
sigset_t set;
/*
* open a race window similar to the one described above.
*/
pselect(1, NULL, NULL, NULL, &ts, &set);
- if (subcmd_should_die)
+ if (subcmd_should_die) {
+ PARA_EMERG_LOG("terminating on SIGTERM\n");
goto out;
+ }
ret = -E_SERVER_CRASH;
if (getppid() == 1)
goto out;
}
EXPORT_SERVER_CMD_HANDLER(hup);
+static int com_ll(struct command_context *cc, struct lls_parse_result *lpr)
+{
+ unsigned ll, perms;
+ char *errctx;
+ const char *sev[] = {SEVERITIES}, *arg;
+ int 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) { /* reporting is an unprivileged op. */
+ const char *severity;
+ mutex_lock(mmd_mutex);
+ severity = sev[mmd->loglevel];
+ mutex_unlock(mmd_mutex);
+ return send_sb_va(&cc->scc, SBD_OUTPUT, "%s\n", severity);
+ }
+ /*
+ * Changing the loglevel changes the state of both the afs and the vss,
+ * so we require both AFS_WRITE and VSS_WRITE.
+ */
+ perms = AFS_WRITE | VSS_WRITE;
+ if ((cc->u->perms & perms) != perms)
+ return -ERRNO_TO_PARA_ERROR(EPERM);
+ arg = lls_input(0, lpr);
+ for (ll = 0; ll < NUM_LOGLEVELS; ll++)
+ if (!strcmp(arg, sev[ll]))
+ break;
+ if (ll >= NUM_LOGLEVELS)
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ PARA_INFO_LOG("new log level: %s\n", sev[ll]);
+ /* Ask the server and afs processes to adjust their log level. */
+ mutex_lock(mmd_mutex);
+ mmd->loglevel = ll;
+ mutex_unlock(mmd_mutex);
+ return 1;
+}
+EXPORT_SERVER_CMD_HANDLER(ll);
+
static int com_term(__a_unused struct command_context *cc,
__a_unused struct lls_parse_result *lpr)
{
+ /*
+ * The server catches SIGTERM and propagates this signal to all its
+ * children. We are about to exit anyway, but we'd leak tons of memory
+ * if being terminated by the signal. So we ignore the signal here and
+ * terminate via the normal exit path, deallocating all memory.
+ */
+ para_sigaction(SIGTERM, SIG_IGN);
kill(getppid(), SIGTERM);
return 1;
}
{
long promille;
int i, ret;
- char c, *errctx;
+ char *errctx;
ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx));
if (ret < 0) {
return ret;
}
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;
- }
- }
+ if (ret < 0)
+ return ret;
mutex_lock(mmd_mutex);
ret = -E_NO_AUDIO_FILE;
if (!mmd->afd.afhi.chunks_total || !mmd->afd.afhi.seconds_total)
for (i = 0; p < end; i++)
p += strlen(p) + 1;
argc = i;
- argv = para_malloc((argc + 1) * sizeof(char *));
+ argv = arr_alloc(argc + 1, sizeof(char *));
for (i = 0, p = iov->iov_base; p < end; i++) {
argv[i] = para_strdup(p);
p += strlen(p) + 1;
int ret;
unsigned char rand_buf[APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
unsigned char challenge_hash[HASH2_SIZE];
- char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
+ char *command = NULL, *buf = alloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
size_t numbytes;
struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct;
struct iovec iov;