#include #include #include #include #include #if defined(__GLIBC__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ < 28) #include #else #include #endif #include #include #if defined(__linux__) #include #endif #include #include "config.h" #include "controller.capnp.h" #include #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); }