Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

klish / bin / konfd.c @ 1a733d28

History | View | Annotate | Download (17.3 KB)

1
/*
2
 * konfd.c
3
 *
4
 * The konfd daemon to store user configuration commands.
5
 *
6
 */
7

    
8
#ifdef HAVE_CONFIG_H
9
#include "config.h"
10
#endif /* HAVE_CONFIG_H */
11

    
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <unistd.h>
15
#include <sys/types.h>
16
#include <sys/stat.h>
17
#include <fcntl.h>
18
#include <sys/wait.h>
19
#include <errno.h>
20
#include <assert.h>
21
#include <sys/socket.h>
22
#include <sys/un.h>
23
#include <string.h>
24
#include <sys/select.h>
25
#include <signal.h>
26
#include <syslog.h>
27

    
28
#if WITH_INTERNAL_GETOPT
29
#include "libc/getopt.h"
30
#else
31
#ifdef HAVE_GETOPT_H
32
#include <getopt.h>
33
#endif
34
#endif
35

    
36
#ifdef HAVE_PWD_H
37
#include <pwd.h>
38
#endif
39
#ifdef HAVE_GRP_H
40
#include <grp.h>
41
#endif
42

    
43
#include "konf/tree.h"
44
#include "konf/query.h"
45
#include "konf/buf.h"
46
#include "konf/net.h"
47
#include "lub/argv.h"
48
#include "lub/string.h"
49
#include "lub/log.h"
50

    
51
#ifndef VERSION
52
#define VERSION 1.2.2
53
#endif
54
#define QUOTE(t) #t
55
#define version(v) printf("%s\n", v)
56

    
57
#define KONFD_PIDFILE "/var/run/konfd.pid"
58

    
59
/* UNIX socket path */
60
/* Don't use UNIX_PATH_MAX due to portability issues */
61
#define USOCK_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
62

    
63
/* OpenBSD has no MSG_NOSIGNAL flag */
64
#ifndef MSG_NOSIGNAL
65
#define MSG_NOSIGNAL 0
66
#endif
67

    
68
/* Global signal vars */
69
static volatile int sigterm = 0;
70
static void sighandler(int signo);
71

    
72
static void help(int status, const char *argv0);
73
static char * process_query(konf_buf_t *tbuf, konf_tree_t * conf, char *str);
74
int answer_send(int sock, char *command);
75
static int dump_running_config(int sock, konf_tree_t *conf, konf_query_t *query);
76
int daemonize(int nochdir, int noclose);
77
struct options *opts_init(void);
78
void opts_free(struct options *opts);
79
static int opts_parse(int argc, char *argv[], struct options *opts);
80
static int create_listen_socket(const char *path,
81
        uid_t uid, gid_t gid, mode_t mode);
