init_parser.c revision a6235eacf4b06b14b19125618d7aca570dbc02b0
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <stdarg.h>
22#include <string.h>
23#include <stddef.h>
24#include <ctype.h>
25
26#include "init.h"
27#include "parser.h"
28#include "init_parser.h"
29#include "log.h"
30#include "property_service.h"
31#include "util.h"
32
33#include <cutils/iosched_policy.h>
34#include <cutils/list.h>
35
36#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
37#include <sys/_system_properties.h>
38
39static list_declare(service_list);
40static list_declare(action_list);
41static list_declare(action_queue);
42
43static void *parse_service(struct parse_state *state, int nargs, char **args);
44static void parse_line_service(struct parse_state *state, int nargs, char **args);
45
46static void *parse_action(struct parse_state *state, int nargs, char **args);
47static void parse_line_action(struct parse_state *state, int nargs, char **args);
48
49#define SECTION 0x01
50#define COMMAND 0x02
51#define OPTION  0x04
52
53#include "keywords.h"
54
55#define KEYWORD(symbol, flags, nargs, func) \
56    [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
57
58struct {
59    const char *name;
60    int (*func)(int nargs, char **args);
61    unsigned char nargs;
62    unsigned char flags;
63} keyword_info[KEYWORD_COUNT] = {
64    [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
65#include "keywords.h"
66};
67#undef KEYWORD
68
69#define kw_is(kw, type) (keyword_info[kw].flags & (type))
70#define kw_name(kw) (keyword_info[kw].name)
71#define kw_func(kw) (keyword_info[kw].func)
72#define kw_nargs(kw) (keyword_info[kw].nargs)
73
74int lookup_keyword(const char *s)
75{
76    switch (*s++) {
77    case 'c':
78    if (!strcmp(s, "opy")) return K_copy;
79        if (!strcmp(s, "apability")) return K_capability;
80        if (!strcmp(s, "hdir")) return K_chdir;
81        if (!strcmp(s, "hroot")) return K_chroot;
82        if (!strcmp(s, "lass")) return K_class;
83        if (!strcmp(s, "lass_start")) return K_class_start;
84        if (!strcmp(s, "lass_stop")) return K_class_stop;
85        if (!strcmp(s, "lass_reset")) return K_class_reset;
86        if (!strcmp(s, "onsole")) return K_console;
87        if (!strcmp(s, "hown")) return K_chown;
88        if (!strcmp(s, "hmod")) return K_chmod;
89        if (!strcmp(s, "ritical")) return K_critical;
90        break;
91    case 'd':
92        if (!strcmp(s, "isabled")) return K_disabled;
93        if (!strcmp(s, "omainname")) return K_domainname;
94        break;
95    case 'e':
96        if (!strcmp(s, "xec")) return K_exec;
97        if (!strcmp(s, "xport")) return K_export;
98        break;
99    case 'g':
100        if (!strcmp(s, "roup")) return K_group;
101        break;
102    case 'h':
103        if (!strcmp(s, "ostname")) return K_hostname;
104        break;
105    case 'i':
106        if (!strcmp(s, "oprio")) return K_ioprio;
107        if (!strcmp(s, "fup")) return K_ifup;
108        if (!strcmp(s, "nsmod")) return K_insmod;
109        if (!strcmp(s, "mport")) return K_import;
110        break;
111    case 'k':
112        if (!strcmp(s, "eycodes")) return K_keycodes;
113        break;
114    case 'l':
115        if (!strcmp(s, "oglevel")) return K_loglevel;
116        if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
117        break;
118    case 'm':
119        if (!strcmp(s, "kdir")) return K_mkdir;
120        if (!strcmp(s, "ount")) return K_mount;
121        break;
122    case 'o':
123        if (!strcmp(s, "n")) return K_on;
124        if (!strcmp(s, "neshot")) return K_oneshot;
125        if (!strcmp(s, "nrestart")) return K_onrestart;
126        break;
127    case 'r':
128        if (!strcmp(s, "estart")) return K_restart;
129        if (!strcmp(s, "mdir")) return K_rmdir;
130        if (!strcmp(s, "m")) return K_rm;
131        break;
132    case 's':
133        if (!strcmp(s, "ervice")) return K_service;
134        if (!strcmp(s, "etenv")) return K_setenv;
135        if (!strcmp(s, "etkey")) return K_setkey;
136        if (!strcmp(s, "etprop")) return K_setprop;
137        if (!strcmp(s, "etrlimit")) return K_setrlimit;
138        if (!strcmp(s, "ocket")) return K_socket;
139        if (!strcmp(s, "tart")) return K_start;
140        if (!strcmp(s, "top")) return K_stop;
141        if (!strcmp(s, "ymlink")) return K_symlink;
142        if (!strcmp(s, "ysclktz")) return K_sysclktz;
143        break;
144    case 't':
145        if (!strcmp(s, "rigger")) return K_trigger;
146        break;
147    case 'u':
148        if (!strcmp(s, "ser")) return K_user;
149        break;
150    case 'w':
151        if (!strcmp(s, "rite")) return K_write;
152        if (!strcmp(s, "ait")) return K_wait;
153        break;
154    }
155    return K_UNKNOWN;
156}
157
158void parse_line_no_op(struct parse_state *state, int nargs, char **args)
159{
160}
161
162static int push_chars(char **dst, int *len, const char *chars, int cnt)
163{
164    if (cnt > *len)
165        return -1;
166
167    memcpy(*dst, chars, cnt);
168    *dst += cnt;
169    *len -= cnt;
170
171    return 0;
172}
173
174static int expand_props(char *dst, const char *src, int dst_size)
175{
176    int cnt = 0;
177    char *dst_ptr = dst;
178    const char *src_ptr = src;
179    int src_len;
180    int idx = 0;
181    int ret = 0;
182    int left = dst_size - 1;
183
184    if (!src || !dst || dst_size == 0)
185        return -1;
186
187    src_len = strlen(src);
188
189    /* - variables can either be $x.y or ${x.y}, in case they are only part
190     *   of the string.
191     * - will accept $$ as a literal $.
192     * - no nested property expansion, i.e. ${foo.${bar}} is not supported,
193     *   bad things will happen
194     */
195    while (*src_ptr && left > 0) {
196        char *c;
197        char prop[PROP_NAME_MAX + 1];
198        const char *prop_val;
199        int prop_len = 0;
200
201        c = strchr(src_ptr, '$');
202        if (!c) {
203            while (left-- > 0 && *src_ptr)
204                *(dst_ptr++) = *(src_ptr++);
205            break;
206        }
207
208        memset(prop, 0, sizeof(prop));
209
210        ret = push_chars(&dst_ptr, &left, src_ptr, c - src_ptr);
211        if (ret < 0)
212            goto err_nospace;
213        c++;
214
215        if (*c == '$') {
216            *(dst_ptr++) = *(c++);
217            src_ptr = c;
218            left--;
219            continue;
220        } else if (*c == '\0') {
221            break;
222        }
223
224        if (*c == '{') {
225            c++;
226            while (*c && *c != '}' && prop_len < PROP_NAME_MAX)
227                prop[prop_len++] = *(c++);
228            if (*c != '}') {
229                /* failed to find closing brace, abort. */
230                if (prop_len == PROP_NAME_MAX)
231                    ERROR("prop name too long during expansion of '%s'\n",
232                          src);
233                else if (*c == '\0')
234                    ERROR("unexpected end of string in '%s', looking for }\n",
235                          src);
236                goto err;
237            }
238            prop[prop_len] = '\0';
239            c++;
240        } else if (*c) {
241            while (*c && prop_len < PROP_NAME_MAX)
242                prop[prop_len++] = *(c++);
243            if (prop_len == PROP_NAME_MAX && *c != '\0') {
244                ERROR("prop name too long in '%s'\n", src);
245                goto err;
246            }
247            prop[prop_len] = '\0';
248            ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
249                  prop);
250        }
251
252        if (prop_len == 0) {
253            ERROR("invalid zero-length prop name in '%s'\n", src);
254            goto err;
255        }
256
257        prop_val = property_get(prop);
258        if (!prop_val) {
259            ERROR("property '%s' doesn't exist while expanding '%s'\n",
260                  prop, src);
261            goto err;
262        }
263
264        ret = push_chars(&dst_ptr, &left, prop_val, strlen(prop_val));
265        if (ret < 0)
266            goto err_nospace;
267        src_ptr = c;
268        continue;
269    }
270
271    *dst_ptr = '\0';
272    return 0;
273
274err_nospace:
275    ERROR("destination buffer overflow while expanding '%s'\n", src);
276err:
277    return -1;
278}
279
280void parse_new_section(struct parse_state *state, int kw,
281                       int nargs, char **args)
282{
283    printf("[ %s %s ]\n", args[0],
284           nargs > 1 ? args[1] : "");
285    switch(kw) {
286    case K_service:
287        state->context = parse_service(state, nargs, args);
288        if (state->context) {
289            state->parse_line = parse_line_service;
290            return;
291        }
292        break;
293    case K_on:
294        state->context = parse_action(state, nargs, args);
295        if (state->context) {
296            state->parse_line = parse_line_action;
297            return;
298        }
299        break;
300    case K_import:
301        {
302            char conf_file[PATH_MAX];
303            int ret;
304
305            if (nargs != 2) {
306                ERROR("single argument needed for import\n");
307                break;
308            }
309
310            ret = expand_props(conf_file, args[1], sizeof(conf_file));
311            if (ret) {
312                ERROR("error while handling import on line '%d' in '%s'\n",
313                      state->line, state->filename);
314                break;
315            }
316            ret = init_parse_config_file(conf_file);
317            if (ret)
318                ERROR("could not import file '%s'\n", conf_file);
319        }
320        break;
321    }
322    state->parse_line = parse_line_no_op;
323}
324
325static void parse_config(const char *fn, char *s)
326{
327    struct parse_state state;
328    char *args[INIT_PARSER_MAXARGS];
329    int nargs;
330
331    nargs = 0;
332    state.filename = fn;
333    state.line = 0;
334    state.ptr = s;
335    state.nexttoken = 0;
336    state.parse_line = parse_line_no_op;
337    for (;;) {
338        switch (next_token(&state)) {
339        case T_EOF:
340            state.parse_line(&state, 0, 0);
341            return;
342        case T_NEWLINE:
343            state.line++;
344            if (nargs) {
345                int kw = lookup_keyword(args[0]);
346                if (kw_is(kw, SECTION)) {
347                    state.parse_line(&state, 0, 0);
348                    parse_new_section(&state, kw, nargs, args);
349                } else {
350                    state.parse_line(&state, nargs, args);
351                }
352                nargs = 0;
353            }
354            break;
355        case T_TEXT:
356            if (nargs < INIT_PARSER_MAXARGS) {
357                args[nargs++] = state.text;
358            }
359            break;
360        }
361    }
362}
363
364int init_parse_config_file(const char *fn)
365{
366    char *data;
367    data = read_file(fn, 0);
368    if (!data) return -1;
369
370    parse_config(fn, data);
371    DUMP();
372    return 0;
373}
374
375static int valid_name(const char *name)
376{
377    if (strlen(name) > 16) {
378        return 0;
379    }
380    while (*name) {
381        if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
382            return 0;
383        }
384        name++;
385    }
386    return 1;
387}
388
389struct service *service_find_by_name(const char *name)
390{
391    struct listnode *node;
392    struct service *svc;
393    list_for_each(node, &service_list) {
394        svc = node_to_item(node, struct service, slist);
395        if (!strcmp(svc->name, name)) {
396            return svc;
397        }
398    }
399    return 0;
400}
401
402struct service *service_find_by_pid(pid_t pid)
403{
404    struct listnode *node;
405    struct service *svc;
406    list_for_each(node, &service_list) {
407        svc = node_to_item(node, struct service, slist);
408        if (svc->pid == pid) {
409            return svc;
410        }
411    }
412    return 0;
413}
414
415struct service *service_find_by_keychord(int keychord_id)
416{
417    struct listnode *node;
418    struct service *svc;
419    list_for_each(node, &service_list) {
420        svc = node_to_item(node, struct service, slist);
421        if (svc->keychord_id == keychord_id) {
422            return svc;
423        }
424    }
425    return 0;
426}
427
428void service_for_each(void (*func)(struct service *svc))
429{
430    struct listnode *node;
431    struct service *svc;
432    list_for_each(node, &service_list) {
433        svc = node_to_item(node, struct service, slist);
434        func(svc);
435    }
436}
437
438void service_for_each_class(const char *classname,
439                            void (*func)(struct service *svc))
440{
441    struct listnode *node;
442    struct service *svc;
443    list_for_each(node, &service_list) {
444        svc = node_to_item(node, struct service, slist);
445        if (!strcmp(svc->classname, classname)) {
446            func(svc);
447        }
448    }
449}
450
451void service_for_each_flags(unsigned matchflags,
452                            void (*func)(struct service *svc))
453{
454    struct listnode *node;
455    struct service *svc;
456    list_for_each(node, &service_list) {
457        svc = node_to_item(node, struct service, slist);
458        if (svc->flags & matchflags) {
459            func(svc);
460        }
461    }
462}
463
464void action_for_each_trigger(const char *trigger,
465                             void (*func)(struct action *act))
466{
467    struct listnode *node;
468    struct action *act;
469    list_for_each(node, &action_list) {
470        act = node_to_item(node, struct action, alist);
471        if (!strcmp(act->name, trigger)) {
472            func(act);
473        }
474    }
475}
476
477void queue_property_triggers(const char *name, const char *value)
478{
479    struct listnode *node;
480    struct action *act;
481    list_for_each(node, &action_list) {
482        act = node_to_item(node, struct action, alist);
483        if (!strncmp(act->name, "property:", strlen("property:"))) {
484            const char *test = act->name + strlen("property:");
485            int name_length = strlen(name);
486
487            if (!strncmp(name, test, name_length) &&
488                    test[name_length] == '=' &&
489                    (!strcmp(test + name_length + 1, value) ||
490                     !strcmp(test + name_length + 1, "*"))) {
491                action_add_queue_tail(act);
492            }
493        }
494    }
495}
496
497void queue_all_property_triggers()
498{
499    struct listnode *node;
500    struct action *act;
501    list_for_each(node, &action_list) {
502        act = node_to_item(node, struct action, alist);
503        if (!strncmp(act->name, "property:", strlen("property:"))) {
504            /* parse property name and value
505               syntax is property:<name>=<value> */
506            const char* name = act->name + strlen("property:");
507            const char* equals = strchr(name, '=');
508            if (equals) {
509                char prop_name[PROP_NAME_MAX + 1];
510                const char* value;
511                int length = equals - name;
512                if (length > PROP_NAME_MAX) {
513                    ERROR("property name too long in trigger %s", act->name);
514                } else {
515                    memcpy(prop_name, name, length);
516                    prop_name[length] = 0;
517
518                    /* does the property exist, and match the trigger value? */
519                    value = property_get(prop_name);
520                    if (value && (!strcmp(equals + 1, value) ||
521                                  !strcmp(equals + 1, "*"))) {
522                        action_add_queue_tail(act);
523                    }
524                }
525            }
526        }
527    }
528}
529
530void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
531{
532    struct action *act;
533    struct command *cmd;
534
535    act = calloc(1, sizeof(*act));
536    act->name = name;
537    list_init(&act->commands);
538
539    cmd = calloc(1, sizeof(*cmd));
540    cmd->func = func;
541    cmd->args[0] = name;
542    list_add_tail(&act->commands, &cmd->clist);
543
544    list_add_tail(&action_list, &act->alist);
545    action_add_queue_tail(act);
546}
547
548void action_add_queue_tail(struct action *act)
549{
550    list_add_tail(&action_queue, &act->qlist);
551}
552
553struct action *action_remove_queue_head(void)
554{
555    if (list_empty(&action_queue)) {
556        return 0;
557    } else {
558        struct listnode *node = list_head(&action_queue);
559        struct action *act = node_to_item(node, struct action, qlist);
560        list_remove(node);
561        return act;
562    }
563}
564
565int action_queue_empty()
566{
567    return list_empty(&action_queue);
568}
569
570static void *parse_service(struct parse_state *state, int nargs, char **args)
571{
572    struct service *svc;
573    if (nargs < 3) {
574        parse_error(state, "services must have a name and a program\n");
575        return 0;
576    }
577    if (!valid_name(args[1])) {
578        parse_error(state, "invalid service name '%s'\n", args[1]);
579        return 0;
580    }
581
582    svc = service_find_by_name(args[1]);
583    if (svc) {
584        parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
585        return 0;
586    }
587
588    nargs -= 2;
589    svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
590    if (!svc) {
591        parse_error(state, "out of memory\n");
592        return 0;
593    }
594    svc->name = args[1];
595    svc->classname = "default";
596    memcpy(svc->args, args + 2, sizeof(char*) * nargs);
597    svc->args[nargs] = 0;
598    svc->nargs = nargs;
599    svc->onrestart.name = "onrestart";
600    list_init(&svc->onrestart.commands);
601    list_add_tail(&service_list, &svc->slist);
602    return svc;
603}
604
605static void parse_line_service(struct parse_state *state, int nargs, char **args)
606{
607    struct service *svc = state->context;
608    struct command *cmd;
609    int i, kw, kw_nargs;
610
611    if (nargs == 0) {
612        return;
613    }
614
615    svc->ioprio_class = IoSchedClass_NONE;
616
617    kw = lookup_keyword(args[0]);
618    switch (kw) {
619    case K_capability:
620        break;
621    case K_class:
622        if (nargs != 2) {
623            parse_error(state, "class option requires a classname\n");
624        } else {
625            svc->classname = args[1];
626        }
627        break;
628    case K_console:
629        svc->flags |= SVC_CONSOLE;
630        break;
631    case K_disabled:
632        svc->flags |= SVC_DISABLED;
633        svc->flags |= SVC_RC_DISABLED;
634        break;
635    case K_ioprio:
636        if (nargs != 3) {
637            parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
638        } else {
639            svc->ioprio_pri = strtoul(args[2], 0, 8);
640
641            if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
642                parse_error(state, "priority value must be range 0 - 7\n");
643                break;
644            }
645
646            if (!strcmp(args[1], "rt")) {
647                svc->ioprio_class = IoSchedClass_RT;
648            } else if (!strcmp(args[1], "be")) {
649                svc->ioprio_class = IoSchedClass_BE;
650            } else if (!strcmp(args[1], "idle")) {
651                svc->ioprio_class = IoSchedClass_IDLE;
652            } else {
653                parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
654            }
655        }
656        break;
657    case K_group:
658        if (nargs < 2) {
659            parse_error(state, "group option requires a group id\n");
660        } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
661            parse_error(state, "group option accepts at most %d supp. groups\n",
662                        NR_SVC_SUPP_GIDS);
663        } else {
664            int n;
665            svc->gid = decode_uid(args[1]);
666            for (n = 2; n < nargs; n++) {
667                svc->supp_gids[n-2] = decode_uid(args[n]);
668            }
669            svc->nr_supp_gids = n - 2;
670        }
671        break;
672    case K_keycodes:
673        if (nargs < 2) {
674            parse_error(state, "keycodes option requires atleast one keycode\n");
675        } else {
676            svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
677            if (!svc->keycodes) {
678                parse_error(state, "could not allocate keycodes\n");
679            } else {
680                svc->nkeycodes = nargs - 1;
681                for (i = 1; i < nargs; i++) {
682                    svc->keycodes[i - 1] = atoi(args[i]);
683                }
684            }
685        }
686        break;
687    case K_oneshot:
688        svc->flags |= SVC_ONESHOT;
689        break;
690    case K_onrestart:
691        nargs--;
692        args++;
693        kw = lookup_keyword(args[0]);
694        if (!kw_is(kw, COMMAND)) {
695            parse_error(state, "invalid command '%s'\n", args[0]);
696            break;
697        }
698        kw_nargs = kw_nargs(kw);
699        if (nargs < kw_nargs) {
700            parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
701                kw_nargs > 2 ? "arguments" : "argument");
702            break;
703        }
704
705        cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
706        cmd->func = kw_func(kw);
707        cmd->nargs = nargs;
708        memcpy(cmd->args, args, sizeof(char*) * nargs);
709        list_add_tail(&svc->onrestart.commands, &cmd->clist);
710        break;
711    case K_critical:
712        svc->flags |= SVC_CRITICAL;
713        break;
714    case K_setenv: { /* name value */
715        struct svcenvinfo *ei;
716        if (nargs < 2) {
717            parse_error(state, "setenv option requires name and value arguments\n");
718            break;
719        }
720        ei = calloc(1, sizeof(*ei));
721        if (!ei) {
722            parse_error(state, "out of memory\n");
723            break;
724        }
725        ei->name = args[1];
726        ei->value = args[2];
727        ei->next = svc->envvars;
728        svc->envvars = ei;
729        break;
730    }
731    case K_socket: {/* name type perm [ uid gid ] */
732        struct socketinfo *si;
733        if (nargs < 4) {
734            parse_error(state, "socket option requires name, type, perm arguments\n");
735            break;
736        }
737        if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
738                && strcmp(args[2],"seqpacket")) {
739            parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
740            break;
741        }
742        si = calloc(1, sizeof(*si));
743        if (!si) {
744            parse_error(state, "out of memory\n");
745            break;
746        }
747        si->name = args[1];
748        si->type = args[2];
749        si->perm = strtoul(args[3], 0, 8);
750        if (nargs > 4)
751            si->uid = decode_uid(args[4]);
752        if (nargs > 5)
753            si->gid = decode_uid(args[5]);
754        si->next = svc->sockets;
755        svc->sockets = si;
756        break;
757    }
758    case K_user:
759        if (nargs != 2) {
760            parse_error(state, "user option requires a user id\n");
761        } else {
762            svc->uid = decode_uid(args[1]);
763        }
764        break;
765    default:
766        parse_error(state, "invalid option '%s'\n", args[0]);
767    }
768}
769
770static void *parse_action(struct parse_state *state, int nargs, char **args)
771{
772    struct action *act;
773    if (nargs < 2) {
774        parse_error(state, "actions must have a trigger\n");
775        return 0;
776    }
777    if (nargs > 2) {
778        parse_error(state, "actions may not have extra parameters\n");
779        return 0;
780    }
781    act = calloc(1, sizeof(*act));
782    act->name = args[1];
783    list_init(&act->commands);
784    list_add_tail(&action_list, &act->alist);
785        /* XXX add to hash */
786    return act;
787}
788
789static void parse_line_action(struct parse_state* state, int nargs, char **args)
790{
791    struct command *cmd;
792    struct action *act = state->context;
793    int (*func)(int nargs, char **args);
794    int kw, n;
795
796    if (nargs == 0) {
797        return;
798    }
799
800    kw = lookup_keyword(args[0]);
801    if (!kw_is(kw, COMMAND)) {
802        parse_error(state, "invalid command '%s'\n", args[0]);
803        return;
804    }
805
806    n = kw_nargs(kw);
807    if (nargs < n) {
808        parse_error(state, "%s requires %d %s\n", args[0], n - 1,
809            n > 2 ? "arguments" : "argument");
810        return;
811    }
812    cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
813    cmd->func = kw_func(kw);
814    cmd->nargs = nargs;
815    memcpy(cmd->args, args, sizeof(char*) * nargs);
816    list_add_tail(&act->commands, &cmd->clist);
817}
818