"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.7/cmd-misc.c" (16 Feb 2018, 15516 Bytes) of package /linux/misc/s-nail-14.9.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cmd-misc.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.6_vs_14.9.7.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Miscellaneous user commands, like `echo', `pwd', etc.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  */
    7 /*
    8  * Copyright (c) 1980, 1993
    9  *      The Regents of the University of California.  All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 #undef n_FILE
   36 #define n_FILE cmd_misc
   37 
   38 #ifndef HAVE_AMALGAMATION
   39 # include "nail.h"
   40 #endif
   41 
   42 /* Expand the shell escape by expanding unescaped !'s into the last issued
   43  * command where possible */
   44 static char const *a_cmisc_bangexp(char const *cp);
   45 
   46 /* c_n?echo(), c_n?echoerr() */
   47 static int a_cmisc_echo(void *vp, FILE *fp, bool_t donl);
   48 
   49 /* c_read() */
   50 static bool_t a_cmisc_read_set(char const *cp, char const *value);
   51 
   52 /* c_version() */
   53 static int a_cmisc_version_cmp(void const *s1, void const *s2);
   54 
   55 static char const *
   56 a_cmisc_bangexp(char const *cp){
   57    static struct str last_bang;
   58 
   59    struct n_string xbang, *bang;
   60    char c;
   61    bool_t changed;
   62    NYD_ENTER;
   63 
   64    if(!ok_blook(bang))
   65       goto jleave;
   66 
   67    changed = FAL0;
   68 
   69    for(bang = n_string_creat(&xbang); (c = *cp++) != '\0';){
   70       if(c == '!'){
   71          if(last_bang.l > 0)
   72             bang = n_string_push_buf(bang, last_bang.s, last_bang.l);
   73          changed = TRU1;
   74       }else{
   75          if(c == '\\' && *cp == '!'){
   76             ++cp;
   77             c = '!';
   78             changed = TRU1;
   79          }
   80          bang = n_string_push_c(bang, c);
   81       }
   82    }
   83 
   84    if(last_bang.s != NULL)
   85       free(last_bang.s);
   86    last_bang.s = n_string_cp(bang);
   87    last_bang.l = bang->s_len;
   88    bang = n_string_drop_ownership(bang);
   89    n_string_gut(bang);
   90 
   91    cp = last_bang.s;
   92    if(changed)
   93       fprintf(n_stdout, "!%s\n", cp);
   94 jleave:
   95    NYD_LEAVE;
   96    return cp;
   97 }
   98 
   99 static int
  100 a_cmisc_echo(void *vp, FILE *fp, bool_t donl){
  101    struct n_string s, *sp;
  102    int rv;
  103    bool_t doerr;
  104    char const **argv, *varname, **ap, *cp;
  105    NYD2_ENTER;
  106 
  107    argv = vp;
  108    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *argv++ : NULL;
  109    sp = n_string_reserve(n_string_creat_auto(&s), 121/* XXX */);
  110 #ifdef HAVE_ERRORS
  111    doerr = (fp == n_stderr &&  (n_psonce & n_PSO_INTERACTIVE));
  112 #else
  113    doerr = FAL0;
  114 #endif
  115 
  116    for(ap = argv; *ap != NULL; ++ap){
  117       if(ap != argv)
  118          sp = n_string_push_c(sp, ' ');
  119       if((cp = fexpand(*ap, FEXP_NSHORTCUT | FEXP_NVAR)) == NULL)
  120          cp = *ap;
  121       sp = n_string_push_cp(sp, cp);
  122    }
  123    if(donl)
  124       sp = n_string_push_c(sp, '\n');
  125    cp = n_string_cp(sp);
  126 
  127    if(varname == NULL){
  128       si32_t e;
  129 
  130       e = n_ERR_NONE;
  131       if(doerr)
  132          n_err("%s", cp);
  133       else if(fputs(cp, fp) == EOF)
  134          e = n_err_no;
  135       if((rv = (fflush(fp) == EOF)))
  136          e = n_err_no;
  137       rv |= ferror(fp) ? 1 : 0;
  138       n_pstate_err_no = e;
  139    }else if(!n_var_vset(varname, (uintptr_t)cp)){
  140       n_pstate_err_no = n_ERR_NOTSUP;
  141       rv = -1;
  142    }else{
  143       n_pstate_err_no = n_ERR_NONE;
  144       rv = (int)sp->s_len;
  145    }
  146    NYD2_LEAVE;
  147    return rv;
  148 }
  149 
  150 static bool_t
  151 a_cmisc_read_set(char const *cp, char const *value){
  152    bool_t rv;
  153    NYD2_ENTER;
  154 
  155    if(!n_shexp_is_valid_varname(cp))
  156       value = N_("not a valid variable name");
  157    else if(!n_var_is_user_writable(cp))
  158       value = N_("variable is read-only");
  159    else if(!n_var_vset(cp, (uintptr_t)value))
  160       value = N_("failed to update variable value");
  161    else{
  162       rv = TRU1;
  163       goto jleave;
  164    }
  165    n_err("`read': %s: %s\n", V_(value), n_shexp_quote_cp(cp, FAL0));
  166    rv = FAL0;
  167 jleave:
  168    NYD2_LEAVE;
  169    return rv;
  170 }
  171 
  172 static int
  173 a_cmisc_version_cmp(void const *s1, void const *s2){
  174    char const * const *cp1, * const *cp2;
  175    int rv;
  176    NYD2_ENTER;
  177 
  178    cp1 = s1;
  179    cp2 = s2;
  180    rv = strcmp(&(*cp1)[1], &(*cp2)[1]);
  181    NYD2_LEAVE;
  182    return rv;
  183 }
  184 
  185 FL int
  186 c_sleep(void *v){
  187    uiz_t sec, msec;
  188    char **argv;
  189    NYD_ENTER;
  190 
  191    argv = v;
  192 
  193    if((n_idec_uiz_cp(&sec, argv[0], 0, NULL) &
  194          (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  195          ) != n_IDEC_STATE_CONSUMED)
  196       goto jesyn;
  197 
  198    if(argv[1] == NULL)
  199       msec = 0;
  200    else if((n_idec_uiz_cp(&msec, argv[1], 0, NULL) &
  201          (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  202          ) != n_IDEC_STATE_CONSUMED)
  203       goto jesyn;
  204 
  205    if(UIZ_MAX / n_DATE_MILLISSEC < sec)
  206       goto jeover;
  207    sec *= n_DATE_MILLISSEC;
  208 
  209    if(UIZ_MAX - sec < msec)
  210       goto jeover;
  211    msec += sec;
  212 
  213    n_pstate_err_no = (n_msleep(msec, (argv[2] == NULL)) > 0)
  214          ? n_ERR_INTR : n_ERR_NONE;
  215 jleave:
  216    NYD_LEAVE;
  217    return (argv == NULL);
  218 jeover:
  219    n_err(_("`sleep': argument(s) overflow(s) datatype\n"));
  220    n_pstate_err_no = n_ERR_OVERFLOW;
  221    argv = NULL;
  222    goto jleave;
  223 jesyn:
  224    n_err(_("Synopsis: sleep: <seconds> [<milliseconds>] [uninterruptible]\n"));
  225    n_pstate_err_no = n_ERR_INVAL;
  226    argv = NULL;
  227    goto jleave;
  228 }
  229 
  230 FL int
  231 c_shell(void *v)
  232 {
  233    sigset_t mask;
  234    int rv;
  235    FILE *fp;
  236    char const **argv, *varname, *varres, *cp;
  237    NYD_ENTER;
  238 
  239    n_pstate_err_no = n_ERR_NONE;
  240    argv = v;
  241    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *argv++ : NULL;
  242    varres = n_empty;
  243    fp = NULL;
  244 
  245    if(varname != NULL &&
  246          (fp = Ftmp(NULL, "shell", OF_RDWR | OF_UNLINK | OF_REGISTER)
  247             ) == NULL){
  248       n_pstate_err_no = n_ERR_CANCELED;
  249       rv = -1;
  250    }else{
  251       cp = a_cmisc_bangexp(*argv);
  252 
  253       sigemptyset(&mask);
  254       if(n_child_run(ok_vlook(SHELL), &mask,
  255             n_CHILD_FD_PASS, (fp != NULL ? fileno(fp) : n_CHILD_FD_PASS),
  256             "-c", cp, NULL, NULL, &rv) < 0){
  257          n_pstate_err_no = n_err_no;
  258          rv = -1;
  259       }else{
  260          rv = WEXITSTATUS(rv);
  261 
  262          if(fp != NULL){
  263             int c;
  264             char *x;
  265             off_t l;
  266 
  267             fflush_rewind(fp);
  268             l = fsize(fp);
  269             if(UICMP(64, l, >=, UIZ_MAX -42)){
  270                n_pstate_err_no = n_ERR_NOMEM;
  271                varres = n_empty;
  272             }else{
  273                varres = x = n_autorec_alloc(l +1);
  274 
  275                for(; l > 0 && (c = getc(fp)) != EOF; --l)
  276                   *x++ = c;
  277                *x++ = '\0';
  278                if(l != 0){
  279                   n_pstate_err_no = n_err_no;
  280                   varres = n_empty; /* xxx hmmm */
  281                }
  282             }
  283          }
  284       }
  285    }
  286 
  287    if(fp != NULL)
  288       Fclose(fp);
  289 
  290    if(varname != NULL){
  291       if(!n_var_vset(varname, (uintptr_t)varres)){
  292          n_pstate_err_no = n_ERR_NOTSUP;
  293          rv = -1;
  294       }
  295    }else if(rv >= 0 && (n_psonce & n_PSO_INTERACTIVE)){
  296       fprintf(n_stdout, "!\n");
  297       /* Line buffered fflush(n_stdout); */
  298    }
  299    NYD_LEAVE;
  300    return rv;
  301 }
  302 
  303 FL int
  304 c_dosh(void *v)
  305 {
  306    int rv;
  307    NYD_ENTER;
  308    n_UNUSED(v);
  309 
  310    if(n_child_run(ok_vlook(SHELL), 0, n_CHILD_FD_PASS, n_CHILD_FD_PASS, NULL,
  311          NULL, NULL, NULL, &rv) < 0){
  312       n_pstate_err_no = n_err_no;
  313       rv = -1;
  314    }else{
  315       putc('\n', n_stdout);
  316       /* Line buffered fflush(n_stdout); */
  317       n_pstate_err_no = n_ERR_NONE;
  318       rv = WEXITSTATUS(rv);
  319    }
  320    NYD_LEAVE;
  321    return rv;
  322 }
  323 
  324 FL int
  325 c_cwd(void *v){
  326    struct n_string s_b, *sp;
  327    size_t l;
  328    char const *varname;
  329    NYD_ENTER;
  330 
  331    sp = n_string_creat_auto(&s_b);
  332    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *(char const**)v : NULL;
  333    l = PATH_MAX;
  334 
  335    for(;; l += PATH_MAX){
  336       sp = n_string_resize(n_string_trunc(sp, 0), l);
  337 
  338       if(getcwd(sp->s_dat, sp->s_len) == NULL){
  339          int e;
  340 
  341          e = n_err_no;
  342          if(e == n_ERR_RANGE)
  343             continue;
  344          n_perr(_("Failed to getcwd(3)"), e);
  345          v = NULL;
  346          break;
  347       }
  348 
  349       if(varname != NULL){
  350          if(!n_var_vset(varname, (uintptr_t)sp->s_dat))
  351             v = NULL;
  352       }else{
  353          l = strlen(sp->s_dat);
  354          sp = n_string_trunc(sp, l);
  355          if(fwrite(sp->s_dat, 1, sp->s_len, n_stdout) == sp->s_len &&
  356                putc('\n', n_stdout) == EOF)
  357             v = NULL;
  358       }
  359       break;
  360    }
  361    NYD_LEAVE;
  362    return (v == NULL);
  363 }
  364 
  365 FL int
  366 c_chdir(void *v)
  367 {
  368    char **arglist = v;
  369    char const *cp;
  370    NYD_ENTER;
  371 
  372    if (*arglist == NULL)
  373       cp = ok_vlook(HOME);
  374    else if ((cp = fexpand(*arglist, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
  375       goto jleave;
  376    if (chdir(cp) == -1) {
  377       n_perr(cp, 0);
  378       cp = NULL;
  379    }
  380 jleave:
  381    NYD_LEAVE;
  382    return (cp == NULL);
  383 }
  384 
  385 FL int
  386 c_echo(void *v){
  387    int rv;
  388    NYD_ENTER;
  389 
  390    rv = a_cmisc_echo(v, n_stdout, TRU1);
  391    NYD_LEAVE;
  392    return rv;
  393 }
  394 
  395 FL int
  396 c_echoerr(void *v){
  397    int rv;
  398    NYD_ENTER;
  399 
  400    rv = a_cmisc_echo(v, n_stderr, TRU1);
  401    NYD_LEAVE;
  402    return rv;
  403 }
  404 
  405 FL int
  406 c_echon(void *v){
  407    int rv;
  408    NYD_ENTER;
  409 
  410    rv = a_cmisc_echo(v, n_stdout, FAL0);
  411    NYD_LEAVE;
  412    return rv;
  413 }
  414 
  415 FL int
  416 c_echoerrn(void *v){
  417    int rv;
  418    NYD_ENTER;
  419 
  420    rv = a_cmisc_echo(v, n_stderr, FAL0);
  421    NYD_LEAVE;
  422    return rv;
  423 }
  424 
  425 FL int
  426 c_read(void * volatile vp){
  427    struct n_sigman sm;
  428    struct str trim;
  429    struct n_string s, *sp;
  430    char *linebuf;
  431    size_t linesize, i;
  432    int rv;
  433    char const *ifs, **argv, *cp;
  434    NYD2_ENTER;
  435 
  436    sp = n_string_creat_auto(&s);
  437    sp = n_string_reserve(sp, 64 -1);
  438 
  439    ifs = ok_vlook(ifs);
  440    linesize = 0;
  441    linebuf = NULL;
  442    argv = vp;
  443 
  444    n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL){
  445    case 0:
  446       break;
  447    default:
  448       n_pstate_err_no = n_ERR_INTR;
  449       rv = -1;
  450       goto jleave;
  451    }
  452 
  453    n_pstate_err_no = n_ERR_NONE;
  454    rv = n_go_input(((n_pstate & n_PS_COMPOSE_MODE
  455             ? n_GO_INPUT_CTX_COMPOSE : n_GO_INPUT_CTX_DEFAULT) |
  456          n_GO_INPUT_FORCE_STDIN | n_GO_INPUT_NL_ESC |
  457          n_GO_INPUT_PROMPT_NONE /* XXX POSIX: PS2: yes! */),
  458          NULL, &linebuf, &linesize, NULL, NULL);
  459    if(rv < 0){
  460       if(!n_go_input_is_eof())
  461          n_pstate_err_no = n_ERR_BADF;
  462       goto jleave;
  463    }else if(rv == 0){
  464       if(n_go_input_is_eof()){
  465          rv = -1;
  466          goto jleave;
  467       }
  468    }else{
  469       trim.s = linebuf;
  470       trim.l = rv;
  471 
  472       for(; *argv != NULL; ++argv){
  473          if(trim.l == 0 || n_str_trim_ifs(&trim, FAL0)->l == 0)
  474             break;
  475 
  476          /* The last variable gets the remaining line less trailing IFS-WS */
  477          if(argv[1] == NULL){
  478 jitall:
  479             sp = n_string_assign_buf(sp, trim.s, trim.l);
  480             trim.l = 0;
  481          }else for(cp = trim.s, i = 1;; ++cp, ++i){
  482             if(strchr(ifs, *cp) != NULL){
  483                sp = n_string_assign_buf(sp, trim.s, i - 1);
  484                trim.s += i;
  485                trim.l -= i;
  486                break;
  487             }
  488             if(i == trim.l)
  489                goto jitall;
  490          }
  491 
  492          if(!a_cmisc_read_set(*argv, n_string_cp(sp))){
  493             n_pstate_err_no = n_ERR_NOTSUP;
  494             rv = -1;
  495             break;
  496          }
  497       }
  498    }
  499 
  500    /* Set the remains to the empty string */
  501    for(; *argv != NULL; ++argv)
  502       if(!a_cmisc_read_set(*argv, n_empty)){
  503          n_pstate_err_no = n_ERR_NOTSUP;
  504          rv = -1;
  505          break;
  506       }
  507 
  508    n_sigman_cleanup_ping(&sm);
  509 jleave:
  510    if(linebuf != NULL)
  511       n_free(linebuf);
  512    NYD2_LEAVE;
  513    n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
  514    return rv;
  515 }
  516 
  517 FL int
  518 c_readall(void * vp){ /* TODO 64-bit retval */
  519    struct n_sigman sm;
  520    struct n_string s, *sp;
  521    char *linebuf;
  522    size_t linesize;
  523    int rv;
  524    char const **argv;
  525    NYD2_ENTER;
  526 
  527    sp = n_string_creat_auto(&s);
  528    sp = n_string_reserve(sp, 64 -1);
  529 
  530    linesize = 0;
  531    linebuf = NULL;
  532    argv = vp;
  533 
  534    n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL){
  535    case 0:
  536       break;
  537    default:
  538       n_pstate_err_no = n_ERR_INTR;
  539       rv = -1;
  540       goto jleave;
  541    }
  542 
  543    n_pstate_err_no = n_ERR_NONE;
  544 
  545    for(;;){
  546       rv = n_go_input(((n_pstate & n_PS_COMPOSE_MODE
  547                ? n_GO_INPUT_CTX_COMPOSE : n_GO_INPUT_CTX_DEFAULT) |
  548             n_GO_INPUT_FORCE_STDIN | /*n_GO_INPUT_NL_ESC |*/
  549             n_GO_INPUT_PROMPT_NONE),
  550             NULL, &linebuf, &linesize, NULL, NULL);
  551       if(rv < 0){
  552          if(!n_go_input_is_eof()){
  553             n_pstate_err_no = n_ERR_BADF;
  554             goto jleave;
  555          }
  556          if(sp->s_len == 0)
  557             goto jleave;
  558          break;
  559       }else if(rv == 0){ /* xxx will not get*/
  560          if(n_go_input_is_eof()){
  561             if(sp->s_len == 0){
  562                rv = -1;
  563                goto jleave;
  564             }
  565             break;
  566          }
  567       }else if(UICMP(32, SI32_MAX - sp->s_len, <=, rv)){
  568          n_pstate_err_no = n_ERR_OVERFLOW;
  569          rv = -1;
  570          goto jleave;
  571       }else{
  572          sp = n_string_push_buf(sp, linebuf, rv);
  573          if(n_pstate & n_PS_READLINE_NL)
  574             sp = n_string_push_c(sp, '\n');
  575       }
  576    }
  577 
  578    if(!a_cmisc_read_set(argv[0], n_string_cp(sp))){
  579       n_pstate_err_no = n_ERR_NOTSUP;
  580       rv = -1;
  581       goto jleave;
  582    }
  583    rv = sp->s_len;
  584 
  585    n_sigman_cleanup_ping(&sm);
  586 jleave:
  587    if(linebuf != NULL)
  588       n_free(linebuf);
  589    NYD2_LEAVE;
  590    n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
  591    return rv;
  592 }
  593 
  594 FL int
  595 c_version(void *vp){
  596    int longest, rv;
  597    char *iop;
  598    char const *cp, **arr;
  599    size_t i, i2;
  600    NYD_ENTER;
  601    n_UNUSED(vp);
  602 
  603    fprintf(n_stdout,
  604       _("%s %s, %s (%s)\nFeatures included (+) or not (-)\n"),
  605       n_uagent, ok_vlook(version), ok_vlook(version_date),
  606       ok_vlook(build_osenv));
  607 
  608    /* *features* starts with dummy byte to avoid + -> *folder* expansions */
  609    i = strlen(cp = &ok_vlook(features)[1]) +1;
  610    iop = n_autorec_alloc(i);
  611    memcpy(iop, cp, i);
  612 
  613    arr = n_autorec_alloc(sizeof(cp) * VAL_FEATURES_CNT);
  614    for(longest = 0, i = 0; (cp = n_strsep(&iop, ',', TRU1)) != NULL; ++i){
  615       arr[i] = cp;
  616       i2 = strlen(cp);
  617       longest = n_MAX(longest, (int)i2);
  618    }
  619    qsort(arr, i, sizeof(cp), &a_cmisc_version_cmp);
  620 
  621    /* We use aligned columns, so don't use n_SCRNWIDTH_FOR_LISTS */
  622    for(++longest, i2 = 0; i-- > 0;){
  623       cp = *(arr++);
  624       fprintf(n_stdout, "%-*s ", longest, cp);
  625       i2 += longest;
  626       if(UICMP(z, ++i2 + longest, >=, n_scrnwidth) || i == 0){
  627          i2 = 0;
  628          putc('\n', n_stdout);
  629       }
  630    }
  631 
  632    if((rv = ferror(n_stdout) != 0))
  633       clearerr(n_stdout);
  634    NYD_LEAVE;
  635    return rv;
  636 }
  637 
  638 /* s-it-mode */