82

    
83
/* Command line options */
84
struct options {
85
        char *socket_path;
86
        char *ro_path;
87
        char *pidfile;
88
        char *chroot;
89
        int debug; /* Don't daemonize in debug mode */
90
        uid_t uid;
91
        gid_t gid;
92
        int log_facility;
93
};
94

    
95
/*--------------------------------------------------------- */
96
int main(int argc, char **argv)
97
{
98
        int retval = -1;
99
        unsigned int i;
100
        char *str;
101
        konf_tree_t *conf;
102
        lub_bintree_t bufs;
103
        konf_buf_t *tbuf;
104
        struct options *opts = NULL;
105
        int pidfd = -1;
106

    
107
        /* Network vars */
108
        int sock = -1;
109
        int ro_sock = -1;
110
        struct sockaddr_un raddr;
111
        fd_set active_fd_set, read_fd_set;
112

    
113
        /* Signal vars */
114
        struct sigaction sig_act, sigpipe_act;
115
        sigset_t sig_set, sigpipe_set;
116

    
117
        /* Parse command line options */
118
        opts = opts_init();
119
        if (opts_parse(argc, argv, opts))
120
                goto err;
121

    
122
        /* Initialize syslog */
123
        openlog(argv[0], LOG_CONS, opts->log_facility);
124
        syslog(LOG_ERR, "Start daemon.\n");
125

    
126
        /* Fork the daemon */
127
        if (!opts->debug) {
128
                /* Daemonize */
129
                if (daemonize(0, 0) < 0) {
130
                        syslog(LOG_ERR, "Can't daemonize\n");
131
                        goto err;
132
                }
133

    
134
                /* Write pidfile */
135
                if ((pidfd = open(opts->pidfile,
136
                        O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
137
                        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
138
                        syslog(LOG_WARNING, "Can't open pidfile %s: %s",
139
                                opts->pidfile, strerror(errno));
140
                } else {
141
                        char str[20];
142
                        snprintf(str, sizeof(str), "%u\n", getpid());
143
                        if (write(pidfd, str, strlen(str)) < 0)
144
                                syslog(LOG_WARNING, "Can't write to %s: %s",
145
                                        opts->pidfile, strerror(errno));
146
                        close(pidfd);
147
                }
148
        }
149

    
150
        /* Create RW listen socket */
151
        if ((sock = create_listen_socket(opts->socket_path,
152
                opts->uid, opts->gid, 0660)) == -1) {
153
                goto err;
154
        }
155

    
156
        /* Create RO listen socket */
157
        if (opts->ro_path && (ro_sock = create_listen_socket(opts->ro_path,
158
                opts->uid, opts->gid, 0666)) == -1) {
159
                goto err;
160
        }
161

    
162
        /* Change GID */
163
        if (opts->gid != getgid()) {
164
                if (setgid(opts->gid)) {
165
                        syslog(LOG_ERR, "Can't set GID to %u: %s",
166
                                opts->gid, strerror(errno));
167
                        goto err;
168
                }
169
        }
170

    
171
#ifdef HAVE_CHROOT
172
        /* Chroot */
173
        if (opts->chroot) {
174
                if (chroot(opts->chroot) < 0) {
175
                        syslog(LOG_ERR, "Can't chroot to %s: %s",
176
                                opts->chroot, strerror(errno));
177
                        goto err;
178
                }
179
        }
180
#endif
181

    
182
        /* Change UID */
183
        if (opts->uid != getuid()) {
184
                if (setuid(opts->uid)) {
185
                        syslog(LOG_ERR, "Can't set UID to %u: %s",
186
                                opts->uid, strerror(errno));
187
                        goto err;
188
                }
189
        }
190

    
191
        /* Create configuration tree */
192
        conf = konf_tree_new("", 0);
193

    
194
        /* Initialize the tree of buffers */
195
        lub_bintree_init(&bufs,
196
                konf_buf_bt_offset(),
197
                konf_buf_bt_compare, konf_buf_bt_getkey);
198

    
199
        /* Set signal handler */
200
        sigemptyset(&sig_set);
201
        sigaddset(&sig_set, SIGTERM);
202
        sigaddset(&sig_set, SIGINT);
203
        sigaddset(&sig_set, SIGQUIT);
204

    
205
        sig_act.sa_flags = 0;
206
        sig_act.sa_mask = sig_set;
207
        sig_act.sa_handler = &sighandler;
208
        sigaction(SIGTERM, &sig_act, NULL);
209
        sigaction(SIGINT, &sig_act, NULL);
210
        sigaction(SIGQUIT, &sig_act, NULL);
211

    
212
        /* Ignore SIGPIPE */
213
        sigemptyset(&sigpipe_set);
214
        sigaddset(&sigpipe_set, SIGPIPE);
215
        sigpipe_act.sa_flags = 0;
216
        sigpipe_act.sa_mask = sigpipe_set;
217
        sigpipe_act.sa_handler = SIG_IGN;
218
        sigaction(SIGPIPE, &sigpipe_act, NULL);
219

    
220
        /* Initialize the set of active sockets. */
221
        FD_ZERO(&active_fd_set);
222
        FD_SET(sock, &active_fd_set);
223
        if (ro_sock >= 0)
224
                FD_SET(ro_sock, &active_fd_set);
225

    
226
        /* Main loop */
227
        while (!sigterm) {
228
                int num;
229

    
230
                /* Block until input arrives on one or more active sockets. */
231
                read_fd_set = active_fd_set;
232
                num = select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
233
                if (num < 0) {
234
                        if (EINTR == errno)
235
                                continue;
236
                        break;
237
                }
238
                if (0 == num)
239
                        continue;
240

    
241
                /* Service all the sockets with input pending. */
242
                for (i = 0; i < FD_SETSIZE; ++i) {
243
                        if (!FD_ISSET(i, &read_fd_set))
244
                                continue;
245
                        /* Connection request on listen socket. */
246
                        if ((i == sock) || (i == ro_sock)) {
247
                                int new;
248
                                socklen_t size = sizeof(raddr);
249
                                new = accept(i,
250
                                        (struct sockaddr *)&raddr, &size);
251
                                if (new < 0) {
252
                                        continue;
253
                                }
254
#ifdef DEBUG
255
                                fprintf(stderr, "------------------------------\n");
256
                                fprintf(stderr, "Connection established %u\n", new);
257
#endif
258
                                konf_buftree_remove(&bufs, new);
259
                                tbuf = konf_buf_new(new);
260
                                /* Insert it into the binary tree */
261
                                lub_bintree_insert(&bufs, tbuf);
262
                                /* In a case of RW socket we use buf's data pointer
263
                                  to indicate RW or RO socket. NULL=RO, not-NULL=RW */
264
                                if (i == sock)
265
                                        konf_buf__set_data(tbuf, (void *)1);
266
                                FD_SET(new, &active_fd_set);
267
                        } else {
268
                                int nbytes;
269

    
270
                                tbuf = konf_buftree_find(&bufs, i);
271
                                /* Data arriving on an already-connected socket. */
272
                                if ((nbytes = konf_buf_read(tbuf)) <= 0) {
273
                                        close(i);
274
                                        FD_CLR(i, &active_fd_set);
275
                                        konf_buftree_remove(&bufs, i);
276
#ifdef DEBUG
277
                                        fprintf(stderr, "Connection closed %u\n", i);
278
#endif
279
                                        continue;
280
                                }
281
                                while ((str = konf_buf_parse(tbuf))) {
282
                                        char *answer;
283
                                        if (!(answer = process_query(tbuf, conf, str)))
284
                                                answer = strdup("-e");
285
                                        free(str);
286
                                        answer_send(i, answer);
287
                                        free(answer);
288
                                }
289
                        }
290
                }
291
        }
292

    
293
        /* Free resources */
294
        konf_tree_delete(conf);
295

    
296
        /* delete each buf */
297
        while ((tbuf = lub_bintree_findfirst(&bufs))) {
298
                /* remove the buf from the tree */
299
                lub_bintree_remove(&bufs, tbuf);
300
                /* release the instance */
301
                konf_buf_delete(tbuf);
302
        }
303

    
304
        retval = 0;
305
err:
306
        /* Close RW socket */
307
        if (sock >= 0) {
308
                close(sock);
309
                unlink(opts->socket_path);
310
        }
311

    
312
        /* Close RO socket */
313
        if (ro_sock >= 0) {
314
                close(ro_sock);
315
                unlink(opts->ro_path);
316
        }
317

    
318
        /* Remove pidfile */
319
        if (pidfd >= 0) {
320
                if (unlink(opts->pidfile) < 0) {
321
                        syslog(LOG_ERR, "Can't remove pid-file %s: %s\n",
322
                        opts->pidfile, strerror(errno));
323
                }
324
        }
325

    
326
        /* Free command line options */
327
        opts_free(opts);
328

    
329
        syslog(LOG_ERR, "Stop daemon.\n");
330

    
331
        return retval;
332
}
333

    
334
/*--------- Create listen socket--------------------------- */
335
static int create_listen_socket(const char *path,
336
        uid_t uid, gid_t gid, mode_t mode)
337
{
338
        int sock = -1;
339
        struct sockaddr_un laddr;
340
        const int reuseaddr = 1;
341

    
342
        if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
343
                syslog(LOG_ERR, "Can't create socket: %s\n", strerror(errno));
344
                goto err1;
345
        }
346
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
347
                &reuseaddr, sizeof(reuseaddr))) {
348
                syslog(LOG_ERR, "Can't set socket options: %s\n", strerror(errno));
349
                goto err1;
350
        }
