source: trunk/package/busybox/patches/920-awx.patch @ 6750

Last change on this file since 6750 was 6750, checked in by nbd, 9 years ago

fix an uninitialized variable in awx (does not fix random segfault yet, still looking into it)

File size: 27.4 KB
  • editors/awk.c

    diff -purN bb.old/editors/awk.c bb.dev/editors/awk.c
    old new  
    3030/* these flags are static, don't change them when value is changed */ 
    3131#define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY) 
    3232 
     33#ifdef CONFIG_AWX 
     34#define fputs(s, stream) fputs_hook(s, stream) 
     35static inline int fputs_hook (__const char *__restrict __s, FILE *__restrict __stream); 
     36#endif 
     37 
    3338/* Variable */ 
    3439typedef struct var_s { 
    3540        unsigned short type;            /* flags */ 
    typedef struct chain_s { 
    5055        char *programname; 
    5156} chain; 
    5257 
     58typedef var *(*awk_cfunc)(var *res, var *args, int nargs); 
    5359/* Function */ 
    5460typedef struct func_s { 
    5561        unsigned short nargs; 
    56         struct chain_s body; 
     62        enum { AWKFUNC, CFUNC } type; 
     63        union { 
     64                awk_cfunc cfunc; 
     65                struct chain_s body; 
     66        } x; 
    5767} func; 
    5868 
    5969/* I/O stream */ 
    static void parse_program(char *p) 
    13121322                        next_token(TC_FUNCTION); 
    13131323                        pos++; 
    13141324                        f = newfunc(t.string); 
    1315                         f->body.first = NULL; 
     1325                        f->type = AWKFUNC; 
     1326                        f->x.body.first = NULL; 
    13161327                        f->nargs = 0; 
    13171328                        while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { 
    13181329                                v = findvar(ahash, t.string); 
    static void parse_program(char *p) 
    13211332                                if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) 
    13221333                                        break; 
    13231334                        } 
    1324                         seq = &(f->body); 
     1335                        seq = &(f->x.body); 
    13251336                        chain_group(); 
    13261337                        clear_array(ahash); 
    13271338 
    static var *evaluate(node *op, var *res) 
    22602271                        break; 
    22612272 
    22622273                case XC( OC_FUNC ): 
    2263                         if (! op->r.f->body.first) 
     2274                        if ((op->r.f->type == AWKFUNC) && 
     2275                                !op->r.f->x.body.first) 
    22642276                                runtime_error(EMSG_UNDEF_FUNC); 
    22652277 
    22662278                        X.v = R.v = nvalloc(op->r.f->nargs+1); 
    static var *evaluate(node *op, var *res) 
    22772289                        fnargs = X.v; 
    22782290 
    22792291                        L.s = programname; 
    2280                         res = evaluate(op->r.f->body.first, res); 
     2292                        if (op->r.f->type == AWKFUNC) 
     2293                                res = evaluate(op->r.f->x.body.first, res); 
     2294                        else if (op->r.f->type == CFUNC) 
     2295                                res = op->r.f->x.cfunc(res, fnargs, op->r.f->nargs); 
     2296 
    22812297                        programname = L.s; 
    22822298 
    22832299                        nvfree(fnargs); 
    static rstream *next_input_file(void) 
    26372653        return &rsm; 
    26382654} 
    26392655 
     2656#ifdef CONFIG_AWX 
     2657static int is_awx = 0; 
     2658#include "awx.c" 
     2659#endif 
     2660 
    26402661int awk_main(int argc, char **argv) 
    26412662{ 
    26422663        int i, j, flen; 
    int awk_main(int argc, char **argv) 
    26932714                free(s); 
    26942715        } 
    26952716 
     2717#ifdef CONFIG_AWX 
     2718        do_awx(argc, argv); 
     2719#endif 
     2720 
    26962721        programname = NULL; 
    26972722        while((c = getopt(argc, argv, "F:v:f:W:")) != EOF) { 
    26982723                switch (c) { 
  • editors/awx.c

    diff -purN bb.old/editors/awx.c bb.dev/editors/awx.c
    old new  
     1/* 
     2 * awk web extension 
     3 * 
     4 * Copyright (C) 2007 by Felix Fietkau <nbd@openwrt.org> 
     5 * 
     6 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 
     7 */ 
     8 
     9#include <cgi.h> 
     10#include <glob.h> 
     11 
     12#define LINE_BUF 2048 
     13#define HASH_MAX        1536 
     14#define TR_START        "@TR<<" 
     15#define TR_END          ">>" 
     16#define MAX_TR  32 
     17#define SSI_START "<%" 
     18#define SSI_END "%>" 
     19 
     20#undef fputs 
     21 
     22static xhash *lstr = NULL; 
     23static xhash *formvar = NULL; 
     24static int lang_inuse = 0; 
     25 
     26/* look up a translation symbol from the hash */ 
     27static inline char *translate_lookup(char *str) 
     28{ 
     29        char *name, *def, *p; 
     30        hash_item *hi; 
     31        var *v; 
     32 
     33        def = name = str; 
     34        if (((p = strchr(str, '|')) != NULL) 
     35                || ((p = strchr(str, '#')) != NULL)) { 
     36                def = p + 1; 
     37                *p = 0; 
     38        } 
     39         
     40        hi = hash_search(lstr, name); 
     41        if (!hi) 
     42                return def; 
     43         
     44        v = &hi->data.v; 
     45 
     46        return getvar_s(v); 
     47} 
     48 
     49/* look for translation markers in the line and return the translated string */ 
     50static char *translate_line(char *line) 
     51{ 
     52        char *tok[MAX_TR * 3]; 
     53        char *l, *p, *p2, *res; 
     54        int len = 0, _pos = 0, i; 
     55 
     56        l = line; 
     57        while (l != NULL) { 
     58                if ((p = strstr(l, TR_START)) == NULL) { 
     59                        len += strlen((tok[_pos++] = l)); 
     60                        break; 
     61                } 
     62 
     63                p2 = strstr(p, TR_END); 
     64                if (p2 == NULL) 
     65                        break; 
     66 
     67                *p = 0; 
     68                *p2 = 0; 
     69                len += strlen((tok[_pos++] = l)); 
     70                len += strlen((tok[_pos++] = translate_lookup(p + strlen(TR_START)))); 
     71 
     72                l = p2; 
     73                l += strlen(TR_END); 
     74        } 
     75        len++; 
     76 
     77        p = xmalloc(len + 1); 
     78        *p = 0; 
     79        res = p; 
     80        for (i = 0; i < _pos; i++) { 
     81                strcat(p, tok[i]); 
     82                p += strlen(tok[i]); 
     83        } 
     84 
     85        return res; 
     86} 
     87 
     88/* hook for intercepting awk's use of puts. used for running all printed strings 
     89 * through the translation system */ 
     90static inline int fputs_hook (__const char *__restrict __s, FILE *__restrict __stream) 
     91{ 
     92        if (lang_inuse && (__stream == stdout)) { 
     93                int ret; 
     94                char *str; 
     95         
     96                str = translate_line((char *) __s); 
     97                ret = fputs(str, __stream); 
     98                free(str); 
     99 
     100                return ret; 
     101        } 
     102 
     103        return fputs(__s, __stream); 
     104} 
     105 
     106static var *init_lang(var *res, var *args, int nargs) 
     107{ 
     108        if (!lstr) 
     109                lstr = hash_init(); 
     110 
     111        lang_inuse = 1; 
     112        return res; 
     113} 
     114 
     115 
     116/* load and parse language file */ 
     117static void load_lang_file(char *file) 
     118{ 
     119        FILE *f; 
     120        char *b, *name, *value; 
     121        char buf1[LINE_BUF]; 
     122 
     123        if ((f = fopen(file, "r")) == NULL) 
     124                return; 
     125 
     126        while (!feof(f) && (fgets(buf1, LINE_BUF - 1, f) != NULL)) { 
     127                b = buf1; 
     128                if (*b == '#') 
     129                        continue; /* skip comments */ 
     130 
     131                while (isspace(*b)) 
     132                        b++; /* skip leading spaces */ 
     133                if (!*b) 
     134                        continue; 
     135                 
     136                name = b; 
     137                if ((b = strstr(name, "=>")) == NULL) 
     138                        continue; /* separator not found */ 
     139 
     140                value = b + 2; 
     141                if (!*value) 
     142                        continue; 
     143                 
     144                *b = 0; 
     145                for (b--; isspace(*b); b--) 
     146                        *b = 0; /* remove trailing spaces */ 
     147                 
     148                while (isspace(*value)) 
     149                        value++; /* skip leading spaces */ 
     150 
     151                for (b = value + strlen(value) - 1; isspace(*b); b--) 
     152                        *b = 0; /* remove trailing spaces */ 
     153                 
     154                if (!*value) 
     155                        continue; 
     156 
     157                setvar_s(findvar(lstr,name), value); 
     158        } 
     159 
     160        fclose(f); 
     161} 
     162 
     163static var *load_lang(var *res, var *args, int nargs) 
     164{ 
     165        const char *langfmt = "/usr/lib/webif/lang/%s.txt"; 
     166        char lbuf[LINE_BUF]; 
     167        char *lang; 
     168 
     169        if (!lang_inuse) 
     170                init_lang(res, args, nargs); 
     171         
     172        lang = getvar_s(args); 
     173        if (!lang || !strcmp(lang, "")) 
     174                return res; 
     175 
     176        sprintf(lbuf, langfmt, lang); 
     177        load_lang_file(lbuf); 
     178 
     179        return res;      
     180} 
     181                 
     182/* read the contents of an entire file */ 
     183static char *get_file(char *fname) 
     184{ 
     185        FILE *F; 
     186        char *s = NULL; 
     187        int i, j, flen; 
     188 
     189        F = fopen(fname, "r"); 
     190        if (!F) { 
     191                return NULL; 
     192        } 
     193 
     194        if (fseek(F, 0, SEEK_END) == 0) { 
     195                flen = ftell(F); 
     196                s = (char *)xmalloc(flen+4); 
     197                fseek(F, 0, SEEK_SET); 
     198                i = 1 + fread(s+1, 1, flen, F); 
     199        } else { 
     200                for (i=j=1; j>0; i+=j) { 
     201                        s = (char *)xrealloc(s, i+4096); 
     202                        j = fread(s+i, 1, 4094, F); 
     203                } 
     204        } 
     205 
     206        s[i] = '\0'; 
     207        fclose(F); 
     208        return s; 
     209} 
     210 
     211 
     212/* parse_include(): 
     213 *  
     214 * taken from parse_program from awk.c 
     215 * END{} is not parsed here, and BEGIN{} is executed immediately 
     216 */ 
     217static void parse_include(char *p) 
     218{ 
     219        uint32_t tclass; 
     220        chain *initseq = NULL; 
     221        chain tmp; 
     222        func *f; 
     223        var *v, tv; 
     224 
     225        memset(&tmp, 0, sizeof(tmp)); 
     226        pos = p; 
     227        t.lineno = 1; 
     228        while ((tclass = next_token(TC_EOF | TC_OPSEQ | 
     229                                TC_OPTERM | TC_BEGIN | TC_FUNCDECL)) != TC_EOF) { 
     230                if (tclass & TC_OPTERM) 
     231                        continue; 
     232 
     233                seq = &tmp; 
     234                if (tclass & TC_BEGIN) { 
     235                        initseq = xzalloc(sizeof(chain)); 
     236                        seq = initseq; 
     237                        chain_group(); 
     238                } else if (tclass & TC_FUNCDECL) { 
     239                        next_token(TC_FUNCTION); 
     240                        pos++; 
     241                        f = newfunc(t.string); 
     242                        f->type = AWKFUNC; 
     243                        f->x.body.first = NULL; 
     244                        f->nargs = 0; 
     245                        while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { 
     246                                v = findvar(ahash, t.string); 
     247                                v->x.aidx = (f->nargs)++; 
     248 
     249                                if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) 
     250                                        break; 
     251                        } 
     252                        seq = &(f->x.body); 
     253                        chain_group(); 
     254                        clear_array(ahash); 
     255                } 
     256        } 
     257        if (initseq) 
     258                evaluate(initseq->first, &tv); 
     259} 
     260 
     261 
     262/* include an awk file and run its BEGIN{} section */ 
     263static xhash *includes = NULL; 
     264static void include_file(char *filename) 
     265{ 
     266        char *s; 
     267        var *v; 
     268 
     269        if (!includes) 
     270                includes = hash_init(); 
     271         
     272        /* find out if the file has been included already */ 
     273        v = findvar(includes, filename); 
     274        if (istrue(v)) 
     275                return; 
     276        setvar_s(v, "1"); 
     277 
     278        /* read include file */ 
     279        s = get_file(filename); 
     280        if (!s) { 
     281                fprintf(stderr, "Could not open file.\n"); 
     282                return; 
     283        } 
     284        parse_include(s+1); 
     285        free(s); 
     286} 
     287 
     288static var *include(var *res, var *args, int nargs) 
     289{ 
     290        char *s; 
     291 
     292        s = getvar_s(args); 
     293        if (s && (strlen(s) > 0)) 
     294                include_file(s); 
     295 
     296        return res; 
     297} 
     298 
     299 
     300/* parse and evaluate an awk expression and return the result as string */ 
     301static char *render_lookup(char *fname, int lnr, char *str) 
     302{ 
     303        chain body; 
     304        var tv; 
     305 
     306        memset(&body, 0, sizeof(body)); 
     307        zero_out_var(&tv); 
     308        pos = str; 
     309        seq = &body; 
     310         
     311        /* end of expression, assume that there's going to be a free byte 
     312         * at the end of the string that can be used for the ')' */ 
     313        strcat(str + strlen(str), ")"); 
     314        return getvar_s(evaluate(parse_expr(TC_SEQTERM), &tv)); 
     315} 
     316 
     317static inline void print_translate(char *s) 
     318{ 
     319        char *str = s; 
     320        if (lang_inuse) 
     321                str = translate_line(s); 
     322        fputs(str, stdout); 
     323        fflush(stdout); 
     324        if (lang_inuse) 
     325                free(str); 
     326} 
     327 
     328/* process awk calls in a template line and print the output to stdout */ 
     329static void render_line(char *fname, int lnr, char *line) 
     330{ 
     331        char *tok[MAX_TR * 3]; 
     332        char *l, *p, *p2, *res; 
     333        int len = 0, _pos = 0, i; 
     334 
     335        l = line; 
     336        while (l != NULL) { 
     337                if ((p = strstr(l, SSI_START)) == NULL) { 
     338                        len += strlen((tok[_pos++] = l)); 
     339                        break; 
     340                } 
     341 
     342                p2 = strstr(p, SSI_END); 
     343                if (p2 == NULL) { 
     344                        fprintf(stderr, "Parse error in '%s', line '%d', unmatched %s\n", fname, lnr, SSI_END); 
     345                        break; 
     346                } 
     347 
     348                *p = 0; 
     349                *p2 = 0; 
     350                 
     351                len += strlen((tok[_pos++] = l)); 
     352                len += strlen((tok[_pos++] = render_lookup(fname, lnr, p + strlen(SSI_START)))); 
     353 
     354                l = p2; 
     355                l += strlen(SSI_END); 
     356        } 
     357        len++; 
     358 
     359        p = xmalloc(len + 1); 
     360        *p = 0; 
     361        res = p; 
     362        for (i = 0; i < _pos; i++) { 
     363                strcat(p, tok[i]); 
     364                p += strlen(tok[i]); 
     365        } 
     366        print_translate(res); 
     367        free(res); 
     368} 
     369 
     370/* awk method render(), which opens a template file and processes all awk ssi calls */ 
     371static void render_file(char *filename) 
     372{ 
     373        int lnr = 0; 
     374        FILE *f; 
     375        char *buf1; 
     376                         
     377        f = fopen(filename, "r"); 
     378        if (!f) 
     379                return; 
     380         
     381        buf1 = xmalloc(LINE_BUF); 
     382        while (!feof(f) && (fgets(buf1, LINE_BUF - 1, f) != NULL)) { 
     383                render_line(filename, ++lnr, buf1); 
     384        } 
     385} 
     386 
     387static var *render(var *res, var *args, int nargs) 
     388{ 
     389        char *s; 
     390 
     391        s = getvar_s(args); 
     392        if (!s) 
     393                return res; 
     394 
     395        render_file(s); 
     396         
     397        return res; 
     398} 
     399                 
     400/* Call render, but only if this function hasn't been called already */ 
     401static int layout_rendered = 0; 
     402static var *render_layout(var *res, var *args, int nargs) 
     403{ 
     404        if (layout_rendered) 
     405                return res; 
     406        layout_rendered = 1; 
     407        return render(res, args, nargs); 
     408} 
     409 
     410/* registers a global c function for the awk interpreter */ 
     411static void register_cfunc(char *name, awk_cfunc cfunc, int nargs) 
     412{ 
     413        func *f; 
     414 
     415        f = newfunc(name); 
     416        f->type = CFUNC; 
     417        f->x.cfunc = cfunc; 
     418        f->nargs = nargs; 
     419} 
     420 
     421static void putvar(vartype type, char *name, char *value) 
     422{ 
     423        if (type != FORM_VAR) 
     424                return; 
     425 
     426        setvar_u(findvar(formvar, name), value); 
     427} 
     428 
     429static char *cgi_getvar(char *name) 
     430{ 
     431        if (!formvar) { 
     432                formvar = hash_init(); 
     433                cgi_init(putvar); 
     434        } 
     435 
     436        if (!formvar || !name) 
     437                return NULL; 
     438         
     439        return getvar_s(findvar(formvar, name)); 
     440} 
     441 
     442/* function call for accessing cgi form variables */ 
     443static var *getvar(var *res, var *args, int nargs) 
     444{ 
     445        char *s; 
     446        char *svar; 
     447 
     448        s = getvar_s(args); 
     449        if (!s) 
     450                return res; 
     451         
     452        svar = cgi_getvar(s); 
     453        if (!svar) 
     454                return res; 
     455 
     456        setvar_u(res, svar); 
     457 
     458        return res; 
     459} 
     460 
     461/* call an awk function without arguments by string reference */ 
     462static var *call(var *res, var *args, int nargs) 
     463{ 
     464        char *s = getvar_s(args); 
     465        func *f; 
     466 
     467        if (!s) 
     468                goto done; 
     469         
     470        f = newfunc(s); 
     471        if (f && f->type == AWKFUNC && f->x.body.first) 
     472                return evaluate(f->x.body.first, res); 
     473 
     474done: 
     475        return res; 
     476} 
     477 
     478 
     479static int run_awxscript(char *name) 
     480{ 
     481        var tv, *layout, *action; 
     482        char *tmp, *s = NULL; 
     483 
     484        zero_out_var(&tv); 
     485        programname = name; 
     486 
     487        /* read the main controller source */ 
     488        s = get_file(programname); 
     489        if (!s) { 
     490                fprintf(stderr, "Could not open file\n"); 
     491                return 1; 
     492        } 
     493        parse_program(s+1); 
     494        free(s); 
     495 
     496 
     497        /* set some defaults for ACTION and LAYOUT, which will have special meaning */ 
     498        layout = newvar("LAYOUT"); 
     499        setvar_s(layout, "views/layout.ahtml"); 
     500 
     501        /* run the BEGIN {} block */ 
     502        evaluate(beginseq.first, &tv); 
     503 
     504        action = newvar("ACTION"); 
     505        if (!(strlen(getvar_s(action)) > 0)) { 
     506                tmp = cgi_getvar("action"); 
     507                if (!tmp || (strlen(tmp) <= 0)) 
     508                        tmp = strdup("default"); 
     509 
     510                setvar_p(action, tmp); 
     511        } 
     512         
     513        /* call the action (precedence: begin block override > cgi parameter > "default") */ 
     514        tmp = xmalloc(strlen(getvar_s(action)) + 7); 
     515        sprintf(tmp, "handle_%s", getvar_s(action)); 
     516        setvar_s(action, tmp); 
     517        call(&tv, action, 1); 
     518        free(tmp); 
     519 
     520        /* render the selected layout, will do nothing if render_layout has been called from awk */ 
     521        render_layout(&tv, layout, 1); 
     522 
     523        return 0; 
     524} 
     525 
     526 
     527/* main awx processing function. called from awk_main() */ 
     528static int do_awx(int argc, char **argv) 
     529{ 
     530        int ret = -1; 
     531        var tv; 
     532        int i, c; 
     533        char **args = argv; 
     534         
     535        zero_out_var(&tv); 
     536 
     537        /* register awk C callbacks */ 
     538        register_cfunc("getvar", getvar, 1); 
     539        register_cfunc("render", render, 1); 
     540        register_cfunc("render_layout", render_layout, 1); 
     541        register_cfunc("call", call, 1); 
     542        register_cfunc("include", include, 1); 
     543        register_cfunc("init_lang", init_lang, 1); 
     544        register_cfunc("load_lang", load_lang, 1); 
     545 
     546        if (!is_awx) 
     547                return 0; 
     548 
     549        /* fill in ARGV array */ 
     550        setvar_i(V[ARGC], argc + 1); 
     551        setari_u(V[ARGV], 0, "awx"); 
     552        i = 0; 
     553        while (*args) 
     554                setari_u(V[ARGV], ++i, *args++); 
     555         
     556        while((c = getopt(argc, argv, "i:f:")) != EOF) { 
     557                switch(c) { 
     558                        case 'i': 
     559                                programname = optarg; 
     560                                include_file(optarg); 
     561                                break; 
     562                        case 'f': 
     563                                ret = 0; 
     564                                programname = optarg; 
     565                                render_file(optarg); 
     566                                goto done; 
     567                } 
     568        } 
     569        argc -= optind; 
     570        argv += optind; 
     571 
     572        if (argc < 1) { 
     573                fprintf(stderr, "Invalid argument.\n"); 
     574                goto done; 
     575        } 
     576 
     577        ret = run_awxscript(*argv); 
     578 
     579done: 
     580        exit(ret); 
     581} 
     582 
     583/* entry point for awx applet */ 
     584int awx_main(int argc, char **argv) 
     585{ 
     586        is_awx = 1; 
     587        return awk_main(argc, argv); 
     588} 
     589 
  • editors/Config.in

    diff -purN bb.old/editors/Config.in bb.dev/editors/Config.in
    old new config AWK 
    1212          Awk is used as a pattern scanning and processing language.  This is 
    1313          the BusyBox implementation of that programming language. 
    1414 
     15config AWX 
     16        bool "Enable awx (awk web extension)" 
     17        default n 
     18        depends on AWK 
     19        help 
     20          awx - awk web extension 
     21 
    1522config FEATURE_AWK_MATH 
    1623        bool "Enable math functions (requires libm)" 
    1724        default y 
  • include/applets.h

    diff -purN bb.old/include/applets.h bb.dev/include/applets.h
    old new USE_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SU 
    6060USE_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 
    6161USE_ASH(APPLET_NOUSAGE(ash, ash, _BB_DIR_BIN, _BB_SUID_NEVER)) 
    6262USE_AWK(APPLET(awk, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 
     63USE_AWX(APPLET_NOUSAGE(awx, awx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))  
    6364USE_BASENAME(APPLET(basename, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 
    6465USE_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_NEVER)) 
    6566//USE_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_NEVER)) 
  • include/cgi.h

    diff -purN bb.old/include/cgi.h bb.dev/include/cgi.h
    old new  
     1#ifndef CGI_H 
     2#define CGI_H 
     3 
     4typedef enum { FORM_VAR, COOKIE_VAR } vartype; 
     5typedef void (*var_handler) (vartype, char *, char *); 
     6int cgi_init(var_handler); 
     7 
     8#endif 
  • libbb/cgi.c

    diff -purN bb.old/libbb/cgi.c bb.dev/libbb/cgi.c
    old new  
     1/* -------------------------------------------------------------------------- 
     2 * functions for processing cgi form data 
     3 * Copyright (C) 2007 by Felix Fietkau <nbd@openwrt.org> 
     4 * 
     5 * parts taken from the core of haserl.cgi - a poor-man's php for embedded/lightweight environments 
     6 * $Id: haserl.c,v 1.13 2004/11/10 17:59:35 nangel Exp $  
     7 * Copyright (c) 2003,2004    Nathan Angelacos (nangel@users.sourceforge.net) 
     8 * 
     9 * This program is free software; you can redistribute it and/or modify 
     10 * it under the terms of the GNU General Public License as published by 
     11 * the Free Software Foundation; either version 2 of the License, or 
     12 * (at your option) any later version. 
     13 * 
     14 * This program is distributed in the hope that it will be useful, 
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
     17 * General Public License for more details. 
     18 * 
     19 * You should have received a copy of the GNU General Public License 
     20 * along with this program; if not, write to the Free Software 
     21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
     22 * 
     23 * ----- 
     24 * The x2c() and unescape_url() routines were taken from   
     25 *  http://www.jmarshall.com/easy/cgi/getcgi.c.txt  
     26 *  
     27 * The comments in that text file state: 
     28 * 
     29 ***  Written in 1996 by James Marshall, james@jmarshall.com, except  
     30 ***  that the x2c() and unescape_url() routines were lifted directly  
     31 ***  from NCSA's sample program util.c, packaged with their HTTPD.  
     32 ***     For the latest, see http://www.jmarshall.com/easy/cgi/  
     33 * ----- 
     34 * 
     35 ------------------------------------------------------------------------- */ 
     36 
     37#include <stdio.h> 
     38#include <unistd.h> 
     39#include <time.h> 
     40#include <sys/mman.h> 
     41#include <sys/types.h> 
     42#include <sys/wait.h> 
     43#include <sys/stat.h> 
     44#include <sys/fcntl.h> 
     45#include <stdlib.h> 
     46#include <string.h> 
     47#include <cgi.h> 
     48 
     49#ifndef MAX_UPLOAD_KB 
     50#define MAX_UPLOAD_KB 2048 
     51#endif 
     52#define TEMPDIR "/tmp" 
     53 
     54static int global_upload_size = 0; 
     55static int ReadMimeEncodedInput(char *qs); 
     56static var_handler do_putvar = NULL; 
     57 
     58/* 
     59 * Convert 2 char hex string into char it represents 
     60 * (from http://www.jmarshall.com/easy/cgi) 
     61 */ 
     62static char x2c (char *what) { 
     63        char digit; 
     64         
     65        digit=(what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0')); 
     66        digit *=16; 
     67        digit+=(what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0')); 
     68 
     69        return digit; 
     70} 
     71 
     72/* 
     73 * unsescape %xx to the characters they represent  
     74 */ 
     75 
     76static void unescape_url (char *url) { 
     77        int  i,j; 
     78 
     79        for (i=0, j=0; url[j]; ++i, ++j) { 
     80                if ((url[i] = url[j]) == '%') { 
     81                        url[i] = x2c(&url[j+1]); 
     82                        j+=2;    
     83                } 
     84        } 
     85        url[i]='\0'; 
     86} 
     87 
     88static inline void put_var(vartype type, char *var) 
     89{ 
     90        char *val; 
     91         
     92        if (!do_putvar) 
     93                return; 
     94 
     95        val = strchr(var, '='); 
     96        if (!val) 
     97                return; 
     98         
     99        *val = 0; 
     100        val++; 
     101        do_putvar(type, var, val); 
     102         
     103        return; 
     104} 
     105 
     106 
     107/* CookieVars () 
     108 * if HTTP_COOKIE is passed as an environment variable, 
     109 * attempt to parse its values into environment variables 
     110 */ 
     111static void CookieVars (void) 
     112{ 
     113        char *qs; 
     114        char *token; 
     115 
     116        if (getenv("HTTP_COOKIE") != NULL) 
     117                qs=strdup(getenv("HTTP_COOKIE")); 
     118        else 
     119                return; 
     120         
     121        /** split on; to extract name value pairs */ 
     122        token=strtok(qs, ";"); 
     123        while (token) { 
     124                // skip leading spaces  
     125                while ( token[0] == ' ' )  
     126                        token++; 
     127                 
     128                put_var(COOKIE_VAR, token); 
     129                 
     130                token = strtok(NULL, ";"); 
     131        } 
     132        free (qs); 
     133} 
     134 
     135/*  
     136 * Read cgi variables from query string, and put in environment 
     137 */ 
     138static int ReadCGIQueryString (void)  
     139{ 
     140        char *qs; 
     141        char *token; 
     142        int i; 
     143 
     144        if (getenv("QUERY_STRING") != NULL) 
     145                qs=strdup(getenv("QUERY_STRING")); 
     146        else 
     147                return 0; 
     148         
     149        /* change plusses into spaces */ 
     150        for (i=0; qs[i]; i++ ) { if (qs[i] == '+' ) { qs[i] = ' ';} }; 
     151 
     152        /** split on & and ; to extract name value pairs */ 
     153         
     154        token=strtok(qs, "&;"); 
     155        while (token) { 
     156                unescape_url(token); 
     157                put_var(FORM_VAR, token); 
     158                token=strtok(NULL, "&;"); 
     159        } 
     160        free(qs); 
     161 
     162        return 0; 
     163} 
     164 
     165 
     166/*  
     167 * Read cgi variables from stdin (for POST queries) 
     168 * (oh... and if its mime-encoded file upload, we save the 
     169 * file to /tmp; and return the name of the tmp file 
     170 * the cgi script is responsible for disposing of the tmp file 
     171 */ 
     172 
     173static int ReadCGIPOSTValues (void) { 
     174        char *qs; 
     175        int content_length; 
     176        int i; 
     177        char *token; 
     178 
     179 
     180        if (getenv("CONTENT_LENGTH") == NULL)  
     181                return(-1); 
     182        else 
     183                content_length = atoi(getenv("CONTENT_LENGTH")); 
     184         
     185        /* protect ourselves from 20GB file uploads */ 
     186        if (content_length > MAX_UPLOAD_KB * 1024 ) { 
     187                /* But we need to finish reading the content */ 
     188                while ( fread( &i, sizeof(int), 1, stdin) == 1 ); 
     189                return -1; 
     190        } 
     191  
     192        if (!(qs=malloc(content_length+1))) 
     193                return -1; 
     194 
     195        /* set the buffer to null, so that a browser messing with less  
     196           data than content_length won't buffer underrun us */ 
     197        memset(qs, 0 ,content_length+1); 
     198 
     199        if ((!fread(qs,content_length,1,stdin) && 
     200                (content_length > 0)  
     201                && !feof(stdin))) { 
     202                         
     203                free(qs); 
     204                return -1; 
     205        } 
     206 
     207        if (getenv("CONTENT_TYPE") && (strncasecmp(getenv("CONTENT_TYPE"), "multipart/form-data", 19) == 0)) { 
     208                /* This is a mime request, we need to go to the mime handler */ 
     209                i=ReadMimeEncodedInput(qs); 
     210                free(qs); 
     211                         
     212                return i; 
     213        } 
     214 
     215        /* change plusses into spaces */ 
     216        for (i=0; qs[i]; i++ ) { if (qs[i] == '+' ) { qs[i] = ' ';} }; 
     217 
     218        /** split on & and ; to extract name value pairs */ 
     219        token=strtok(qs, "&;"); 
     220        while (token) { 
     221                unescape_url(token); 
     222                put_var(FORM_VAR, token); 
     223                token=strtok(NULL, "&;"); 
     224        } 
     225         
     226        free(qs); 
     227         
     228        return 0; 
     229} 
     230 
     231/* 
     232 *  LineToStr - Scans char and replaces the first "\n" with a "\0"; 
     233 *  If it finds a "\r", it does that to; (fix DOS brokennes) returns 
     234 *  the length of the string; 
     235 */ 
     236static int LineToStr (char *string, size_t max) { 
     237        size_t offset=0; 
     238 
     239        while ((offset < max) && (string[offset] != '\n') && (string[offset] != '\r')) 
     240                offset++; 
     241 
     242        if (string[offset] == '\r') { 
     243                string[offset]='\0'; 
     244                offset++; 
     245        } 
     246        if (string[offset] == '\n') { 
     247                string[offset]='\0'; 
     248                offset++; 
     249        } 
     250 
     251        return offset; 
     252} 
     253 
     254 
     255/* 
     256 * ReadMimeEncodedInput - handles things that are mime encoded 
     257 * takes a pointer to the input; returns 0 on success 
     258 */ 
     259 
     260static int ReadMimeEncodedInput(char *qs)  
     261{ 
     262        char    *boundary; 
     263        char    *ct; 
     264        int     i; 
     265        int     datastart; 
     266        size_t  cl; 
     267        size_t  offset; 
     268        char    *envname; 
     269        char    *filename; 
     270        char    *ptr; 
     271        int     line; 
     272        char    tmpname[] = TEMPDIR "/XXXXXX"; 
     273        int     fd; 
     274        /* we should only get here if the content type was set. Segfaults happen 
     275           if Content_Type is null */ 
     276 
     277        if (getenv("CONTENT_LENGTH") == NULL) 
     278                /* No content length?! */ 
     279                return(-1); 
     280 
     281        cl=atoi(getenv("CONTENT_LENGTH")); 
     282         
     283        /* we do this 'cause we can't mess with the real env. variable - it would 
     284         * overwrite the environment - I tried. 
     285         */ 
     286        i=strlen(getenv("CONTENT_TYPE"))+1; 
     287        ct=malloc(i); 
     288        if (ct) 
     289                memcpy(ct, getenv("CONTENT_TYPE"), i); 
     290        else 
     291                return(-1); 
     292         
     293        i=(int) NULL; 
     294        if (ct != NULL) { 
     295                while (i < strlen(ct) && (strncmp("boundary=", &ct[i], 9) != 0))  
     296                        i++; 
     297        } 
     298        if (i == strlen(ct)) { 
     299                /* no boundary informaiton found */ 
     300                free(ct); 
     301                return -1; 
     302        } 
     303        boundary=&ct[i+7]; 
     304        /* add two leading -- to the boundary */ 
     305        boundary[0]='-'; 
     306        boundary[1]='-'; 
     307         
     308        /* begin the big loop.  Look for: 
     309                --boundary 
     310                Content-Disposition: form-data;  name="......."  
     311                .... 
     312                <blank line> 
     313                content 
     314                --boundary 
     315                Content-Disposition: form-data; name="....." filename="....." 
     316                ... 
     317                <blank line> 
     318                --boundary-- 
     319                eof 
     320        */ 
     321 
     322        offset=0; 
     323        while (offset < cl) { 
     324                /* first look for boundary */ 
     325                while ((offset < cl) && (memcmp(&qs[offset], boundary, strlen(boundary))))  
     326                        offset++; 
     327 
     328                /* if we got here and we ran off the end, its an error          */ 
     329                if (offset >= cl) {  
     330                        free(ct); 
     331                        return -1; 
     332                } 
     333 
     334                /* if the two characters following the boundary are --,         */  
     335                /* then we are at the end, exit                                 */ 
     336                if (memcmp(&qs[offset+strlen(boundary)], "--", 2) == 0) { 
     337                        offset+=2; 
     338                        break; 
     339                } 
     340                /* find where the offset should be */ 
     341                line=LineToStr(&qs[offset], cl-offset); 
     342                offset+=line; 
     343                                 
     344                /* Now we're going to look for content-disposition              */  
     345                line=LineToStr(&qs[offset], cl-offset); 
     346                if (strncasecmp(&qs[offset], "Content-Disposition", 19) != 0) { 
     347                        /* hmm... content disposition was not where we expected it */ 
     348                        free(ct); 
     349                        return -1; 
     350                } 
     351                /* Found it, so let's go find "name="                           */ 
     352                if (!(envname=strstr(&qs[offset], "name="))) { 
     353                        /* now name= is missing?!                               */ 
     354                        free(ct); 
     355                        return(-1); 
     356                } else 
     357                        envname+=6; 
     358 
     359                /* is there a filename tag?                                     */ 
     360                if ((filename=strstr(&qs[offset], "filename="))!= NULL) 
     361                        filename+=10; 
     362                else 
     363                        filename=NULL; 
     364                 
     365                /* make envname and filename ASCIIZ                             */ 
     366                for (i=0; (envname[i] != '"') && (envname[i] != '\0'); i++); 
     367                 
     368                envname[i] = '\0'; 
     369                if (filename) { 
     370                        for (i=0; (filename[i] != '"') && (filename[i] != '\0'); i++); 
     371                        filename[i] = '\0'; 
     372                } 
     373                offset+=line; 
     374                 
     375                /* Ok, by some miracle, we have the name; let's skip till we    */ 
     376                /* come to a blank line                                         */ 
     377                line=LineToStr(&qs[offset], cl-offset); 
     378                while (strlen(&qs[offset]) > 1) { 
     379                        offset+=line; 
     380                        line=LineToStr(&qs[offset], cl-offset); 
     381                } 
     382                offset+=line; 
     383                datastart=offset; 
     384                /* And we go back to looking for a boundary */ 
     385                while ((offset < cl) && (memcmp(&qs[offset], boundary, strlen(boundary)))) 
     386                        offset++; 
     387 
     388                /* strip [cr] lf */ 
     389                if ((qs[offset-1] == '\n') && (qs[offset-2] == '\r')) 
     390                        offset-=2;  
     391                else 
     392                        offset-=1; 
     393 
     394                qs[offset]=0; 
     395 
     396                /* ok, at this point, we know where the name is, and we know    */ 
     397                /* where the content is... we have to do one of two things      */ 
     398                /* based on whether its a file or not                           */ 
     399                if (filename==NULL) { /* its not a file, so its easy            */ 
     400                        /* just jam the content after the name          */ 
     401                        memcpy(&envname[strlen(envname)+1], &qs[datastart], offset-datastart+1); 
     402                        envname[strlen(envname)]='='; 
     403                        put_var(FORM_VAR, envname); 
     404                } else {        /* handle the fileupload case           */ 
     405                        if (offset-datastart) {  /* only if they uploaded */ 
     406                                if ( global_upload_size == 0 ) { 
     407                                        return -1; 
     408                                } 
     409                                /*  stuff in the filename */ 
     410                                ptr= calloc ( sizeof (char), strlen(envname)+strlen(filename)+2+5 ); 
     411                                sprintf (ptr, "%s_name=%s", envname, filename); 
     412                                put_var(FORM_VAR, ptr); 
     413                                free(ptr); 
     414                                                 
     415                                fd=mkstemp(tmpname); 
     416                                 
     417                                if (fd == -1) 
     418                                        return(-1); 
     419 
     420                                write(fd, &qs[datastart], offset-datastart); 
     421                                close(fd); 
     422                                ptr= calloc (sizeof(char), strlen(envname)+strlen(tmpname)+2); 
     423                                sprintf (ptr, "%s=%s", envname, tmpname); 
     424                                put_var(FORM_VAR, ptr); 
     425                                free(ptr); 
     426                        } 
     427                } 
     428        } 
     429        free(ct); 
     430        return 0; 
     431} 
     432 
     433         
     434/*------------------------------------------------------------------------- 
     435 * 
     436 * Main  
     437 * 
     438 *------------------------------------------------------------------------*/ 
     439 
     440int cgi_init(var_handler putvar_handler) 
     441{ 
     442        int     retval = 0; 
     443         
     444        do_putvar = putvar_handler; 
     445 
     446        /* Read the current environment into our chain */ 
     447        CookieVars(); 
     448        if (getenv("REQUEST_METHOD")) { 
     449                if (strcasecmp(getenv("REQUEST_METHOD"), "GET") == 0) 
     450                        retval = ReadCGIQueryString(); 
     451 
     452                if (strcasecmp(getenv("REQUEST_METHOD"), "POST") == 0) 
     453                        retval = ReadCGIPOSTValues(); 
     454        } 
     455 
     456        return retval; 
     457}  
  • libbb/Kbuild

    diff -purN bb.old/libbb/Kbuild bb.dev/libbb/Kbuild
    old new lib-$(CONFIG_GREP) += xregcomp.o 
    118118lib-$(CONFIG_MDEV) += xregcomp.o 
    119119lib-$(CONFIG_LESS) += xregcomp.o 
    120120lib-$(CONFIG_DEVFSD) += xregcomp.o 
     121 
     122lib-$(CONFIG_AWX) += cgi.o 
     123 
Note: See TracBrowser for help on using the repository browser.