|
@@ -13,6 +13,8 @@
|
|
|
#include <stdlib.h>
|
|
|
#include <unistd.h>
|
|
|
#include <sys/types.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <fcntl.h>
|
|
|
#include <sys/wait.h>
|
|
|
#include <errno.h>
|
|
|
#include <assert.h>
|
|
@@ -21,9 +23,12 @@
|
|
|
#include <string.h>
|
|
|
#include <sys/select.h>
|
|
|
#include <signal.h>
|
|
|
+#include <syslog.h>
|
|
|
#ifdef HAVE_GETOPT_H
|
|
|
#include <getopt.h>
|
|
|
#endif
|
|
|
+#include <pwd.h>
|
|
|
+#include <grp.h>
|
|
|
|
|
|
#include "clish/private.h"
|
|
|
#include "konf/tree.h"
|
|
@@ -38,7 +43,7 @@
|
|
|
#define QUOTE(t) #t
|
|
|
#define version(v) printf("%s\n", v)
|
|
|
|
|
|
-#define KONFD_CONFIG_PATH "/tmp/running-config"
|
|
|
+#define KONFD_PIDFILE "/var/run/konfd.pid"
|
|
|
|
|
|
|
|
|
#ifndef UNIX_PATH_MAX
|
|
@@ -60,67 +65,48 @@ static void help(int status, const char *argv0);
|
|
|
static char * process_query(int sock, konf_tree_t * conf, char *str);
|
|
|
int answer_send(int sock, char *command);
|
|
|
static int dump_running_config(int sock, konf_tree_t *conf, konf_query_t *query);
|
|
|
+int daemonize(int nochdir, int noclose);
|
|
|
+struct options *opts_init(void);
|
|
|
+void opts_free(struct options *opts);
|
|
|
+static int opts_parse(int argc, char *argv[], struct options *opts);
|
|
|
+
|
|
|
+
|
|
|
+struct options {
|
|
|
+ char *socket_path;
|
|
|
+ char *pidfile;
|
|
|
+ int debug;
|
|
|
+ uid_t uid;
|
|
|
+ gid_t gid;
|
|
|
+};
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
- int retval = 0;
|
|
|
+ int retval = -1;
|
|
|
unsigned i;
|
|
|
char *str;
|
|
|
konf_tree_t *conf;
|
|
|
lub_bintree_t bufs;
|
|
|
konf_buf_t *tbuf;
|
|
|
+ struct options *opts = NULL;
|
|
|
|
|
|
|
|
|
int sock;
|
|
|
struct sockaddr_un laddr;
|
|
|
struct sockaddr_un raddr;
|
|
|
fd_set active_fd_set, read_fd_set;
|
|
|
- const char *socket_path = KONFD_SOCKET_PATH;
|
|
|
|
|
|
|
|
|
struct sigaction sig_act, sigpipe_act;
|
|
|
sigset_t sig_set, sigpipe_set;
|
|
|
-
|
|
|
- static const char *shortopts = "hvs:";
|
|
|
-#ifdef HAVE_GETOPT_H
|
|
|
- static const struct option longopts[] = {
|
|
|
- {"help", 0, NULL, 'h'},
|
|
|
- {"version", 0, NULL, 'v'},
|
|
|
- {"socket", 1, NULL, 's'},
|
|
|
- {NULL, 0, NULL, 0}
|
|
|
- };
|
|
|
-#endif
|
|
|
+
|
|
|
+
|
|
|
+ openlog(argv[0], LOG_CONS | LOG_PERROR, LOG_DAEMON);
|
|
|
|
|
|
|
|
|
- optind = 0;
|
|
|
- while(1) {
|
|
|
- int opt;
|
|
|
-#ifdef HAVE_GETOPT_H
|
|
|
- opt = getopt_long(argc, argv, shortopts, longopts, NULL);
|
|
|
-#else
|
|
|
- opt = getopt(argc, argv, shortopts);
|
|
|
-#endif
|
|
|
- if (-1 == opt)
|
|
|
- break;
|
|
|
- switch (opt) {
|
|
|
- case 's':
|
|
|
- socket_path = optarg;
|
|
|
- break;
|
|
|
- case 'h':
|
|
|
- help(0, argv[0]);
|
|
|
- exit(0);
|
|
|
- break;
|
|
|
- case 'v':
|
|
|
- version(VERSION);
|
|
|
- exit(0);
|
|
|
- break;
|
|
|
- default:
|
|
|
- help(-1, argv[0]);
|
|
|
- exit(-1);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ opts = opts_init();
|
|
|
+ if (opts_parse(argc, argv, opts))
|
|
|
+ goto err;
|
|
|
|
|
|
|
|
|
sigemptyset(&sig_set);
|
|
@@ -145,22 +131,54 @@ int main(int argc, char **argv)
|
|
|
|
|
|
|
|
|
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
|
- fprintf(stderr, "Cannot create socket: %s\n", strerror(errno));
|
|
|
-
|
|
|
- return -1;
|
|
|
+ syslog(LOG_ERR, "Can't create listen socket: %s\n",
|
|
|
+ strerror(errno));
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
laddr.sun_family = AF_UNIX;
|
|
|
- strncpy(laddr.sun_path, socket_path, UNIX_PATH_MAX);
|
|
|
+ strncpy(laddr.sun_path, opts->socket_path, UNIX_PATH_MAX);
|
|
|
laddr.sun_path[UNIX_PATH_MAX - 1] = '\0';
|
|
|
if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr))) {
|
|
|
- fprintf(stderr, "Can't bind()\n");
|
|
|
-
|
|
|
- close(sock);
|
|
|
- return -1;
|
|
|
+ syslog(LOG_ERR, "Can't bind socket: %s\n",
|
|
|
+ strerror(errno));
|
|
|
+ goto err;
|
|
|
}
|
|
|
listen(sock, 5);
|
|
|
|
|
|
+ if (!opts->debug) {
|
|
|
+ FILE *f_pid = NULL;
|
|
|
+
|
|
|
+
|
|
|
+ if (daemonize(0, 0) < 0) {
|
|
|
+ syslog(LOG_ERR, "Can't daemonize\n");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if ((f_pid = fopen(opts->pidfile, "w")) == NULL) {
|
|
|
+ syslog(LOG_WARNING, "Can't open pidfile %s: %s",
|
|
|
+ opts->pidfile, strerror(errno));
|
|
|
+ } else {
|
|
|
+ if (fprintf(f_pid, "%u\n", getpid()) < 0)
|
|
|
+ syslog(LOG_WARNING, "Can't write to %s: %s",
|
|
|
+ opts->pidfile, strerror(errno));
|
|
|
+ fclose(f_pid);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ setfsuid(opts.user);
|
|
|
+ if ((setresgid(opts.user, opts.user, opts.user)<0) ||
|
|
|
+ (setresuid(opts.user, opts.user, opts.user)<0)) {
|
|
|
+ syslog(LOG_ERR, "%s", strerror(errno));
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+*/
|
|
|
+
|
|
|
+
|
|
|
|
|
|
conf = konf_tree_new("", 0);
|
|
|
|
|
@@ -242,9 +260,16 @@ int main(int argc, char **argv)
|
|
|
konf_buf_delete(tbuf);
|
|
|
}
|
|
|
|
|
|
+ retval = 0;
|
|
|
+err:
|
|
|
|
|
|
- close(sock);
|
|
|
- unlink(socket_path);
|
|
|
+ if (sock >= 0) {
|
|
|
+ close(sock);
|
|
|
+ unlink(opts->socket_path);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ opts_free(opts);
|
|
|
|
|
|
return retval;
|
|
|
}
|
|
@@ -415,6 +440,152 @@ static int dump_running_config(int sock, konf_tree_t *conf, konf_query_t *query)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+int daemonize(int nochdir, int noclose)
|
|
|
+{
|
|
|
+ int fd;
|
|
|
+ int pid;
|
|
|
+
|
|
|
+ pid = fork();
|
|
|
+ if (-1 == pid)
|
|
|
+ return -1;
|
|
|
+ if (pid > 0)
|
|
|
+ _exit(0);
|
|
|
+ if (setsid() == -1)
|
|
|
+ return -1;
|
|
|
+ if (!nochdir)
|
|
|
+ chdir("/");
|
|
|
+ if (!noclose) {
|
|
|
+ fd = open("/dev/null", O_RDWR, 0);
|
|
|
+ if (fd < 0)
|
|
|
+ return -1;
|
|
|
+ dup2(fd, STDIN_FILENO);
|
|
|
+ dup2(fd, STDOUT_FILENO);
|
|
|
+ dup2(fd, STDERR_FILENO);
|
|
|
+ if (fd > 2)
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+struct options *opts_init(void)
|
|
|
+{
|
|
|
+ struct options *opts = NULL;
|
|
|
+
|
|
|
+ opts = malloc(sizeof(*opts));
|
|
|
+ assert(opts);
|
|
|
+ opts->debug = 0;
|
|
|
+ opts->socket_path = lub_string_dup(KONFD_SOCKET_PATH);
|
|
|
+ opts->pidfile = lub_string_dup(KONFD_PIDFILE);
|
|
|
+
|
|
|
+ return opts;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void opts_free(struct options *opts)
|
|
|
+{
|
|
|
+ if (opts->socket_path)
|
|
|
+ lub_string_free(opts->socket_path);
|
|
|
+ if (opts->pidfile)
|
|
|
+ lub_string_free(opts->pidfile);
|
|
|
+ free(opts);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static int opts_parse(int argc, char *argv[], struct options *opts)
|
|
|
+{
|
|
|
+ static const char *shortopts = "hvs:p:u:g:d";
|
|
|
+#ifdef HAVE_GETOPT_H
|
|
|
+ static const struct option longopts[] = {
|
|
|
+ {"help", 0, NULL, 'h'},
|
|
|
+ {"version", 0, NULL, 'v'},
|
|
|
+ {"socket", 1, NULL, 's'},
|
|
|
+ {"pid", 1, NULL, 'p'},
|
|
|
+ {"user", 1, NULL, 'u'},
|
|
|
+ {"group", 1, NULL, 'g'},
|
|
|
+ {"debug", 0, NULL, 'd'},
|
|
|
+ {NULL, 0, NULL, 0}
|
|
|
+ };
|
|
|
+#endif
|
|
|
+ optind = 0;
|
|
|
+ while(1) {
|
|
|
+ int opt;
|
|
|
+#ifdef HAVE_GETOPT_H
|
|
|
+ opt = getopt_long(argc, argv, shortopts, longopts, NULL);
|
|
|
+#else
|
|
|
+ opt = getopt(argc, argv, shortopts);
|
|
|
+#endif
|
|
|
+ if (-1 == opt)
|
|
|
+ break;
|
|
|
+ switch (opt) {
|
|
|
+ case 's':
|
|
|
+ if (opts->socket_path)
|
|
|
+ lub_string_free(opts->socket_path);
|
|
|
+ opts->socket_path = lub_string_dup(optarg);
|
|
|
+ break;
|
|
|
+ case 'p':
|
|
|
+ if (opts->pidfile)
|
|
|
+ lub_string_free(opts->pidfile);
|
|
|
+ opts->pidfile = lub_string_dup(optarg);
|
|
|
+ break;
|
|
|
+ case 'd':
|
|
|
+ opts->debug = 1;
|
|
|
+ break;
|
|
|
+ case 'u': {
|
|
|
+ struct passwd pwd, *result;
|
|
|
+ size_t bufsize;
|
|
|
+ char *buf;
|
|
|
+ int res;
|
|
|
+
|
|
|
+ bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
|
|
+ if (bufsize == -1)
|
|
|
+ bufsize = 16384;
|
|
|
+ buf = malloc(bufsize);
|
|
|
+ assert(buf);
|
|
|
+ res = getpwnam_r(optarg, &pwd, buf, bufsize, &result);
|
|
|
+ if (!result) {
|
|
|
+ syslog(LOG_ERR, "Can't identify user \"%s\"\n",
|
|
|
+ optarg);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ opts->uid = pwd.pw_uid;
|
|
|
+ free(buf);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'g': {
|
|
|
+ struct group *grp = getgrnam(optarg);
|
|
|
+ if (!grp) {
|
|
|
+ syslog(LOG_ERR, "Can't identify group \"%s\"\n",
|
|
|
+ optarg);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ opts->gid = grp->gr_gid;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'h':
|
|
|
+ help(0, argv[0]);
|
|
|
+ exit(0);
|
|
|
+ break;
|
|
|
+ case 'v':
|
|
|
+ version(VERSION);
|
|
|
+ exit(0);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ help(-1, argv[0]);
|
|
|
+ exit(-1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
|
|
|
static void help(int status, const char *argv0)
|
|
@@ -441,7 +612,13 @@ static void help(int status, const char *argv0)
|
|
|
printf("Options:\n");
|
|
|
printf("\t-v, --version\tPrint version.\n");
|
|
|
printf("\t-h, --help\tPrint this help.\n");
|
|
|
+ printf("\t-d, --debug\tDebug mode. Don't daemonize.\n");
|
|
|
printf("\t-s <path>, --socket=<path>\tSpecify the UNIX socket "
|
|
|
"filesystem path to listen on.\n");
|
|
|
+ printf("\t-p <path>, --pid=<path>\tFile to save daemon's PID to.\n");
|
|
|
+ printf("\t-u <user>, --user=<user>\tExecute process as"
|
|
|
+ " specified user.\n");
|
|
|
+ printf("\t-g <group>, --group=<group>\tExecute process as"
|
|
|
+ " specified group.\n");
|
|
|
}
|
|
|
}
|