351
        laddr.sun_family = AF_UNIX;
352
        strncpy(laddr.sun_path, path, USOCK_PATH_MAX);
353
        laddr.sun_path[USOCK_PATH_MAX - 1] = '\0';
354
        if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr))) {
355
                syslog(LOG_ERR, "Can't bind socket: %s\n", strerror(errno));
356
                goto err1;
357
        }
358
        if (chown(path, uid, gid)) {
359
                syslog(LOG_ERR, "Can't chown socket: %s\n", strerror(errno));
360
                goto err2;
361
        }
362
        if (chmod(path, mode)) {
363
                syslog(LOG_ERR, "Can't chmod socket: %s\n", strerror(errno));
364
                goto err2;
365
        }
366
        if (listen(sock, 10)) {
367
                syslog(LOG_ERR, "Can't listen socket: %s\n", strerror(errno));
368
                goto err2;
369
        }
370

    
371
        return sock;
372

    
373
err2:
374
        unlink(path);
375
err1:
376
        if (sock >= 0)
377
                close(sock);
378

    
379
        return -1;
380
}
381

    
382
/*--------------------------------------------------------- */
383
static char * process_query(konf_buf_t *tbuf, konf_tree_t * conf, char *str)
384
{
385
        unsigned int i;
386
        int res;
387
        konf_tree_t *iconf;
388
        konf_tree_t *tmpconf;
389
        konf_query_t *query;
390
        char *retval = NULL;
391
        konf_query_op_t ret = KONF_QUERY_OP_ERROR;
392

    
393
#ifdef DEBUG
394
        fprintf(stderr, "REQUEST: %s\n", str);
395
#endif
396
        /* Parse query */
397
        query = konf_query_new();
398
        res = konf_query_parse_str(query, str);
399
        if (res < 0) {
400
                konf_query_free(query);
401
                return NULL;
402
        }
403
#ifdef DEBUG
404
        konf_query_dump(query);
405
#endif
406

    
407
        /* Restrict RO socket for non-DUMP operation */
408
        if (!konf_buf__get_data(tbuf) &&
409
                (konf_query__get_op(query) != KONF_QUERY_OP_DUMP)) {
410
#ifdef DEBUG
411
                fprintf(stderr, "Permission denied. Read-only socket.\n");
412
#endif
413
                konf_query_free(query);
414
                return NULL;
415
        }
416

    
417
        /* Go through the pwd */
418
        iconf = conf;
419
        for (i = 0; i < konf_query__get_pwdc(query); i++) {
420
                if (!(iconf = konf_tree_find_conf(iconf,
421
                        konf_query__get_pwd(query, i), 0, 0))) {
422
                        iconf = NULL;
423
                        break;
424
                }
425
        }
426

    
427
        if (!iconf) {
428
#ifdef DEBUG
429
                fprintf(stderr, "Unknown path.\n");
430
#endif
431
                konf_query_free(query);
432
                return NULL;
433
        }
434

    
435
        switch (konf_query__get_op(query)) {
436

    
437
        case KONF_QUERY_OP_SET:
438
                if (konf_query__get_unique(query)) {
439
                        int exist = 0;
440
                        exist = konf_tree_del_pattern(iconf,
441
                                konf_query__get_line(query),
442
                                konf_query__get_unique(query),
443
                                konf_query__get_pattern(query),
444
                                konf_query__get_priority(query),
445
                                konf_query__get_seq(query),
446
                                konf_query__get_seq_num(query));
447
                        if (exist < 0)
448
                                break;
449
                        if (exist > 0) {
450
                                ret = KONF_QUERY_OP_OK;
451
                                break;
452
                        }
453
                }
454
                tmpconf = konf_tree_new_conf(iconf,
455
                        konf_query__get_line(query), konf_query__get_priority(query),
456
                        konf_query__get_seq(query), konf_query__get_seq_num(query));
457
                if (!tmpconf)
458
                        break;
459
                konf_tree__set_splitter(tmpconf, konf_query__get_splitter(query));
460
                konf_tree__set_depth(tmpconf, konf_query__get_pwdc(query));
461
                ret = KONF_QUERY_OP_OK;
462
                break;
463

    
464
        case KONF_QUERY_OP_UNSET:
465
                if (konf_tree_del_pattern(iconf,
466
                        NULL,
467
                        BOOL_TRUE,
468
                        konf_query__get_pattern(query),
469
                        konf_query__get_priority(query),
470
                        konf_query__get_seq(query),
471
                        konf_query__get_seq_num(query)) < 0)
472
                        break;
473
                ret = KONF_QUERY_OP_OK;
474
                break;
475

    
476
        case KONF_QUERY_OP_DUMP:
477
                if (dump_running_config(konf_buf__get_fd(tbuf), iconf, query))
478
                        break;
479
                ret = KONF_QUERY_OP_OK;
480
                break;
481

    
482
        default:
483
                break;
484
        }
485

    
486
#ifdef DEBUG
487
        /* Print whole tree */
488
        konf_tree_fprintf(conf, stderr, NULL, -1, -1, BOOL_TRUE, 0);
489
#endif
490

    
491
        /* Free resources */
492
        konf_query_free(query);
493

    
494
        switch (ret) {
495
        case KONF_QUERY_OP_OK:
496
                lub_string_cat(&retval, "-o");
497
                break;
498
        case KONF_QUERY_OP_ERROR:
499
                lub_string_cat(&retval, "-e");
500
                break;
501
        default:
502
                lub_string_cat(&retval, "-e");
503
                break;
504
        };
505

    
506
#ifdef DEBUG
507
        fprintf(stderr, "ANSWER: %s\n", retval);
508
#endif
509

    
510
        return retval;
511
}
512

    
513
/*--------------------------------------------------------- */
514
/*
515
 * Signal handler for temination signals (like SIGTERM, SIGINT, ...)
516
 */
