481 lines
11 KiB
C
481 lines
11 KiB
C
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#if defined(__GLIBC__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ < 28)
|
|
#include <pthread.h>
|
|
#else
|
|
#include <threads.h>
|
|
#endif
|
|
#include <sys/param.h>
|
|
#include <unistd.h>
|
|
|
|
#if defined(__linux__)
|
|
#include <execinfo.h>
|
|
#endif
|
|
|
|
#include <tlog.h>
|
|
|
|
#include "config.h"
|
|
#include "controller.capnp.h"
|
|
#include <capnp_c.h>
|
|
|
|
#include "utils.h"
|
|
#include "xce/errnox.h"
|
|
#include "xce/types.h"
|
|
|
|
static capn_text chars_to_text_internal(const char* chars)
|
|
{
|
|
capn_text data = {
|
|
.len = strlen(chars),
|
|
.str = chars,
|
|
.seg = NULL,
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
capn_text chars_to_text(const char* chars)
|
|
{
|
|
if (chars == NULL) {
|
|
chars = "";
|
|
}
|
|
|
|
return chars_to_text_internal(chars);
|
|
}
|
|
|
|
#define ARGV_INCR_DELTA (16)
|
|
|
|
#define FILL_ARGV(rc, argv, argc, maxargc, delta, s) \
|
|
do { \
|
|
(rc) = 0; \
|
|
char* s1; \
|
|
if (((argc) >= (maxargc))) { \
|
|
char** p; \
|
|
int nc, i; \
|
|
nc = (maxargc) + (delta); \
|
|
p = (char**)realloc((argv), nc * sizeof(char*)); \
|
|
if (p == NULL) { \
|
|
(rc) = -ENOMEM; \
|
|
break; \
|
|
} \
|
|
for (i = (maxargc); i < nc; i++) { \
|
|
p[i] = NULL; \
|
|
} \
|
|
(argv) = p; \
|
|
(maxargc) = nc; \
|
|
} \
|
|
s1 = strdup(s); \
|
|
if (s1 == NULL) { \
|
|
(rc) = -ENOMEM; \
|
|
break; \
|
|
} \
|
|
(argv)[argc] = s1; \
|
|
(argc)++; \
|
|
} while (0)
|
|
|
|
#define FREE_ARGV(argv, argc) \
|
|
do { \
|
|
int i; \
|
|
if ((argv) == NULL) { \
|
|
break; \
|
|
} \
|
|
for (i = 0; i < (argc); i++) { \
|
|
if ((argv)[i] != NULL) { \
|
|
free((argv)[i]); \
|
|
(argv)[i] = NULL; \
|
|
} \
|
|
} \
|
|
free(argv); \
|
|
} while (0)
|
|
|
|
int parse_argv(char* input,
|
|
char*** argv)
|
|
{
|
|
int max_argc = 0;
|
|
char* arg = NULL;
|
|
int i = 0;
|
|
int in_quotes = 0;
|
|
char quote_char = 0;
|
|
int argc = 0;
|
|
int rc = 0;
|
|
|
|
rc = 0;
|
|
arg = (char*)malloc(strlen(input) + 1);
|
|
if (arg == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
*argv = NULL;
|
|
while (*input) {
|
|
if (in_quotes) {
|
|
if (*input == quote_char) {
|
|
in_quotes = 0;
|
|
} else if (*input == '\\') {
|
|
input++;
|
|
if (*input) {
|
|
arg[i++] = *input;
|
|
}
|
|
} else {
|
|
arg[i++] = *input;
|
|
}
|
|
} else {
|
|
if (isspace(*input)) {
|
|
if (i > 0) {
|
|
arg[i] = '\0';
|
|
FILL_ARGV(rc, *argv, argc, max_argc,
|
|
ARGV_INCR_DELTA, arg);
|
|
if (rc < 0) {
|
|
FREE_ARGV(*argv, argc);
|
|
free(arg);
|
|
return rc;
|
|
}
|
|
i = 0;
|
|
}
|
|
} else if ((*input == '"') || (*input == '\'')) {
|
|
in_quotes = 1;
|
|
quote_char = *input;
|
|
} else if (*input == '\\') {
|
|
input++;
|
|
if (*input) {
|
|
arg[i++] = *input;
|
|
}
|
|
} else {
|
|
arg[i++] = *input;
|
|
}
|
|
}
|
|
input++;
|
|
}
|
|
|
|
if (i > 0) {
|
|
arg[i] = '\0';
|
|
FILL_ARGV(rc, *argv, argc, max_argc,
|
|
ARGV_INCR_DELTA, arg);
|
|
if (rc < 0) {
|
|
FREE_ARGV(*argv, argc);
|
|
free(arg);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
free(arg);
|
|
return argc;
|
|
}
|
|
|
|
void free_argv(char** argv, int argc)
|
|
{
|
|
FREE_ARGV(argv, argc);
|
|
}
|
|
|
|
#if 0
|
|
void freeup_kvs(int count,
|
|
xce_kv_t* vals)
|
|
{
|
|
int i;
|
|
|
|
if (vals == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (vals[i].value.which != XceFieldValue_data_svalue) {
|
|
continue;
|
|
}
|
|
|
|
FREEUP(vals[i].value.u.svalue);
|
|
}
|
|
|
|
FREEUP(vals);
|
|
}
|
|
#endif
|
|
|
|
char* frame_symbol(int k)
|
|
{
|
|
#if defined(__linux__)
|
|
void* array[k + 1];
|
|
size_t size = backtrace(array, k + 1);
|
|
char** symbols = backtrace_symbols(array, size);
|
|
char* s = NULL;
|
|
|
|
if (symbols == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
s = strdup(symbols[MIN(size - 1, k)]);
|
|
free(symbols);
|
|
return s;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
int xce_vprintf(const char* fmt, va_list ap)
|
|
{
|
|
int rc;
|
|
|
|
if (tlog_get_root() == NULL) {
|
|
rc = vfprintf(stdout, fmt, ap);
|
|
} else {
|
|
rc = tlog_vext(TLOG_INFO, __FILE__, __LINE__,
|
|
__func__, NULL, fmt, ap);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int name_to_level(char* lvlname)
|
|
{
|
|
static struct {
|
|
char* lvlstr;
|
|
int lvl;
|
|
} levels[] = {
|
|
{ "debug", TLOG_DEBUG },
|
|
{ "debug2", TLOG_DEBUG2 },
|
|
{ "debug3", TLOG_DEBUG3 },
|
|
{ "info", TLOG_INFO },
|
|
{ "notice", TLOG_NOTICE },
|
|
{ "warn", TLOG_WARN },
|
|
{ "error", TLOG_ERROR },
|
|
{ "fatal", TLOG_FATAL },
|
|
{ NULL, -1 }
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; levels[i].lvlstr != NULL; i++) {
|
|
if (strcasecmp(levels[i].lvlstr, lvlname) == 0) {
|
|
return levels[i].lvl;
|
|
}
|
|
}
|
|
|
|
return TLOG_INFO;
|
|
}
|
|
|
|
static int my_tlog_format(char* buff,
|
|
int maxlen,
|
|
struct tlog_loginfo* info,
|
|
void* userptr,
|
|
const char* fmt,
|
|
va_list ap)
|
|
{
|
|
int len = 0;
|
|
int total_len = 0;
|
|
struct tlog_time* tm = &info->time;
|
|
|
|
xce_use(userptr);
|
|
|
|
/* format prefix */
|
|
if (info->level < TLOG_INFO) {
|
|
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d] [%5d] [%6s] [%17s:%-4d] ",
|
|
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
|
|
tlog_get_level_string(info->level), info->file, info->line);
|
|
} else {
|
|
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d] [%5d] [%6s] [%22s] ",
|
|
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
|
|
tlog_get_level_string(info->level), info->func);
|
|
}
|
|
|
|
if (len < 0 || len >= maxlen) {
|
|
return -1;
|
|
}
|
|
buff += len;
|
|
total_len += len;
|
|
maxlen -= len;
|
|
|
|
/* format log message */
|
|
len = vsnprintf(buff, maxlen, fmt, ap);
|
|
if (len < 0 || len == maxlen) {
|
|
return -1;
|
|
}
|
|
buff += len;
|
|
total_len += len;
|
|
|
|
/* return total length */
|
|
return total_len;
|
|
}
|
|
int mylog_init(char* logfile,
|
|
char* loglvl,
|
|
int max_log_size,
|
|
int max_log_count)
|
|
{
|
|
int flag = 0;
|
|
int rc = 0;
|
|
|
|
if (isatty(STDERR_FILENO)) {
|
|
flag = TLOG_SCREEN_COLOR;
|
|
}
|
|
|
|
rc = tlog_init(logfile, max_log_size,
|
|
max_log_count, 0, flag);
|
|
if (rc >= 0) {
|
|
rc = tlog_setlevel(name_to_level(loglvl));
|
|
}
|
|
|
|
tlog_reg_format_func(my_tlog_format);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int mylog_setlevel(char* level)
|
|
{
|
|
return tlog_setlevel(name_to_level(level));
|
|
}
|
|
|
|
void mylog_fini()
|
|
{
|
|
tlog_exit();
|
|
}
|
|
|
|
static _Thread_local ectx_t ectx;
|
|
|
|
void set_error(char* file,
|
|
char* func,
|
|
int line,
|
|
int code)
|
|
{
|
|
ectx.file = file;
|
|
ectx.func = func;
|
|
ectx.line = line;
|
|
ectx.code = code;
|
|
errno = code;
|
|
}
|
|
|
|
ectx_t* get_ectx()
|
|
{
|
|
return &ectx;
|
|
}
|
|
|
|
static char* xce_err_str[] = {
|
|
"invalid job",
|
|
"invalid worker",
|
|
"duplicated jobs",
|
|
"duplicated workers",
|
|
"bad opcode",
|
|
"unknown role",
|
|
"unknown resource",
|
|
"unknown queue",
|
|
"unknown group",
|
|
"internal error",
|
|
NULL
|
|
};
|
|
|
|
int xce_strerror_r(int errnum,
|
|
char* buf,
|
|
size_t bufsize)
|
|
{
|
|
if (errnum < XCE_ERRNO_BASE) {
|
|
return strerror_r(errnum, buf, bufsize);
|
|
}
|
|
|
|
if (errnum >= E_XCE_MAX) {
|
|
strncpy(buf, "unknown error", bufsize);
|
|
return -1;
|
|
}
|
|
|
|
strncpy(buf, xce_err_str[errnum - XCE_ERRNO_BASE],
|
|
bufsize);
|
|
return 0;
|
|
}
|
|
|
|
int copy_int_list(int** dst,
|
|
int* src,
|
|
int count)
|
|
{
|
|
int i;
|
|
|
|
FREEUP(*dst);
|
|
if (count == 0) {
|
|
return 0;
|
|
}
|
|
|
|
*dst = (int*)calloc(count, sizeof(int));
|
|
if ((*dst) == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
(*dst)[i] = (int)src[i];
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int copy_strlist(xce_strlist_t* dst,
|
|
xce_strlist_t src)
|
|
{
|
|
if (!dst) {
|
|
return -1;
|
|
}
|
|
for (int i = 0; i < dst->count; i++) {
|
|
FREEUP(dst->data[i]);
|
|
}
|
|
FREEUP(dst->data);
|
|
dst->count = src.count;
|
|
if (dst->count == 0) {
|
|
return 0;
|
|
}
|
|
|
|
dst->data = (char**)calloc(dst->count, sizeof(char*));
|
|
if (dst->data == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
for (int i = 0; i < src.count; i++) {
|
|
if (src.data[i]) {
|
|
dst->data[i] = strndup(src.data[i], strlen(src.data[i]));
|
|
if (dst->data[i] == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
void free_resval_with_idx_list(xce_val_with_idx_t*** vals,
|
|
int count)
|
|
{
|
|
xce_val_with_idx_t** resvals = *vals;
|
|
int i;
|
|
|
|
if (resvals == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (count <= 0) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
xce_val_with_idx_t* val = resvals[i];
|
|
|
|
if (val == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (val->val->which == Value_u_svalue) {
|
|
FREEUP(val->val->u.svalue);
|
|
}
|
|
|
|
FREEUP(val->val);
|
|
FREEUP(val);
|
|
}
|
|
|
|
FREEUP(resvals);
|
|
*vals = NULL;
|
|
}
|
|
|
|
void free_strlist(xce_strlist_t* l)
|
|
{
|
|
int i;
|
|
|
|
if (l == NULL) {
|
|
return;
|
|
}
|
|
|
|
if ((l->count <= 0) || (l->data == NULL)) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < l->count; i++) {
|
|
FREEUP(l->data[i]);
|
|
}
|
|
|
|
FREEUP(l->data);
|
|
}
|