/* * Buxton * * Copyright (C) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "log.h" #include "direct.h" #include "proto.h" #include "serialize.h" #include "config.h" #include "daemon.h" #include "socks.h" #include "cynara.h" #include "dbus.h" #include "cache.h" #define BXT_LOG_FOLDER "/run/buxton2/log" #define BXT_NULL_STRING "(VCONF_NULL)" #define BXT_SYSTEM_DB_LAYER "system" #define BXT_SYSTEM_MEMORY_LAYER "memory" static int _log_max_line = 2000; static bool _log_on = true; static FILE *_fp; enum log_type { LOG_SET, LOG_NOTI, LOG_DELAYED_NOTI, LOG_SEND_DELAYED_NOTI, LOG_REG_NOTI, LOG_UNREG_NOTI, LOG_MAX }; static char *log_map[] = { "SET", "NOTIFY", "DELAYED_NOTI", "SEND_DELAYED_NOTI", "REG_NOTI", "UNREG_NOTI" }; struct bxt_noti { char *layer_key; GList *clients; /* struct bxt_client */ }; static bool _init_log(); static void _write_file_log(enum log_type type, struct bxt_client *cli, struct request *rqst); static gboolean signal_cb(gint fd, GIOCondition cond, gpointer data) { struct bxt_daemon *bxtd = data; int r; struct signalfd_siginfo si; r = read(fd, &si, sizeof(struct signalfd_siginfo)); if (r == -1) { bxt_err("Read signalfd: %d", errno); return G_SOURCE_CONTINUE; } if (r != sizeof(struct signalfd_siginfo)) { bxt_err("Invalid siginfo received"); return G_SOURCE_CONTINUE; } switch (si.ssi_signo) { case SIGINT: case SIGTERM: g_main_loop_quit(bxtd->loop); break; case SIGPIPE: /* Ignore signal */ break; } return G_SOURCE_CONTINUE; } static int create_sigfd(void) { int r; int fd; sigset_t mask; sigset_t old; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGPIPE); r = sigprocmask(SIG_BLOCK, &mask, &old); if (r == -1) { bxt_err("sigprocmask: %d", errno); return -1; } fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); if (fd == -1) { bxt_err("signalfd: %d", errno); sigprocmask(SIG_SETMASK, &old, NULL); return -1; } return fd; } static void remove_noti_cli(struct bxt_daemon *bxtd, struct bxt_client *cli) { GList *l; struct bxt_noti *noti; for (l = cli->notilist; l; l = g_list_next(l)) { noti = l->data; noti->clients = g_list_remove(noti->clients, cli); bxt_dbg("client %p deleted from noti %p list", cli, noti); if (!noti->clients) { g_hash_table_remove(bxtd->notis, noti->layer_key); bxt_dbg("noti %p deleted from table", noti); } } } static void remove_notilist(struct bxt_noti *noti) { GList *l; struct bxt_client *cli; for (l = noti->clients; l; l = g_list_next(l)) { cli = l->data; cli->notilist = g_list_remove(cli->notilist, noti); bxt_dbg("noti %p deleted from client %p", noti, cli); } } static void free_noti(struct bxt_noti *noti) { if (!noti) return; remove_notilist(noti); g_list_free(noti->clients); noti->clients = NULL; free(noti->layer_key); free(noti); bxt_dbg("free noti %p", noti); } static gboolean del_client(gpointer data) { struct bxt_client *cli = data; if (!cli || !cli->bxtd || !cli->bxtd->clients) return G_SOURCE_REMOVE; buxton_cynara_cancel(cli); bxt_dbg("Client %p removed", cli); g_hash_table_remove(cli->bxtd->clients, cli); return G_SOURCE_REMOVE; } static void send_res(struct bxt_client *cli, struct response *resp) { int r; uint8_t *data; int len; if (resp->res != BUXTON_ERROR_NONE) bxt_err("send res: error %d", resp->res); r = serialz_response(resp->type, resp->msgid, resp->res, resp->val, resp->nmlen, resp->names, &data, &len); if (r != BUXTON_ERROR_NONE) { bxt_err("send res: fd %d msgid %u: serialize error : %d", cli->fd, resp->msgid, r); return; } r = proto_send_block(cli->fd, resp->type, data, len); free(data); if (r != BUXTON_ERROR_NONE) bxt_err("send res: error %d", r); } static int get_search_key_u(const struct buxton_layer *layer, const char *key, char **lykey) { char uid[16]; char *u; const struct layer *ly; int ret; ret = conf_get_layer(layer->name, &ly); if (ret != BUXTON_ERROR_NONE) return ret; if (ly->type == LAYER_USER) { snprintf(uid, sizeof(uid), "%d", layer->uid); u = uid; } else { u = NULL; } return get_search_key(layer, key, u, lykey); } static gboolean _send_notis(gpointer key, gpointer value, gpointer data) { int r; guchar *_data; gsize _len; struct bxt_client *cli = (struct bxt_client *)data; gchar *g_data = (gchar *)value; _data = g_base64_decode(g_data, &_len); r = proto_send(cli->fd, MSG_NOTI, (uint8_t *)_data, (int)_len); free(_data); if (r != BUXTON_ERROR_NONE) { bxt_err("send noti again key : %s pid : %d return value : %d", (char *)key, cli->cred.pid, r); if (r == BUXTON_ERROR_TIME_OUT) return FALSE; } else { _write_file_log(LOG_SEND_DELAYED_NOTI, cli, NULL); } return TRUE; } static gboolean _send_delayed_noti(gint fd, GIOCondition cond, gpointer data) { struct bxt_client *cli = (struct bxt_client *)data; if (cli->delay_notilist && g_hash_table_size(cli->delay_notilist) > 0) g_hash_table_foreach_remove(cli->delay_notilist, (GHRFunc)_send_notis, cli); if (g_hash_table_size(cli->delay_notilist) > 0) return G_SOURCE_CONTINUE; cli->fd_out_id = 0; return G_SOURCE_REMOVE; } static void send_notis(struct bxt_daemon *bxtd, struct request *rqst) { int r; char *lykey; struct bxt_noti *noti; GList *l; struct request req; uint8_t *data; int len; gchar *_data; r = get_search_key_u(rqst->layer, rqst->key, &lykey); if (r != BUXTON_ERROR_NONE) return; noti = g_hash_table_lookup(bxtd->notis, lykey); free(lykey); if (!noti) return; memset(&req, 0, sizeof(req)); req.type = MSG_NOTI; req.layer = rqst->layer; req.key = rqst->key; req.val = rqst->val; r = serialz_request(&req, &data, &len); if (r != BUXTON_ERROR_NONE) return; for (l = noti->clients; l; l = g_list_next(l)) { struct bxt_client *cli = l->data; r = proto_send(cli->fd, req.type, data, len); if (r != BUXTON_ERROR_NONE) { bxt_err("send notis: cli pid : %d label : %s key : %s error %d", cli->cred.pid, cli->label, rqst->key, r); if (r == BUXTON_ERROR_TIME_OUT) { _data = g_base64_encode(data, len); if (cli->fd_out_id == 0) { cli->fd_out_id = g_unix_fd_add_full(G_PRIORITY_DEFAULT, cli->fd, G_IO_OUT, _send_delayed_noti, cli, NULL); } if (!cli->delay_notilist) { cli->delay_notilist = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)free, (GDestroyNotify)g_free); } g_hash_table_replace(cli->delay_notilist, strdup(rqst->key), _data); _write_file_log(LOG_DELAYED_NOTI, cli, rqst); } } else { _write_file_log(LOG_NOTI, cli, rqst); if (cli->delay_notilist) g_hash_table_remove(cli->delay_notilist, rqst->key); } } free(data); } static void proc_set(struct bxt_client *cli, struct request *rqst, struct response *resp) { resp->res = direct_set(rqst->layer, rqst->key, rqst->val); if (resp->res == BUXTON_ERROR_NONE) _write_file_log(LOG_SET, cli, rqst); } static void proc_get(struct bxt_client *cli, struct request *rqst, struct response *resp) { struct buxton_value *val; val = calloc(1, sizeof(*val)); if (!val) { bxt_err("out of memory"); resp->res = BUXTON_ERROR_OUT_OF_MEMORY; return; } resp->res = direct_get(rqst->layer, rqst->key, val); if (resp->res != BUXTON_ERROR_NONE) { free(val); return; } resp->val = val; } static void proc_list(struct bxt_client *cli, struct request *rqst, struct response *resp) { resp->res = direct_list(rqst->layer, &resp->names, &resp->nmlen, true); } static void proc_create(struct bxt_client *cli, struct request *rqst, struct response *resp) { if (cli->cred.uid != 0) { resp->res = BUXTON_ERROR_PERMISSION_DENIED; return; } resp->res = direct_create(rqst->layer, rqst->key, rqst->rpriv, rqst->wpriv, rqst->val); } static void proc_unset(struct bxt_client *cli, struct request *rqst, struct response *resp) { if (cli->cred.uid != 0) { resp->res = BUXTON_ERROR_PERMISSION_DENIED; return; } resp->res = direct_unset(rqst->layer, rqst->key); } static void add_cli(struct bxt_noti *noti, struct bxt_client *client) { GList *l; for (l = noti->clients; l; l = g_list_next(l)) { if (l->data == client) return; } noti->clients = g_list_append(noti->clients, client); client->notilist = g_list_append(client->notilist, noti); bxt_dbg("proc notify: noti %p '%s' client %p added", noti, noti->layer_key, client); } static void proc_notify(struct bxt_client *cli, struct request *rqst, struct response *resp) { char *lykey; struct bxt_noti *noti; resp->res = direct_check(rqst->layer, rqst->key); if (resp->res != BUXTON_ERROR_NONE) return; resp->res = get_search_key_u(rqst->layer, rqst->key, &lykey); if (resp->res != BUXTON_ERROR_NONE) return; noti = g_hash_table_lookup(cli->bxtd->notis, lykey); if (!noti) { noti = calloc(1, sizeof(*noti)); if (!noti) { bxt_err("out of memory"); resp->res = BUXTON_ERROR_OUT_OF_MEMORY; return; } noti->layer_key = lykey; g_hash_table_insert(cli->bxtd->notis, noti->layer_key, noti); bxt_dbg("proc notify: noti %p '%s' added", noti, lykey); } else { free(lykey); } add_cli(noti, cli); _write_file_log(LOG_REG_NOTI, cli, rqst); resp->res = BUXTON_ERROR_NONE; } static void proc_unnotify(struct bxt_client *cli, struct request *rqst, struct response *resp) { char *lykey; struct bxt_noti *noti; resp->res = get_search_key_u(rqst->layer, rqst->key, &lykey); if (resp->res != BUXTON_ERROR_NONE) return; noti = g_hash_table_lookup(cli->bxtd->notis, lykey); if (!noti) { bxt_dbg("%s does not exist", lykey); free(lykey); resp->res = BUXTON_ERROR_NOT_EXIST; return; } cli->notilist = g_list_remove(cli->notilist, noti); noti->clients = g_list_remove(noti->clients, cli); bxt_dbg("proc notify: noti %p '%s' client %p deleted", noti, noti->layer_key, cli); if (!noti->clients) /* no client */ g_hash_table_remove(cli->bxtd->notis, lykey); _write_file_log(LOG_UNREG_NOTI, cli, rqst); resp->res = BUXTON_ERROR_NONE; free(lykey); } static void proc_set_priv(struct bxt_client *cli, struct request *rqst, struct response *resp) { enum buxton_priv_type type; if (cli->cred.uid != 0) { resp->res = BUXTON_ERROR_PERMISSION_DENIED; return; } if (rqst->type == MSG_SET_WP) type = BUXTON_PRIV_WRITE; else type = BUXTON_PRIV_READ; resp->res = direct_set_priv(rqst->layer, rqst->key, type, rqst->val->value.s); } static void proc_get_priv(struct bxt_client *cli, struct request *rqst, struct response *resp) { enum buxton_priv_type type; struct buxton_value *val; val = calloc(1, sizeof(*val)); if (!val) { bxt_err("out of memory"); resp->res = BUXTON_ERROR_OUT_OF_MEMORY; return; } if (rqst->type == MSG_GET_WP) type = BUXTON_PRIV_WRITE; else type = BUXTON_PRIV_READ; val->type = BUXTON_TYPE_PRIVILEGE; resp->res = direct_get_priv(rqst->layer, rqst->key, type, &val->value.s); if (resp->res != BUXTON_ERROR_NONE) { free(val); return; } resp->val = val; } static void update_label(gpointer key, gpointer value, gpointer user_data) { int fd; int ret; char buf[1024]; char path[1024]; struct bxt_client *cli = (struct bxt_client *)value; int pid = *(int *)user_data; if (cli->cred.pid != pid) return; snprintf(path, sizeof(path), "/proc/%d/attr/current", cli->cred.pid); fd = open(path, O_RDONLY); if (fd < 0) return; ret = read(fd, buf, sizeof(buf) - 1); if (ret <= 0) { close(fd); return; } else { buf[ret] = 0; } close(fd); if (cli->label) free(cli->label); cli->label = strdup(buf); } static int update_client_label(struct bxt_client *cli) { g_hash_table_foreach(cli->bxtd->clients, (GHFunc)update_label, &(cli->cred.pid)); return BUXTON_ERROR_NONE; } static void proc_control(struct bxt_client *cli, struct request *rqst, struct response *resp) { if (!strcmp(rqst->key, "set_security_mode")) { if (cli->cred.uid != 0) { resp->res = BUXTON_ERROR_PERMISSION_DENIED; return; } if (rqst->val->value.b == TRUE) buxton_cynara_enable(); else buxton_cynara_disable(); resp->res = BUXTON_ERROR_NONE; return; } else if (!strcmp(rqst->key, "update_client_label")) { resp->res = update_client_label(cli); return; } resp->res = BUXTON_ERROR_INVALID_OPERATION; } typedef void (*proc_func)(struct bxt_client *cli, struct request *, struct response *); static proc_func proc_funcs[MSG_MAX] = { [MSG_SET] = proc_set, [MSG_GET] = proc_get, [MSG_LIST] = proc_list, [MSG_CREAT] = proc_create, [MSG_UNSET] = proc_unset, [MSG_NOTIFY] = proc_notify, [MSG_UNNOTIFY] = proc_unnotify, [MSG_SET_WP] = proc_set_priv, [MSG_SET_RP] = proc_set_priv, [MSG_GET_WP] = proc_get_priv, [MSG_GET_RP] = proc_get_priv, [MSG_CTRL] = proc_control, }; static void proc_msg(struct bxt_client *cli, struct request *rqst, struct response *resp) { if (!cli || !rqst || !resp || !rqst->layer) { bxt_err("Invalid parameter"); return; } if (rqst->type <= MSG_UNKNOWN || rqst->type >= MSG_MAX) { bxt_err("proc msg: invalid type %d", rqst->type); resp->res = BUXTON_ERROR_INVALID_PARAMETER; return; } if (cli->cred.uid != 0 && cli->cred.uid != rqst->layer->uid) { /* Only root can access other user's */ resp->res = BUXTON_ERROR_PERMISSION_DENIED; return; } if (!proc_funcs[rqst->type]) { bxt_err("proc msg: %d not supported", rqst->type); resp->res = BUXTON_ERROR_INVALID_OPERATION; return; } proc_funcs[rqst->type](cli, rqst, resp); } static void cyn_cb(struct bxt_client *cli, enum buxton_cynara_res res, void *data) { struct request *rqst = data; struct response resp; if (!rqst) { bxt_err("Invalid parameter"); return; } memset(&resp, 0, sizeof(resp)); resp.type = rqst->type; resp.msgid = rqst->msgid; switch (res) { case BUXTON_CYNARA_ALLOWED: proc_msg(cli, rqst, &resp); break; case BUXTON_CYNARA_DENIED: default: resp.res = BUXTON_ERROR_PERMISSION_DENIED; break; } send_res(cli, &resp); if (rqst->type == MSG_SET) send_notis(cli->bxtd, rqst); free_response(&resp); free_request(rqst); free(rqst); } static int check_priv(struct bxt_client *cli, struct request *rqst) { int r; enum buxton_priv_type type; char *priv; switch (rqst->type) { case MSG_SET: case MSG_GET: case MSG_NOTIFY: if (rqst->type == MSG_SET) type = BUXTON_PRIV_WRITE; else type = BUXTON_PRIV_READ; r = direct_get_priv(rqst->layer, rqst->key, type, &priv); if (r != BUXTON_ERROR_NONE) break; bxt_dbg("priv '%s'", priv); r = buxton_cynara_check(cli, cli->label, "", cli->cred.uid, priv, cli->cred.pid, rqst->key, cyn_cb, rqst); free(priv); break; default: r = BUXTON_CYNARA_ALLOWED; break; } return r; } static int proc_serialized_msg(struct bxt_client *cli, uint8_t *data, int len) { int r; struct request *rqst; struct response resp; rqst = calloc(1, sizeof(*rqst)); if (!rqst) { bxt_err("out of memory"); return BUXTON_ERROR_OUT_OF_MEMORY; } r = deserialz_request(data, len, rqst); if (r != BUXTON_ERROR_NONE) { free(rqst); return r; } r = check_priv(cli, rqst); /* wait for cynara response, rqst should be freed in callback */ if (r == BUXTON_CYNARA_UNKNOWN) return BUXTON_ERROR_NONE; memset(&resp, 0, sizeof(resp)); resp.type = rqst->type; resp.msgid = rqst->msgid; if (r != BUXTON_CYNARA_ALLOWED) resp.res = r == BUXTON_CYNARA_DENIED ? BUXTON_ERROR_PERMISSION_DENIED : r; else proc_msg(cli, rqst, &resp); send_res(cli, &resp); if (rqst->type == MSG_SET) send_notis(cli->bxtd, rqst); free_response(&resp); free_request(rqst); free(rqst); return BUXTON_ERROR_NONE; } static int proc_client_msg(struct bxt_client *cli) { int r; uint8_t *data; int len; enum message_type type; r = proto_recv(cli->fd, &type, &data, &len); if (r != BUXTON_ERROR_NONE) return r; switch (type) { case MSG_SET: case MSG_GET: case MSG_CREAT: case MSG_UNSET: case MSG_LIST: case MSG_NOTIFY: case MSG_UNNOTIFY: case MSG_SET_WP: case MSG_SET_RP: case MSG_GET_WP: case MSG_GET_RP: case MSG_CTRL: r = proc_serialized_msg(cli, data, len); break; case MSG_NOTI: default: bxt_err("proc msg: Invalid message type %d", type); r = BUXTON_ERROR_INVALID_PARAMETER; break; } free(data); return r; } static gboolean client_cb(gint fd, GIOCondition cond, gpointer data) { int r, proc_fd; char proc_name[512] = {0,}; char buf[512] = {0,}; struct bxt_client *cli = data; assert(cli); bxt_dbg("Client %d: cond %x", fd, cond); if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { if (cond & (G_IO_ERR | G_IO_NVAL)) bxt_err("Client %d: PID %d(%s) IO %s", fd, cli->cred.pid, cli->label ? cli->label : "", cond & G_IO_ERR ? "error" : "nval"); cli->fd_id = 0; g_idle_add(del_client, cli); return G_SOURCE_REMOVE; } if (cli->cred.pid == 0) { sock_get_client_cred(fd, &cli->cred); sock_get_client_label(fd, &cli->label); snprintf(buf, sizeof(buf), "/proc/%d/cmdline", cli->cred.pid); proc_fd = open(buf, O_RDONLY); if (proc_fd >= 0) { r = read(proc_fd, proc_name, sizeof(proc_name) - 1); if (r < 0) bxt_err("Cannot read %s: %d", buf, errno); close(proc_fd); if (strlen(proc_name) > 0) cli->process_name = strdup(proc_name); } } r = proc_client_msg(cli); if (r != BUXTON_ERROR_NONE) { cli->fd_id = 0; g_idle_add(del_client, cli); return G_SOURCE_REMOVE; } return G_SOURCE_CONTINUE; } static void add_client(struct bxt_daemon *bxtd, int fd) { int r; struct bxt_client *cli; r = sock_set_client(fd); if (r != BUXTON_ERROR_NONE) { close(fd); return; } cli = calloc(1, sizeof(*cli)); if (!cli) { bxt_err("Client %d: out of memory", fd); close(fd); return; } cli->fd = fd; cli->bxtd = bxtd; cli->fd_id = g_unix_fd_add(fd, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, client_cb, cli); cli->fd_out_id = 0; g_hash_table_insert(bxtd->clients, cli, cli); bxt_dbg("Client %p added, fd %d", cli, fd); } static gboolean accept_cb(gint fd, GIOCondition cond, gpointer data) { struct bxt_daemon *bxtd = data; int cfd; struct sockaddr sa; socklen_t addrlen; bxt_dbg("Accept: fd %d cond %x", fd, cond); addrlen = sizeof(sa); cfd = accept(fd, (struct sockaddr *)&sa, &addrlen); if (cfd == -1) { if (errno == EMFILE) { bxt_err("Too many open files, stop calling accept()"); bxtd->sk_id = 0; return G_SOURCE_REMOVE; } bxt_err("Accept: %d", errno); return G_SOURCE_CONTINUE; } add_client(bxtd, cfd); return G_SOURCE_CONTINUE; } static void resume_accept(struct bxt_daemon *bxtd) { if (bxtd->sk_id == 0) { bxt_err("Resume calling accept()"); bxtd->sk_id = g_unix_fd_add(bxtd->sk, G_IO_IN, accept_cb, bxtd); } } static void free_client(struct bxt_client *cli) { if (!cli) return; resume_accept(cli->bxtd); remove_noti_cli(cli->bxtd, cli); g_list_free(cli->notilist); cli->notilist = NULL; if (cli->delay_notilist) g_hash_table_destroy(cli->delay_notilist); if (cli->fd_id) g_source_remove(cli->fd_id); if (cli->fd_out_id) g_source_remove(cli->fd_out_id); if (cli->fd != -1) close(cli->fd); if (cli->process_name) free(cli->process_name); free(cli->label); free(cli); bxt_dbg("free client %p", cli); } static bool _init_log() { char buffer[256] = {0, }; int ret; ret = mkdir(BXT_LOG_FOLDER, 0755); if (ret < 0 && errno != EEXIST) { bxt_err("Failed to mkdir %s - %d", BXT_LOG_FOLDER, errno); return false; } snprintf(buffer, sizeof(buffer), "%s/log_%d.log", BXT_LOG_FOLDER, getpid()); _fp = fopen(buffer, "wt"); if (_fp == NULL) { bxt_err("Failed to open %s - %d", buffer, errno); return false; } return true; } static void _write_file_log(enum log_type type, struct bxt_client *cli, struct request *rqst) { char buf[512] = {0,}; char time_buf[32] = {0,}; char tmp_value[32] = {0,}; char *label; char *value = NULL; int ret = 0; time_t now; static enum log_type prev_type = LOG_MAX; static int _log_index = 0; if (_log_on == false) return; if (_fp == NULL) { if (_init_log() == false) return; } if (_log_index >= _log_max_line) { fseek(_fp, 0, SEEK_SET); _log_index = 0; } if (cli->process_name != NULL) label = cli->process_name; else label = cli->label; time(&now); ctime_r(&now, time_buf); /* remove newline */ if (strlen(time_buf) > 1) time_buf[strlen(time_buf) -1] = '\0'; if (type == LOG_NOTI) { if (prev_type != type) { _log_index++; snprintf(buf, sizeof(buf), "\n[%5d]%s %-18s %s - pid(%d:%s)", _log_index, time_buf, log_map[type], rqst->key, cli->cred.pid, label); } else { snprintf(buf, sizeof(buf), ", pid(%d:%s)", cli->cred.pid, label); } } else { _log_index++; snprintf(buf, sizeof(buf), "\n[%5d]%s %-18s - pid(%d:%s) - %s ", _log_index, time_buf, log_map[type], cli->cred.pid, label, rqst ? rqst->key : "NULL"); if (type == LOG_SET && rqst) { value = tmp_value; switch (rqst->val->type) { case BUXTON_TYPE_STRING: value = rqst->val->value.s; break; case BUXTON_TYPE_INT32: snprintf(tmp_value, sizeof(tmp_value), "%d", rqst->val->value.i); break; case BUXTON_TYPE_UINT32: snprintf(tmp_value, sizeof(tmp_value), "%u", rqst->val->value.u); break; case BUXTON_TYPE_INT64: snprintf(tmp_value, sizeof(tmp_value), "%"PRId64, rqst->val->value.i64); break; case BUXTON_TYPE_UINT64: snprintf(tmp_value, sizeof(tmp_value), "%"PRIu64, rqst->val->value.u64); break; case BUXTON_TYPE_DOUBLE: snprintf(tmp_value, sizeof(tmp_value), "%lf", rqst->val->value.d); break; case BUXTON_TYPE_BOOLEAN: if (rqst->val->value.b) snprintf(tmp_value, sizeof(tmp_value), "True"); else snprintf(tmp_value, sizeof(tmp_value), "False"); break; default: snprintf(tmp_value, sizeof(tmp_value), "Unknown type"); break; } } } if (value == NULL || strlen(value) == 0) value = BXT_NULL_STRING; ret = fwrite(buf, strlen(buf), 1 , _fp); if (ret <= 0) { bxt_err("Cannot write the key log: %d, type(%d) pid(%d:%s) %s %s", errno, type, cli->cred.pid, label, rqst ? rqst->key : BXT_NULL_STRING, value); return; } if (type == LOG_SET) { ret = fwrite(value, strlen(value), 1, _fp); if (ret <= 0) { bxt_err("Cannot write the value log: %d, type(%d) pid(%d:%s) %s %s", errno, type, cli->cred.pid, label, rqst ? rqst->key : BXT_NULL_STRING, value); return; } } prev_type = type; } static void bxt_exit(struct bxt_daemon *bxtd) { buxton_cynara_exit(); if (bxtd->notis) g_hash_table_destroy(bxtd->notis); if (bxtd->clients) g_hash_table_destroy(bxtd->clients); if (bxtd->loop) g_main_loop_unref(bxtd->loop); if (bxtd->sk != -1) close(bxtd->sk); direct_exit(); buxton_dbus_exit(); if (bxtd->sigfd != -1) close(bxtd->sigfd); } static int bxt_init(struct bxt_daemon *bxtd, const char *confpath) { int r; bxtd->clients = g_hash_table_new_full(g_direct_hash, g_direct_equal, (GDestroyNotify)free_client, NULL); if (!bxtd->clients) { bxt_err("out of memory"); return BUXTON_ERROR_OUT_OF_MEMORY; } bxtd->notis = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)free_noti); if (!bxtd->notis) { bxt_err("out of memory"); return BUXTON_ERROR_OUT_OF_MEMORY; } bxtd->sigfd = create_sigfd(); g_unix_fd_add(bxtd->sigfd, G_IO_IN, signal_cb, bxtd); r = direct_init(MODULE_DIR, confpath, &_log_on, &_log_max_line); if (r != BUXTON_ERROR_NONE) return r; r = direct_db_check(BXT_SYSTEM_DB_LAYER); if (r != BUXTON_ERROR_NONE) return r; r = direct_db_check(BXT_SYSTEM_MEMORY_LAYER); if (r != BUXTON_ERROR_NONE) return r; bxtd->sk = sock_get_server(SOCKPATH); if (bxtd->sk < 0) return bxtd->sk; bxtd->sk_id = g_unix_fd_add(bxtd->sk, G_IO_IN, accept_cb, bxtd); r = buxton_cynara_init(); if (r != BUXTON_ERROR_NONE) return r; buxton_dbus_init(); bxtd->loop = g_main_loop_new(NULL, FALSE); return BUXTON_ERROR_NONE; } int start_daemon(struct bxt_daemon *bxtd, const char *confpath) { int r; if (!confpath) confpath = CONFPATH; r = bxt_init(bxtd, confpath); if (r != BUXTON_ERROR_NONE) { bxt_exit(bxtd); return EXIT_FAILURE; } cache_init(); g_main_loop_run(bxtd->loop); bxt_exit(bxtd); return EXIT_SUCCESS; }