517
static void sighandler(int signo)
518
{
519
        sigterm = 1;
520
}
521

    
522
/*--------------------------------------------------------- */
523
int answer_send(int sock, char *command)
524
{
525
        return send(sock, command, strlen(command) + 1, MSG_NOSIGNAL);
526
}
527

    
528
/*--------------------------------------------------------- */
529
static int dump_running_config(int sock, konf_tree_t *conf, konf_query_t *query)
530
{
531
        FILE *fd;
532
        char *filename;
533
        int dupsock = -1;
534

    
535
        if ((filename = konf_query__get_path(query))) {
536
                if (!(fd = fopen(filename, "w")))
537
                        return -1;
538
        } else {
539
                if ((dupsock = dup(sock)) < 0)
540
                        return -1;
541
                fd = fdopen(dupsock, "w");
542
        }
543
        if (!filename) {
544
                fprintf(fd, "-t\n");
545
#ifdef DEBUG
546
                fprintf(stderr, "ANSWER: -t\n");
547
#endif
548
        }
549
        konf_tree_fprintf(conf,
550
                fd,
551
                konf_query__get_pattern(query),
552
                konf_query__get_pwdc(query) - 1,
553
                konf_query__get_depth(query),
554
                konf_query__get_seq(query),
555
                0);
556
        if (!filename) {
557
                fprintf(fd, "\n");
558
#ifdef DEBUG
559
                fprintf(stderr, "SEND DATA: \n");
560
#endif
561
        }
562

    
563
        fclose(fd);
564

    
565
        return 0;
566
}
567

    
568
/*--------------------------------------------------------- */
569
/* Implement own simple daemon() to don't use Non-POSIX */
570
int daemonize(int nochdir, int noclose)
571
{
572
        int fd;
573
        int pid;
574

    
575
        pid = fork();
576
        if (-1 == pid)
577
                return -1;
578
        if (pid > 0)
579
                _exit(0); /* Exit parent */
580
        if (setsid() == -1)
581
                return -1;
582
        if (!nochdir) {
583
                if (chdir("/"))
584
                        return -1;
585
        }
586
        if (!noclose) {
587
                fd = open("/dev/null", O_RDWR, 0);
588
                if (fd < 0)
589
                        return -1;
590
                dup2(fd, STDIN_FILENO);
591
                dup2(fd, STDOUT_FILENO);
592
                dup2(fd, STDERR_FILENO);
593
                if (fd > 2)
594
                        close(fd);
595
        }
596

    
597
        return 0;
598
}
599

    
600
/*--------------------------------------------------------- */
601
/* Initialize option structure by defaults */
602
struct options *opts_init(void)
603
{
604
        struct options *opts = NULL;
605

    
606
        opts = malloc(sizeof(*opts));
607
        assert(opts);
608
        opts->debug = 0; /* daemonize by default */
609
        opts->socket_path = strdup(KONFD_SOCKET_PATH);
610
        opts->ro_path = NULL;
611
        opts->pidfile = strdup(KONFD_PIDFILE);
612
        opts->chroot = NULL;
613
        opts->uid = getuid();
614
        opts->gid = getgid();
615
        opts->log_facility = LOG_DAEMON;
616

    
617
        return opts;
618
}
619

    
620
/*--------------------------------------------------------- */
621
/* Free option structure */
622
void opts_free(struct options *opts)
623
{
624
        if (opts->socket_path)
625
                free(opts->socket_path);
626
        if (opts->ro_path)
627
                free(opts->ro_path);
628
        if (opts->pidfile)
629
                free(opts->pidfile);
630
        if (opts->chroot)
631
                free(opts->chroot);
632
        free(opts);
633
}
634

    
635
/*--------------------------------------------------------- */
636
/* Parse command line options */
637
static int opts_parse(int argc, char *argv[], struct options *opts)
638
{
639
        static const char *shortopts = "hvs:S:p:u:g:dr:O:";
640
#ifdef HAVE_GETOPT_LONG
641
        static const struct option longopts[] = {
642
                {"help",        0, NULL, 'h'},
643
                {"version",        0, NULL, 'v'},
644
                {"socket",        1, NULL, 's'},
645
                {"ro-socket",        1, NULL, 'S'},
646
                {"pid",                1, NULL, 'p'},
647
                {"user",        1, NULL, 'u'},
648
                {"group",        1, NULL, 'g'},
649
                {"debug",        0, NULL, 'd'},
650
                {"chroot",        1, NULL, 'r'},
651
                {"facility",        1, NULL, 'O'},
652
                {NULL,                0, NULL, 0}
653
        };
654
#endif
655
        optind = 1;
656
        while(1) {
657
                int opt;
658
#ifdef HAVE_GETOPT_LONG
659
                opt = getopt_long(argc, argv, shortopts, longopts, NULL);
660
#else
661
                opt = getopt(argc, argv, shortopts);
662
#endif
663
                if (-1 == opt)
664
                        break;
665
                switch (opt) {
666
                case 's':
667
                        if (opts->socket_path)
668
                                free(opts->socket_path);
669
                        opts->socket_path = strdup(optarg);
670
                        break;
671
                case 'S':
672
                        if (opts->ro_path)
673
                                free(opts->ro_path);
674
                        opts->ro_path = strdup(optarg);
675
                        break;
676
                case 'p':
677
                        if (opts->pidfile)
678
                                free(opts->pidfile);
679
                        opts->pidfile = strdup(optarg);
680
                        break;
681
                case 'r':
682
#ifdef HAVE_CHROOT
683
                        if (opts->chroot)
684
                                free(opts->chroot);
685
                        opts->chroot = strdup(optarg);
686
#else
687
                        fprintf(stderr, "Error: The --chroot option is not supported.\n");
688
                        return -1;
689
#endif
690
                        break;
691
                case 'd':
692
                        opts->debug = 1;
693
                        break;
694
                case 'u': {
695
#ifdef HAVE_PWD_H
696
                        struct passwd *pwd = getpwnam(optarg);
697
                        if (!pwd) {
698
                                fprintf(stderr, "Error: Can't identify user \"%s\"\n",
699
                                        optarg);
700
                                return -1;
701
                        }
702
                        opts->uid = pwd->pw_uid;
703
#else
704
                        fprintf(stderr, "The --user option is not supported.\n");
705
                        return -1;
706
#endif
707
                        break;
708
                }
709
                case 'g': {
710
#ifdef HAVE_GRP_H
711
                        struct group *grp = getgrnam(optarg);
712
                        if (!grp) {
713
                                fprintf(stderr, "Can't identify group \"%s\"\n",
714
                                        optarg);
715
                                return -1;
716
                        }
717
                        opts->gid = grp->gr_gid;
718
#else
719
                        fprintf(stderr, "The --group option is not supported.\n");
720
                        return -1;
721
#endif
722
                        break;
723
                }
724
                case 'O':
725
                        if (lub_log_facility(optarg, &(opts->log_facility))) {
726
                                fprintf(stderr, "Error: Illegal syslog facility %s.\n", optarg);
727
                                help(-1, argv[0]);
728
                                exit(-1);
729
                        }
730
                        break;
731
                case 'h':
732
                        help(0, argv[0]);
733
                        exit(0);
734
                        break;
735
                case 'v':
736
                        version(VERSION);
737
                        exit(0);
738
                        break;
739
                default:
740
                        help(-1, argv[0]);
741
                        exit(-1);
742
                        break;
743
                }
744
        }
745

    
746
        return 0;
747
}
748

    
749
/*--------------------------------------------------------- */
750
/* Print help message */
751
static void help(int status, const char *argv0)
752
{
753
        const char *name = NULL;
754

    
755
        if (!argv0)
756
                return;
757

    
758
        /* Find the basename */
759
        name = strrchr(argv0, '/');
760
        if (name)
761
                name++;
762
        else
763
                name = argv0;
764

    
765
        if (status != 0) {
766
                fprintf(stderr, "Try `%s -h' for more information.\n",
767
                        name);
768
        } else {
769
                printf("Usage: %s [options]\n", name);
770
                printf("Daemon to store user configuration (i.e. commands). "
771
                        "The part of the klish project.\n");
772
                printf("Options:\n");
773
                printf("\t-v, --version\tPrint version.\n");
774
                printf("\t-h, --help\tPrint this help.\n");
775
                printf("\t-d, --debug\tDebug mode. Don't daemonize.\n");
776
                printf("\t-s <path>, --socket=<path>\tSpecify the UNIX socket "
777
                        "filesystem path to listen on.\n");
778
                printf("\t-p <path>, --pid=<path>\tFile to save daemon's PID to.\n");
779
                printf("\t-r <path>, --chroot=<path>\tDirectory to chroot.\n");
780
                printf("\t-u <user>, --user=<user>\tExecute process as"
781
                        " specified user.\n");
782
                printf("\t-g <group>, --group=<group>\tExecute process as"
783
                        " specified group.\n");
784
                printf("\t-O, --facility\tSyslog facility. Default is DAEMON.\n");
785
        }
786
}