diff --git a/Makefile b/Makefile index 1d1bd5a..21c95c5 100644 --- a/Makefile +++ b/Makefile @@ -255,6 +255,7 @@ install:: $(call quiet-installdir,0755,${DESTDIR}${SYSCONFDIR}/mxq) $(call quiet-installdir,0755,${DESTDIR}${MAN1DIR}) $(call quiet-installdir,0755,${DESTDIR}${CGIDIR}) + $(call quiet-installdir,0755,${DESTDIR}${LOCALSTATEDIR}/log) ######################################################################## diff --git a/mx_util.c b/mx_util.c index f783ed3..e2b488c 100644 --- a/mx_util.c +++ b/mx_util.c @@ -856,6 +856,47 @@ int mx_strscan_ll(char **str, long long int *to) return res; } +char *_mx_strconcat_do(char *first, ...) +{ + va_list ap; + char *join = NULL; + char *str; + char *ptr; + size_t len; + + if (!first) { + join = strdup(""); + return join; + } + + len = strlen(first); + + va_start(ap, first); + do { + str = va_arg(ap, char *); + if (!str) + break; + len += strlen(str); + } while(1); + va_end(ap); + + join = malloc(len+1); + if (!join) + return NULL; + + ptr = stpcpy(join, first); + va_start(ap, first); + do { + str = va_arg(ap, char *); + if (!str) + break; + ptr = stpcpy(ptr, str); + } while(1); + va_end(ap); + + return join; +} + int mx_sleep(unsigned int seconds) { if (seconds) diff --git a/mx_util.h b/mx_util.h index 508476c..92614fe 100644 --- a/mx_util.h +++ b/mx_util.h @@ -136,6 +136,9 @@ int mx_read_first_line_from_file(char *fname, char **line); int mx_strscan_ull(char **str, unsigned long long int *to); int mx_strscan_ll(char **str, long long int *to); +char *_mx_strconcat_do(char *first, ...); +#define mx_strconcat(s, ...) _mx_strconcat_do((s), ##__VA_ARGS__, NULL) + int mx_sleep(unsigned int seconds); int mx_sleep_nofail(unsigned int seconds); diff --git a/mxq.h b/mxq.h index 54b073f..aac59fe 100644 --- a/mxq.h +++ b/mxq.h @@ -46,6 +46,12 @@ #endif #define MXQ_MYSQL_DEFAULT_GROUP_STR MXQ_MYSQL_DEFAULT_GROUP +#if defined (LOCALSTATEDIR) +# define MXQ_LOGDIR LOCALSTATEDIR "/log" +#else +# define MXQ_LOGDIR "/var/log" +#endif + static void mxq_print_generic_version(void) { printf( diff --git a/mxq_job.c b/mxq_job.c index d4bbe21..4b33fda 100644 --- a/mxq_job.c +++ b/mxq_job.c @@ -601,7 +601,7 @@ int mxq_job_set_tmpfilenames(struct mxq_group *g, struct mxq_job *j) return 1; } -int mxq_load_job_assigned_to_server(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, char *hostname, char *server_id) +int mxq_load_job_from_group_assigned_to_server(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, uint64_t group_id, char *hostname, char *server_id) { int res; struct mxq_job *jobs = NULL; @@ -624,14 +624,16 @@ int mxq_load_job_assigned_to_server(struct mx_mysql *mysql, struct mxq_job **mxq " WHERE job_status = " status_str(MXQ_JOB_STATUS_ASSIGNED) " AND host_hostname = ?" " AND server_id = ?" + " AND group_id = ?" " LIMIT 1"; - res = mx_mysql_bind_init_param(¶m, 2); + res = mx_mysql_bind_init_param(¶m, 3); assert(res == 0); res = 0; res += mx_mysql_bind_var(¶m, 0, string, &hostname); res += mx_mysql_bind_var(¶m, 1, string, &server_id); + res += mx_mysql_bind_var(¶m, 2, uint64, &group_id); assert(res == 0); res = bind_result_job_fields(&result, &j); @@ -662,10 +664,10 @@ int mxq_load_job_from_group_for_server(struct mx_mysql *mysql, struct mxq_job *m assert(*host_id); do { - res = mxq_load_job_assigned_to_server(mysql, &jobs, hostname, server_id); + res = mxq_load_job_from_group_assigned_to_server(mysql, &jobs, group_id, hostname, server_id); if(res < 0) { - mx_log_err(" group_id=%lu :: mxq_load_job_assigned_to_server: %m", group_id); + mx_log_err(" group_id=%lu :: mxq_load_job_from_group_assigned_to_server: %m", group_id); return 0; } if(res == 1) { diff --git a/mxq_job.h b/mxq_job.h index f29baf6..3bf62bb 100644 --- a/mxq_job.h +++ b/mxq_job.h @@ -105,7 +105,7 @@ int mxq_set_job_status_running(struct mx_mysql *mysql, struct mxq_job *job); int mxq_set_job_status_exited(struct mx_mysql *mysql, struct mxq_job *job); int mxq_set_job_status_unknown_for_server(struct mx_mysql *mysql, char *hostname, char *server_id); int mxq_job_set_tmpfilenames(struct mxq_group *g, struct mxq_job *j); -int mxq_load_job_assigned_to_server(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, char *hostname, char *server_id); +int mxq_load_job_from_group_assigned_to_server(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, uint64_t group_id, char *hostname, char *server_id); int mxq_load_job_from_group_for_server(struct mx_mysql *mysql, struct mxq_job *mxqjob, uint64_t group_id, char *hostname, char *server_id, char *host_id); #endif diff --git a/mxqd.c b/mxqd.c index 167ed12..15fa51d 100644 --- a/mxqd.c +++ b/mxqd.c @@ -78,7 +78,9 @@ static void print_usage(void) #else " --no-log default: write a logfile\n" #endif + " --log-directory default: " MXQ_LOGDIR "\n" " --debug default: info log level\n" + "\n" " --recover-only (recover from crash and exit)\n" "\n" " --initial-path default: %s\n" @@ -92,6 +94,9 @@ static void print_usage(void) " -M, --mysql-default-file [mysql-file] default: %s\n" " -S, --mysql-default-group [mysql-group] default: %s\n" "\n" + "Directories:\n" + " LOGDIR " MXQ_LOGDIR "\n" + "\n" "Environment:\n" " MXQ_MYSQL_DEFAULT_FILE change default for [mysql-file]\n" " MXQ_MYSQL_DEFAULT_GROUP change default for [mysql-group]\n" @@ -135,11 +140,26 @@ static void cpuset_clear_running(cpu_set_t *running,cpu_set_t *job) { } /**********************************************************************/ -int setup_cronolog(char *cronolog, char *link, char *format) +int setup_cronolog(char *cronolog, char *logdir, char *rellink, char *relformat) { int res; int pipe_fd[2]; int pid; + _mx_cleanup_free_ char *link = NULL; + _mx_cleanup_free_ char *format = NULL; + + if (logdir) { + link = mx_strconcat(logdir, "/", rellink); + format = mx_strconcat(logdir, "/", relformat); + } else { + link = strdup(rellink); + format = strdup(relformat); + } + + if (!link || !format) { + mx_log_err("can't allocate filenames: (%m)"); + return 0; + } res = pipe(pipe_fd); if (res == -1) { @@ -276,6 +296,7 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) char *arg_mysql_default_group; char *arg_mysql_default_file; char *arg_pidfile = NULL; + char *arg_logdir = NULL; char *arg_initial_path; char *arg_initial_tmpdir; char arg_daemonize = 0; @@ -296,7 +317,8 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) MX_OPTION_NO_ARG("version", 'V'), MX_OPTION_NO_ARG("daemonize", 1), MX_OPTION_NO_ARG("no-log", 3), - MX_OPTION_NO_ARG("log", 4), + MX_OPTION_OPTIONAL_ARG("log", 4), + MX_OPTION_REQUIRED_ARG("log-directory", 4), MX_OPTION_NO_ARG("debug", 5), MX_OPTION_NO_ARG("recover-only", 9), MX_OPTION_REQUIRED_ARG("pid-file", 2), @@ -354,6 +376,7 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) case 4: arg_nolog = 0; + arg_logdir = optctl.optarg; break; case 5: @@ -433,15 +456,6 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) MX_GETOPT_FINISH(optctl, argc, argv); - if (!RUNNING_AS_ROOT) { -#if defined(MXQ_DEVELOPMENT) || defined(RUNASNORMALUSER) - mx_log_notice("Running mxqd as non-root user."); -#else - mx_log_err("Running mxqd as non-root user is not supported at the moment."); - exit(EX_USAGE); -#endif - } - if (arg_daemonize && arg_nolog) { mx_log_err("Error while using conflicting options --daemonize and --no-log at once."); exit(EX_USAGE); @@ -449,13 +463,6 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) memset(server, 0, sizeof(*server)); - res = mx_mysql_initialize(&(server->mysql)); - assert(res == 0); - - mx_mysql_option_set_default_file(server->mysql, arg_mysql_default_file); - mx_mysql_option_set_default_group(server->mysql, arg_mysql_default_group); - mx_mysql_option_set_reconnect(server->mysql, 1); - server->hostname = arg_hostname; server->server_id = arg_server_id; server->initial_path = arg_initial_path; @@ -499,17 +506,34 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) setup_stdin("/dev/null"); if (!arg_nolog) { - if (access("/var/log",R_OK|W_OK|X_OK)) { - mx_log_err("MAIN: cant write to /var/log: %m"); + if (!arg_logdir) + arg_logdir = MXQ_LOGDIR; + + if (access(arg_logdir, R_OK|W_OK|X_OK)) { + if (!RUNNING_AS_ROOT) + mx_log_warning("Running mxqd as non-root user."); + mx_log_err("MAIN: can't write to '%s': %m", arg_logdir); exit(EX_IOERR); } - res = setup_cronolog("/usr/sbin/cronolog", "/var/log/mxqd_log", "/var/log/%Y/mxqd_log-%Y-%m"); + res = setup_cronolog("/usr/sbin/cronolog", arg_logdir, "mxqd_log", "%Y/mxqd_log-%Y-%m"); if (!res) { + if (!RUNNING_AS_ROOT) + mx_log_warning("Running mxqd as non-root user."); mx_log_err("MAIN: cronolog setup failed. exiting."); exit(EX_IOERR); } } + if (!RUNNING_AS_ROOT) + mx_log_warning("Running mxqd as non-root user."); + + res = mx_mysql_initialize(&(server->mysql)); + assert(res == 0); + + mx_mysql_option_set_default_file(server->mysql, arg_mysql_default_file); + mx_mysql_option_set_default_group(server->mysql, arg_mysql_default_group); + mx_mysql_option_set_reconnect(server->mysql, 1); + res = mx_read_first_line_from_file("/proc/sys/kernel/random/boot_id", &str_bootid); assert(res == 36); assert(str_bootid); diff --git a/test_mx_util.c b/test_mx_util.c index 06cfe72..2f6be8f 100644 --- a/test_mx_util.c +++ b/test_mx_util.c @@ -384,6 +384,27 @@ static void test_mx_strvec() { mx_strvec_free(strvec); } +static void test_mx_strcat() { + char *str; + char *str2; + + assert(str = mx_strconcat(NULL)); + assert(mx_streq(str, "")); + mx_free_null(str); + + assert(str = mx_strconcat("abc", "123")); + assert(mx_streq(str, "abc123")); + + assert(str2 = mx_strconcat(str, "def", str, "456")); + assert(mx_streq(str2, "abc123defabc123456")); + mx_free_null(str2); + + assert(str2 = mx_strconcat(str)); + assert(mx_streq(str, str2)); + mx_free_null(str); + mx_free_null(str2); +} + static void test_mx_cpuset(void) { cpu_set_t cpuset; @@ -421,6 +442,7 @@ int main(int argc, char *argv[]) test_mx_read_first_line_from_file(); test_mx_strscan(); test_mx_strvec(); + test_mx_strcat(); test_mx_cpuset(); return 0; }