int sdb_unixsock_client_connect(sdb_unixsock_client_t *client) { struct sockaddr_un sa; int fd; if ((! client) || (! client->path)) return -1; memset(&sa, 0, sizeof(sa)); if (client->fh) fclose(client->fh); fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0); if (fd < 0) { char errbuf[1024]; sdb_log(SDB_LOG_ERR, "unixsock: Failed to open socket: %s", sdb_strerror(errno, errbuf, sizeof(errbuf))); return -1; } sa.sun_family = AF_UNIX; strncpy(sa.sun_path, client->path, sizeof(sa.sun_path)); sa.sun_path[sizeof(sa.sun_path) - 1] = '\0'; if (connect(fd, (struct sockaddr *)&sa, sizeof(sa))) { char errbuf[1024]; sdb_log(SDB_LOG_ERR, "unixsock: Failed to connect to %s: %s", sa.sun_path, sdb_strerror(errno, errbuf, sizeof(errbuf))); close(fd); return -1; } client->fh = fdopen(fd, "r+"); if (! client->fh) { char errbuf[1024]; sdb_log(SDB_LOG_ERR, "unixsock: Failed to open I/O " "stream for %s: %s", sa.sun_path, sdb_strerror(errno, errbuf, sizeof(errbuf))); close(fd); return -1; } /* enable line-buffering */ setvbuf(client->fh, NULL, _IOLBF, 0); client->shutdown = 0; return 0; } /* sdb_unixsock_client_connect */
int sdb_unixsock_client_send(sdb_unixsock_client_t *client, const char *msg) { int status; if ((! client) || (! client->fh)) return -1; if (client->shutdown & SDB_SHUT_WR) /* reconnect */ sdb_unixsock_client_connect(client); status = fprintf(client->fh, "%s\r\n", msg); if (status < 0) { char errbuf[1024]; sdb_log(SDB_LOG_ERR, "unixsock: Failed to write to " "socket (%s): %s", client->path, sdb_strerror(errno, errbuf, sizeof(errbuf))); return status; } return status; } /* sdb_unixsock_client_send */
char * sdb_unixsock_client_recv(sdb_unixsock_client_t *client, char *buffer, size_t buflen) { char *tmp; if ((! client) || (! client->fh) || (! buffer)) return NULL; if (client->shutdown & SDB_SHUT_RD) /* reconnect */ sdb_unixsock_client_connect(client); tmp = NULL; while (tmp == NULL) { errno = 0; tmp = fgets(buffer, (int)buflen - 1, client->fh); if (! tmp) { if ((errno == EAGAIN) || (errno == EINTR)) continue; if (! feof(client->fh)) { char errbuf[1024]; sdb_log(SDB_LOG_ERR, "unixsock: Failed to read " "from socket (%s): %s", client->path, sdb_strerror(errno, errbuf, sizeof(errbuf))); } return NULL; } } buffer[buflen - 1] = '\0'; buflen = strlen(buffer); while (buflen && ((buffer[buflen - 1] == '\n') || (buffer[buflen - 1] == '\r'))) { buffer[buflen - 1] = '\0'; --buflen; } return buffer; } /* sdb_unixsock_client_recv */
int main(int argc, char **argv) { const char *host = NULL; char *homedir; char hist_file[1024] = ""; sdb_input_t input = SDB_INPUT_INIT; sdb_llist_t *commands = NULL; while (42) { int opt = getopt(argc, argv, "H:U:c:C:K:A:hV"); if (-1 == opt) break; switch (opt) { case 'H': host = optarg; break; case 'U': input.user = optarg; break; case 'c': { sdb_object_t *obj; if (! commands) commands = sdb_llist_create(); if (! commands) { sdb_log(SDB_LOG_ERR, "Failed to create list object"); exit(1); } if (! (obj = sdb_object_create_T(optarg, sdb_object_t))) { sdb_log(SDB_LOG_ERR, "Failed to create object"); exit(1); } if (sdb_llist_append(commands, obj)) { sdb_log(SDB_LOG_ERR, "Failed to append command to list"); sdb_object_deref(obj); exit(1); } sdb_object_deref(obj); } break; case 'C': ssl_options.cert_file = optarg; break; case 'K': ssl_options.key_file = optarg; break; case 'A': ssl_options.ca_file = optarg; break; case 'h': exit_usage(argv[0], 0); break; case 'V': exit_version(); break; default: exit_usage(argv[0], 1); } } if (optind < argc) exit_usage(argv[0], 1); if (! host) host = DEFAULT_SOCKET; if (! input.user) input.user = sdb_get_current_user(); else input.user = strdup(input.user); if (! input.user) exit(1); if (sdb_ssl_init()) exit(1); input.client = sdb_client_create(host); if (! input.client) { sdb_log(SDB_LOG_ERR, "Failed to create client object"); sdb_input_reset(&input); exit(1); } canonicalize_ssl_options(); if (sdb_client_set_ssl_options(input.client, &ssl_options)) { sdb_log(SDB_LOG_ERR, "Failed to apply SSL options"); sdb_input_reset(&input); sdb_ssl_free_options(&ssl_options); exit(1); } sdb_ssl_free_options(&ssl_options); if (sdb_client_connect(input.client, input.user)) { sdb_log(SDB_LOG_ERR, "Failed to connect to SysDBd"); sdb_input_reset(&input); exit(1); } if (commands) { int status = execute_commands(input.client, commands); sdb_llist_destroy(commands); sdb_input_reset(&input); if ((status != SDB_CONNECTION_OK) && (status != SDB_CONNECTION_DATA)) exit(1); exit(0); } sdb_log(SDB_LOG_INFO, "SysDB client "SDB_CLIENT_VERSION_STRING SDB_CLIENT_VERSION_EXTRA" (libsysdbclient %s%s)", sdb_client_version_string(), sdb_client_version_extra()); sdb_command_print_server_version(&input); printf("\n"); using_history(); if ((homedir = sdb_get_homedir())) { snprintf(hist_file, sizeof(hist_file) - 1, "%s/.sysdb_history", homedir); hist_file[sizeof(hist_file) - 1] = '\0'; free(homedir); homedir = NULL; errno = 0; if (read_history(hist_file) && (errno != ENOENT)) { char errbuf[1024]; sdb_log(SDB_LOG_WARNING, "Failed to load history (%s): %s", hist_file, sdb_strerror(errno, errbuf, sizeof(errbuf))); } } input.input = sdb_strbuf_create(2048); sdb_input_init(&input); sdb_input_mainloop(); sdb_client_shutdown(input.client, SHUT_WR); while (! sdb_client_eof(input.client)) { /* wait for remaining data to arrive */ sdb_command_print_reply(input.client); } if (hist_file[0] != '\0') { errno = 0; if (write_history(hist_file)) { char errbuf[1024]; sdb_log(SDB_LOG_WARNING, "Failed to store history (%s): %s", hist_file, sdb_strerror(errno, errbuf, sizeof(errbuf))); } } sdb_input_reset(&input); sdb_ssl_shutdown(); return 0; } /* main */
static sdb_timeseries_t * sdb_rrd_fetch(const char *id, sdb_timeseries_opts_t *opts, sdb_object_t *user_data) { sdb_timeseries_t *ts; time_t start = (time_t)SDB_TIME_TO_SECS(opts->start); time_t end = (time_t)SDB_TIME_TO_SECS(opts->end); unsigned long step = 0; unsigned long ds_cnt = 0; unsigned long val_cnt = 0; char **ds_namv = NULL; rrd_value_t *data = NULL; if (user_data) { /* -> use RRDCacheD */ char *addr = SDB_OBJ_WRAPPER(user_data)->data; if (! rrdcached_connect(addr)) return NULL; #ifdef HAVE_RRD_CLIENT_H if (rrdc_flush(id)) { sdb_log(SDB_LOG_ERR, "Failed to flush '%s' through RRDCacheD: %s", id, rrd_get_error()); return NULL; } #endif } #define FREE_RRD_DATA() \ do { \ size_t i; \ for (i = 0; i < ds_cnt; ++i) \ rrd_freemem(ds_namv[i]); \ rrd_freemem(ds_namv); \ rrd_freemem(data); \ } while (0) /* limit to about 1000 data-points for now * TODO: make this configurable */ step = (end - start) / 1000; if (rrd_fetch_r(id, "AVERAGE", &start, &end, &step, &ds_cnt, &ds_namv, &data)) { char errbuf[1024]; sdb_strerror(errno, errbuf, sizeof(errbuf)); sdb_log(SDB_LOG_ERR, "Failed to fetch data from %s: %s", id, errbuf); return NULL; } val_cnt = (unsigned long)(end - start) / step; /* RRDtool does not support fetching specific data-sources, so we'll have * to filter the requested ones after fetching them all */ if (opts->data_names && opts->data_names_len) ts = sdb_timeseries_create(opts->data_names_len, (const char * const *)opts->data_names, val_cnt); else ts = sdb_timeseries_create(ds_cnt, (const char * const *)ds_namv, val_cnt); if (! ts) { char errbuf[1024]; sdb_strerror(errno, errbuf, sizeof(errbuf)); sdb_log(SDB_LOG_ERR, "Failed to allocate time-series object: %s", errbuf); FREE_RRD_DATA(); return NULL; } ts->start = SECS_TO_SDB_TIME(start + (time_t)step); ts->end = SECS_TO_SDB_TIME(end); if (copy_data(ts, data, (time_t)step, (size_t)ds_cnt, ds_namv) < 0) { FREE_RRD_DATA(); sdb_timeseries_destroy(ts); return NULL; } FREE_RRD_DATA(); return ts; } /* sdb_rrd_fetch */
static int connection_init(sdb_object_t *obj, va_list ap) { sdb_conn_t *conn; int sock_fd; int sock_fl; assert(obj); conn = CONN(obj); sock_fd = va_arg(ap, int); conn->buf = sdb_strbuf_create(/* size = */ 128); if (! conn->buf) { sdb_log(SDB_LOG_ERR, "frontend: Failed to allocate a read buffer " "for a new connection"); return -1; } conn->errbuf = sdb_strbuf_create(0); if (! conn->errbuf) { sdb_log(SDB_LOG_ERR, "frontend: Failed to allocate an error buffer " "for a new connection"); return -1; } conn->client_addr_len = sizeof(conn->client_addr); conn->fd = accept(sock_fd, (struct sockaddr *)&conn->client_addr, &conn->client_addr_len); if (conn->fd < 0) { char buf[1024]; sdb_log(SDB_LOG_ERR, "frontend: Failed to accept remote " "connection: %s", sdb_strerror(errno, buf, sizeof(buf))); return -1; } /* update the object name */ snprintf(obj->name + strlen(CONN_FD_PREFIX), strlen(CONN_FD_PLACEHOLDER), "%i", conn->fd); /* defaults */ conn->read = conn_read; conn->write = conn_write; conn->finish = NULL; conn->ssl_session = NULL; sock_fl = fcntl(conn->fd, F_GETFL); if (fcntl(conn->fd, F_SETFL, sock_fl | O_NONBLOCK)) { char buf[1024]; sdb_log(SDB_LOG_ERR, "frontend: Failed to switch connection conn#%i " "to non-blocking mode: %s", conn->fd, sdb_strerror(errno, buf, sizeof(buf))); return -1; } conn->username = NULL; conn->ready = 0; sdb_log(SDB_LOG_DEBUG, "frontend: Accepted connection on fd=%i", conn->fd); conn->cmd = SDB_CONNECTION_IDLE; conn->cmd_len = 0; conn->skip_len = 0; return 0; } /* connection_init */