Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

klish / bin / clish.c @ 1a733d28

History | View | Annotate | Download (10.2 KB)

1
/*
2
 * --------------------------------------
3
 * clish.c
4
 *
5
 * A console client for libclish
6
 * --------------------------------------
7
 */
8

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

    
13
#include <stdlib.h>
14
#include <stdio.h>
15
#include <string.h>
16
#include <unistd.h>
17
#include <syslog.h>
18

    
19
#if WITH_INTERNAL_GETOPT
20
#include "libc/getopt.h"
21
#else
22
#ifdef HAVE_GETOPT_H
23
#include <getopt.h>
24
#endif
25
#endif
26

    
27
#include <signal.h>
28
#if HAVE_LOCALE_H
29
#include <locale.h>
30
#endif
31
#if HAVE_LANGINFO_CODESET
32
#include <langinfo.h>
33
#endif
34

    
35
#include "lub/list.h"
36
#include "lub/system.h"
37
#include "lub/log.h"
38
#include "clish/shell.h"
39

    
40
#define QUOTE(t) #t
41
/* #define version(v) printf("%s\n", QUOTE(v)) */
42
#define version(v) printf("%s\n", v)
43

    
44
static void sighandler(int signo);
45
static void help(int status, const char *argv0);
46

    
47
/*--------------------------------------------------------- */
48
int main(int argc, char **argv)
49
{
50
        int running;
51
        int result = -1;
52
        clish_shell_t *shell = NULL;
53

    
54
        /* Command line options */
55
        const char *socket_path = KONFD_SOCKET_PATH;
56
        bool_t lockless = BOOL_FALSE;
57
        bool_t stop_on_error = BOOL_FALSE;
58
        bool_t interactive = BOOL_TRUE;
59
        bool_t quiet = BOOL_FALSE;
60
        bool_t utf8 = BOOL_FALSE;
61
        bool_t bit8 = BOOL_FALSE;
62
        bool_t log = BOOL_FALSE;
63
        int log_facility = LOG_LOCAL0;
64
        bool_t dryrun = BOOL_FALSE;
65
        bool_t dryrun_config = BOOL_FALSE;
66
        const char *xml_path = getenv("CLISH_PATH");
67
        const char *view = getenv("CLISH_VIEW");
68
        const char *viewid = getenv("CLISH_VIEWID");
69

    
70
        FILE *outfd = stdout;
71
        bool_t istimeout = BOOL_FALSE;
72
        int timeout = 0;
73
        bool_t cmd = BOOL_FALSE; /* -c option */
74
        lub_list_t *cmds; /* Commands defined by -c */
75
        lub_list_node_t *iter;
76
        const char *histfile = "~/.clish_history";
77
        char *histfile_expanded = NULL;
78
        unsigned int histsize = 50;
79
        clish_sym_t *sym = NULL;
80

    
81
        /* Signal vars */
82
        struct sigaction sigpipe_act;
83
        sigset_t sigpipe_set;
84

    
85
        static const char *shortopts = "hvs:ledx:w:i:bqu8oO:kt:c:f:z:";
86
#ifdef HAVE_GETOPT_LONG
87
        static const struct option longopts[] = {
88
                {"help",        0, NULL, 'h'},
89
                {"version",        0, NULL, 'v'},
90
                {"socket",        1, NULL, 's'},
91
                {"lockless",        0, NULL, 'l'},
92
                {"stop-on-error", 0, NULL, 'e'},
93
                {"dry-run",        0, NULL, 'd'},
94
                {"xml-path",        1, NULL, 'x'},
95
                {"view",        1, NULL, 'w'},
96
                {"viewid",        1, NULL, 'i'},
97
                {"background",        0, NULL, 'b'},
98
                {"quiet",        0, NULL, 'q'},
99
                {"utf8",        0, NULL, 'u'},
100
                {"8bit",        0, NULL, '8'},
101
                {"log",                0, NULL, 'o'},
102
                {"facility",        1, NULL, 'O'},
103
                {"check",        0, NULL, 'k'},
104
                {"timeout",        1, NULL, 't'},
105
                {"command",        1, NULL, 'c'},
106
                {"histfile",        1, NULL, 'f'},
107
                {"histsize",        1, NULL, 'z'},
108
                {NULL,                0, NULL, 0}
109
        };
110
#endif
111

    
112
        /* Ignore SIGPIPE */
113
        sigemptyset(&sigpipe_set);
114
        sigaddset(&sigpipe_set, SIGPIPE);
115
        sigpipe_act.sa_flags = 0;
116
        sigpipe_act.sa_mask = sigpipe_set;
117
        sigpipe_act.sa_handler = &sighandler;
118
        sigaction(SIGPIPE, &sigpipe_act, NULL);
119

    
120
#if HAVE_LOCALE_H
121
        /* Set current locale */
122
        setlocale(LC_ALL, "");
123
#endif
124

    
125
        /* Var initialization */
126
        cmds = lub_list_new(NULL);
127

    
128
        /* Parse command line options */
129
        while(1) {
130
                int opt;
131
#ifdef HAVE_GETOPT_LONG
132
                opt = getopt_long(argc, argv, shortopts, longopts, NULL);
133
#else
134
                opt = getopt(argc, argv, shortopts);
135
#endif
136
                if (-1 == opt)
137
                        break;
138
                switch (opt) {
139
                case 's':
140
                        socket_path = optarg;
141
                        break;
142
                case 'l':
143
                        lockless = BOOL_TRUE;
144
                        break;
145
                case 'e':
146
                        stop_on_error = BOOL_TRUE;
147
                        break;
148
                case 'b':
149
                        interactive = BOOL_FALSE;
150
                        break;
151
                case 'q':
152
                        quiet = BOOL_TRUE;
153
                        break;
154
                case 'u':
155
                        utf8 = BOOL_TRUE;
156
                        break;
157
                case '8':
158
                        bit8 = BOOL_TRUE;
159
                        break;
160
                case 'o':
161
                        log = BOOL_TRUE;
162
                        break;
163
                case 'O':
164
                        if (lub_log_facility(optarg, &log_facility)) {
165
                                fprintf(stderr, "Error: Illegal syslog facility %s.\n", optarg);
166
                                help(-1, argv[0]);
167
                                goto end;
168
                        }
169
                        break;
170
                case 'd':
171
                        dryrun = BOOL_TRUE;
172
                        break;
173
                case 'x':
174
                        xml_path = optarg;
175
                        break;
176
                case 'w':
177
                        view = optarg;
178
                        break;
179
                case 'i':
180
                        viewid = optarg;
181
                        break;
182
                case 'k':
183
                        lockless = BOOL_TRUE;
184
                        dryrun = BOOL_TRUE;
185
                        dryrun_config = BOOL_TRUE;
186
                        break;
187
                case 't':
188
                        istimeout = BOOL_TRUE;
189
                        timeout = atoi(optarg);
190
                        break;
191
                case 'c': {
192
                                char *str;
193
                                cmd = BOOL_TRUE;
194
                                quiet = BOOL_TRUE;
195
                                str = strdup(optarg);
196
                                lub_list_add(cmds, str);
197
                        }
198
                        break;
199
                case 'f':
200
                        if (!strcmp(optarg, "/dev/null"))
201
                                histfile = NULL;
202
                        else
203
                                histfile = optarg;
204
                        break;
205
                case 'z': {
206
                                int itmp = 0;
207
                                itmp = atoi(optarg);
208
                                if (itmp <= 0) {
209
                                        fprintf(stderr, "Error: Illegal histsize option value.\n");
210
                                        help(-1, argv[0]);
211
                                        goto end;
212
                                }
213
                                histsize = itmp;
214
                        }
215
                        break;
216
                case 'h':
217
                        help(0, argv[0]);
218
                        exit(0);
219
                        break;
220
                case 'v':
221
                        version(VERSION);
222
                        exit(0);
223
                        break;
224
                default:
225
                        help(-1, argv[0]);
226
                        goto end;
227
                        break;
228
                }
229
        }
230

    
231
        /* Validate command line options */
232
        if (utf8 && bit8) {
233
                fprintf(stderr, "Error: The -u and -8 options can't be used together.\n");
234
                goto end;
235
        }
236

    
237
        /* Create shell instance */
238
        if (quiet)
239
                outfd = fopen("/dev/null", "w");
240
        shell = clish_shell_new(NULL, outfd, stop_on_error);
241
        if (!shell) {
242
                fprintf(stderr, "Error: Can't run clish.\n");
243
                goto end;
244
        }
245
        /* Load the XML files */
246
        if (clish_shell_load_scheme(shell, xml_path))
247
                goto end;
248
        /* Set communication to the konfd */
249
        clish_shell__set_socket(shell, socket_path);
250
        /* Set lockless mode */
251
        if (lockless)
252
                clish_shell__set_lockfile(shell, NULL);
253
        /* Set interactive mode */
254
        if (!interactive)
255
                clish_shell__set_interactive(shell, interactive);
256
        /* Set startup view */
257
        if (view)
258
                clish_shell__set_startup_view(shell, view);
259
        /* Set startup viewid */
260
        if (viewid)
261
                clish_shell__set_startup_viewid(shell, viewid);
262
        /* Set UTF-8 or 8-bit mode */
263
        if (utf8 || bit8)
264
                clish_shell__set_utf8(shell, utf8);
265
        else {
266
#if HAVE_LANGINFO_CODESET
267
                /* Autodetect encoding */
268
                if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
269
                        clish_shell__set_utf8(shell, BOOL_TRUE);
270
#else
271
                /* The default is 8-bit if locale is not supported */
272
                clish_shell__set_utf8(shell, BOOL_FALSE);
273
#endif
274
        }
275
        /* Set logging */
276
        if (log) {
277
                clish_shell__set_log(shell, log);
278
                clish_shell__set_facility(shell, log_facility);
279
        }
280
        /* Set dry-run */
281
        if (dryrun)
282
                clish_shell__set_dryrun(shell, dryrun);
283
        /* Set idle timeout */
284
        if (istimeout)
285
                clish_shell__set_timeout(shell, timeout);
286
        /* Set history settings */
287
        clish_shell__stifle_history(shell, histsize);
288
        if (histfile)
289
                histfile_expanded = lub_system_tilde_expand(histfile);
290
        if (histfile_expanded)
291
                clish_shell__restore_history(shell, histfile_expanded);
292
        /* Load plugins */
293
        if (clish_shell_load_plugins(shell) < 0)
294
                goto end;
295
        if (clish_shell_link_plugins(shell) < 0)
296
                goto end;
297
        /* Dryrun config and log hooks */
298
        if (dryrun_config) {
299
                if ((sym = clish_shell_get_hook(shell, CLISH_SYM_TYPE_CONFIG)))
300
                        clish_sym__set_permanent(sym, BOOL_FALSE);
301
                if ((sym = clish_shell_get_hook(shell, CLISH_SYM_TYPE_LOG)))
302
                        clish_sym__set_permanent(sym, BOOL_FALSE);
303
        }
304

    
305
        /* Set source of command stream: files or interactive tty */
306
        if(optind < argc) {
307
                int i;
308
                /* Run the commands from the files */
309
                for (i = argc - 1; i >= optind; i--)
310
                        clish_shell_push_file(shell, argv[i], stop_on_error);
311
        } else {
312
                /* The interactive shell */
313
                clish_shell_push_fd(shell, fdopen(dup(fileno(stdin)), "r"),
314
                        stop_on_error);
315
        }
316

    
317
        /* Execute startup */
318
        running = clish_shell_startup(shell);
319
        if (running) {
320
                fprintf(stderr, "Error: Can't startup clish.\n");
321
                goto end;
322
        }
323

    
324
        if (cmd) {
325
                /* Iterate cmds */
326
                for(iter = lub_list__get_head(cmds);
327
                        iter; iter = lub_list_node__get_next(iter)) {
328
                        char *str = (char *)lub_list_node__get_data(iter);
329
                        result = clish_shell_forceline(shell, str, NULL);
330
                        if (stop_on_error && result)
331
                                break;
332
                }
333
        } else {
334
                /* Main loop */
335
                result = clish_shell_loop(shell);
336
        }
337

    
338
end:
339
        /* Cleanup */
340
        if (shell) {
341
                if (histfile_expanded) {
342
                        clish_shell__save_history(shell, histfile_expanded);
343
                        free(histfile_expanded);
344
                }
345
                clish_shell_delete(shell);
346
        }
347
        if (quiet)
348
                fclose(outfd);
349

    
350
        /* Delete each cmds element */
351
        while ((iter = lub_list__get_head(cmds))) {
352
                lub_list_del(cmds, iter);
353
                free(lub_list_node__get_data(iter));
354
                lub_list_node_free(iter);
355
        }
356
        lub_list_free(cmds);
357

    
358
        return result;
359
}
360

    
361
/*--------------------------------------------------------- */
362
/* Print help message */
363
static void help(int status, const char *argv0)
364
{
365
        const char *name = NULL;
366

    
367
        if (!argv0)
368
                return;
369

    
370
        /* Find the basename */
371
        name = strrchr(argv0, '/');
372
        if (name)
373
                name++;
374
        else
375
                name = argv0;
376

    
377
        if (status != 0) {
378
                fprintf(stderr, "Try `%s -h' for more information.\n",
379
                        name);
380
        } else {
381
                printf("Usage: %s [options] [script_file] [script_file] ...\n", name);
382
                printf("CLI utility. Command line shell."
383
                        "The part of the klish project.\n");
384
                printf("Options:\n");
385
                printf("\t-v, --version\tPrint version.\n");
386
                printf("\t-h, --help\tPrint this help.\n");
387
                printf("\t-s <path>, --socket=<path>\tSpecify listen socket "
388
                        "\n\t\tof the konfd daemon.\n");
389
                printf("\t-l, --lockless\tDon't use locking mechanism.\n");
390
                printf("\t-e, --stop-on-error\tStop script execution on error.\n");
391
                printf("\t-b, --background\tStart shell using non-interactive mode.\n");
392
                printf("\t-q, --quiet\tDisable echo while executing commands\n\t\tfrom the file stream.\n");
393
                printf("\t-d, --dry-run\tDon't actually execute ACTION scripts.\n");
394
                printf("\t-x <path>, --xml-path=<path>\tPath to XML scheme files.\n");
395
                printf("\t-w <view_name>, --view=<view_name>\tSet the startup view.\n");
396
                printf("\t-i <vars>, --viewid=<vars>\tSet the startup viewid variables.\n");
397
                printf("\t-u, --utf8\tForce UTF-8 encoding.\n");
398
                printf("\t-8, --8bit\tForce 8-bit encoding.\n");
399
                printf("\t-o, --log\tEnable command logging to syslog's.\n");
400
                printf("\t-O, --facility\tSyslog facility. Default is LOCAL0.\n");
401
                printf("\t-k, --check\tCheck input files for syntax errors only.\n");
402
                printf("\t-t <timeout>, --timeout=<timeout>\tIdle timeout in seconds.\n");
403
                printf("\t-c <command>, --command=<command>\tExecute specified command(s).\n\t\tMultiple options are possible.\n");
404
                printf("\t-f <path>, --histfile=<path>\tFile to save command history.\n");
405
                printf("\t-z <num>, --histsize=<num>\tCommand history size in lines.\n");
406
        }
407
}
408

    
409
/*--------------------------------------------------------- */
410
/*
411
 * Signal handler for SIGPIPE.
412
 * It's empty but it's needed to don't ignore SIGPIPE because
413
 * SIG_IGN will be inherited while ACTION execution.
414
 */
415
static void sighandler(int signo)
416
{
417
        return;
418
}