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

Last change on this file since 6750 was 6750, checked in by nbd, 10 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.