"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/cmd-misc.c" (25 Mar 2018, 16598 Bytes) of package /linux/misc/s-nail-14.9.10.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 last Fossies "Diffs" side-by-side code changes report: 14.9.7_vs_14.9.8.

    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 #include <sys/utsname.h>
   43 
   44 /* Expand the shell escape by expanding unescaped !'s into the last issued
   45  * command where possible */
   46 static char const *a_cmisc_bangexp(char const *cp);
   47 
   48 /* c_n?echo(), c_n?echoerr() */
   49 static int a_cmisc_echo(void *vp, FILE *fp, bool_t donl);
   50 
   51 /* c_read() */
   52 static bool_t a_cmisc_read_set(char const *cp, char const *value);
   53 
   54 /* c_version() */
   55 static int a_cmisc_version_cmp(void const *s1, void const *s2);
   56 
   57 static char const *
   58 a_cmisc_bangexp(char const *cp){
   59    static struct str last_bang;
   60 
   61    struct n_string xbang, *bang;
   62    char c;
   63    bool_t changed;
   64    NYD_ENTER;
   65 
   66    if(!ok_blook(bang))
   67       goto jleave;
   68 
   69    changed = FAL0;
   70 
   71    for(bang = n_string_creat(&xbang); (c = *cp++) != '\0';){
   72       if(c == '!'){
   73          if(last_bang.l > 0)
   74             bang = n_string_push_buf(bang, last_bang.s, last_bang.l);
   75          changed = TRU1;
   76       }else{
   77          if(c == '\\' && *cp == '!'){
   78             ++cp;
   79             c = '!';
   80             changed = TRU1;
   81          }
   82          bang = n_string_push_c(bang, c);
   83       }
   84    }
   85 
   86    if(last_bang.s != NULL)
   87       free(last_bang.s);
   88    last_bang.s = n_string_cp(bang);
   89    last_bang.l = bang->s_len;
   90    bang = n_string_drop_ownership(bang);
   91    n_string_gut(bang);
   92 
   93    cp = last_bang.s;
   94    if(changed)
   95       fprintf(n_stdout, "!%s\n", cp);
   96 jleave:
   97    NYD_LEAVE;
   98    return cp;
   99 }
  100 
  101 static int
  102 a_cmisc_echo(void *vp, FILE *fp, bool_t donl){
  103    struct n_string s, *sp;
  104    int rv;
  105    bool_t doerr;
  106    char const **argv, *varname, **ap, *cp;
  107    NYD2_ENTER;
  108 
  109    argv = vp;
  110    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *argv++ : NULL;
  111    sp = n_string_reserve(n_string_creat_auto(&s), 121/* XXX */);
  112 #ifdef HAVE_ERRORS
  113    doerr = (fp == n_stderr &&  (n_psonce & n_PSO_INTERACTIVE));
  114 #else
  115    doerr = FAL0;
  116 #endif
  117 
  118    for(ap = argv; *ap != NULL; ++ap){
  119       if(ap != argv)
  120          sp = n_string_push_c(sp, ' ');
  121       if((cp = fexpand(*ap, FEXP_NSHORTCUT | FEXP_NVAR)) == NULL)
  122          cp = *ap;
  123       sp = n_string_push_cp(sp, cp);
  124    }
  125    if(donl)
  126       sp = n_string_push_c(sp, '\n');
  127    cp = n_string_cp(sp);
  128 
  129    if(varname == NULL){
  130       si32_t e;
  131 
  132       e = n_ERR_NONE;
  133       if(doerr)
  134          n_err("%s", cp);
  135       else if(fputs(cp, fp) == EOF)
  136          e = n_err_no;
  137       if((rv = (fflush(fp) == EOF)))
  138          e = n_err_no;
  139       rv |= ferror(fp) ? 1 : 0;
  140       n_pstate_err_no = e;
  141    }else if(!n_var_vset(varname, (uintptr_t)cp)){
  142       n_pstate_err_no = n_ERR_NOTSUP;
  143       rv = -1;
  144    }else{
  145       n_pstate_err_no = n_ERR_NONE;
  146       rv = (int)sp->s_len;
  147    }
  148    NYD2_LEAVE;
  149    return rv;
  150 }
  151 
  152 static bool_t
  153 a_cmisc_read_set(char const *cp, char const *value){
  154    bool_t rv;
  155    NYD2_ENTER;
  156 
  157    if(!n_shexp_is_valid_varname(cp))
  158       value = N_("not a valid variable name");
  159    else if(!n_var_is_user_writable(cp))
  160       value = N_("variable is read-only");
  161    else if(!n_var_vset(cp, (uintptr_t)value))
  162       value = N_("failed to update variable value");
  163    else{
  164       rv = TRU1;
  165       goto jleave;
  166    }
  167    n_err("`read': %s: %s\n", V_(value), n_shexp_quote_cp(cp, FAL0));
  168    rv = FAL0;
  169 jleave:
  170    NYD2_LEAVE;
  171    return rv;
  172 }
  173 
  174 static int
  175 a_cmisc_version_cmp(void const *s1, void const *s2){
  176    char const * const *cp1, * const *cp2;
  177    int rv;
  178    NYD2_ENTER;
  179 
  180    cp1 = s1;
  181    cp2 = s2;
  182    rv = strcmp(&(*cp1)[1], &(*cp2)[1]);
  183    NYD2_LEAVE;
  184    return rv;
  185 }
  186 
  187 FL int
  188 c_sleep(void *v){
  189    uiz_t sec, msec;
  190    char **argv;
  191    NYD_ENTER;
  192 
  193    argv = v;
  194 
  195    if((n_idec_uiz_cp(&sec, argv[0], 0, NULL) &
  196          (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  197          ) != n_IDEC_STATE_CONSUMED)
  198       goto jesyn;
  199 
  200    if(argv[1] == NULL)
  201       msec = 0;
  202    else if((n_idec_uiz_cp(&msec, argv[1], 0, NULL) &
  203          (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  204          ) != n_IDEC_STATE_CONSUMED)
  205       goto jesyn;
  206 
  207    if(UIZ_MAX / n_DATE_MILLISSEC < sec)
  208       goto jeover;
  209    sec *= n_DATE_MILLISSEC;
  210 
  211    if(UIZ_MAX - sec < msec)
  212       goto jeover;
  213    msec += sec;
  214 
  215    n_pstate_err_no = (n_msleep(msec, (argv[2] == NULL)) > 0)
  216          ? n_ERR_INTR : n_ERR_NONE;
  217 jleave:
  218    NYD_LEAVE;
  219    return (argv == NULL);
  220 jeover:
  221    n_err(_("`sleep': argument(s) overflow(s) datatype\n"));
  222    n_pstate_err_no = n_ERR_OVERFLOW;
  223    argv = NULL;
  224    goto jleave;
  225 jesyn:
  226    n_err(_("Synopsis: sleep: <seconds> [<milliseconds>] [uninterruptible]\n"));
  227    n_pstate_err_no = n_ERR_INVAL;
  228    argv = NULL;
  229    goto jleave;
  230 }
  231 
  232 FL int
  233 c_shell(void *v)
  234 {
  235    sigset_t mask;
  236    int rv;
  237    FILE *fp;
  238    char const **argv, *varname, *varres, *cp;
  239    NYD_ENTER;
  240 
  241    n_pstate_err_no = n_ERR_NONE;
  242    argv = v;
  243    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *argv++ : NULL;
  244    varres = n_empty;
  245    fp = NULL;
  246 
  247    if(varname != NULL &&
  248          (fp = Ftmp(NULL, "shell", OF_RDWR | OF_UNLINK | OF_REGISTER)
  249             ) == NULL){
  250       n_pstate_err_no = n_ERR_CANCELED;
  251       rv = -1;
  252    }else{
  253       cp = a_cmisc_bangexp(*argv);
  254 
  255       sigemptyset(&mask);
  256       if(n_child_run(ok_vlook(SHELL), &mask,
  257             n_CHILD_FD_PASS, (fp != NULL ? fileno(fp) : n_CHILD_FD_PASS),
  258             "-c", cp, NULL, NULL, &rv) < 0){
  259          n_pstate_err_no = n_err_no;
  260          rv = -1;
  261       }else{
  262          rv = WEXITSTATUS(rv);
  263 
  264          if(fp != NULL){
  265             int c;
  266             char *x;
  267             off_t l;
  268 
  269             fflush_rewind(fp);
  270             l = fsize(fp);
  271             if(UICMP(64, l, >=, UIZ_MAX -42)){
  272                n_pstate_err_no = n_ERR_NOMEM;
  273                varres = n_empty;
  274             }else{
  275                varres = x = n_autorec_alloc(l +1);
  276 
  277                for(; l > 0 && (c = getc(fp)) != EOF; --l)
  278                   *x++ = c;
  279                *x++ = '\0';
  280                if(l != 0){
  281                   n_pstate_err_no = n_err_no;
  282                   varres = n_empty; /* xxx hmmm */
  283                }
  284             }
  285          }
  286       }
  287    }
  288 
  289    if(fp != NULL)
  290       Fclose(fp);
  291 
  292    if(varname != NULL){
  293       if(!n_var_vset(varname, (uintptr_t)varres)){
  294          n_pstate_err_no = n_ERR_NOTSUP;
  295          rv = -1;
  296       }
  297    }else if(rv >= 0 && (n_psonce & n_PSO_INTERACTIVE)){
  298       fprintf(n_stdout, "!\n");
  299       /* Line buffered fflush(n_stdout); */
  300    }
  301    NYD_LEAVE;
  302    return rv;
  303 }
  304 
  305 FL int
  306 c_dosh(void *v)
  307 {
  308    int rv;
  309    NYD_ENTER;
  310    n_UNUSED(v);
  311 
  312    if(n_child_run(ok_vlook(SHELL), 0, n_CHILD_FD_PASS, n_CHILD_FD_PASS, NULL,
  313          NULL, NULL, NULL, &rv) < 0){
  314       n_pstate_err_no = n_err_no;
  315       rv = -1;
  316    }else{
  317       putc('\n', n_stdout);
  318       /* Line buffered fflush(n_stdout); */
  319       n_pstate_err_no = n_ERR_NONE;
  320       rv = WEXITSTATUS(rv);
  321    }
  322    NYD_LEAVE;
  323    return rv;
  324 }
  325 
  326 FL int
  327 c_cwd(void *v){
  328    struct n_string s_b, *sp;
  329    size_t l;
  330    char const *varname;
  331    NYD_ENTER;
  332 
  333    sp = n_string_creat_auto(&s_b);
  334    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *(char const**)v : NULL;
  335    l = PATH_MAX;
  336 
  337    for(;; l += PATH_MAX){
  338       sp = n_string_resize(n_string_trunc(sp, 0), l);
  339 
  340       if(getcwd(sp->s_dat, sp->s_len) == NULL){
  341          int e;
  342 
  343          e = n_err_no;
  344          if(e == n_ERR_RANGE)
  345             continue;
  346          n_perr(_("Failed to getcwd(3)"), e);
  347          v = NULL;
  348          break;
  349       }
  350 
  351       if(varname != NULL){
  352          if(!n_var_vset(varname, (uintptr_t)sp->s_dat))
  353             v = NULL;
  354       }else{
  355          l = strlen(sp->s_dat);
  356          sp = n_string_trunc(sp, l);
  357          if(fwrite(sp->s_dat, 1, sp->s_len, n_stdout) == sp->s_len &&
  358                putc('\n', n_stdout) == EOF)
  359             v = NULL;
  360       }
  361       break;
  362    }
  363    NYD_LEAVE;
  364    return (v == NULL);
  365 }
  366 
  367 FL int
  368 c_chdir(void *v)
  369 {
  370    char **arglist = v;
  371    char const *cp;
  372    NYD_ENTER;
  373 
  374    if (*arglist == NULL)
  375       cp = ok_vlook(HOME);
  376    else if ((cp = fexpand(*arglist, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
  377       goto jleave;
  378    if (chdir(cp) == -1) {
  379       n_perr(cp, 0);
  380       cp = NULL;
  381    }
  382 jleave:
  383    NYD_LEAVE;
  384    return (cp == NULL);
  385 }
  386 
  387 FL int
  388 c_echo(void *v){
  389    int rv;
  390    NYD_ENTER;
  391 
  392    rv = a_cmisc_echo(v, n_stdout, TRU1);
  393    NYD_LEAVE;
  394    return rv;
  395 }
  396 
  397 FL int
  398 c_echoerr(void *v){
  399    int rv;
  400    NYD_ENTER;
  401 
  402    rv = a_cmisc_echo(v, n_stderr, TRU1);
  403    NYD_LEAVE;
  404    return rv;
  405 }
  406 
  407 FL int
  408 c_echon(void *v){
  409    int rv;
  410    NYD_ENTER;
  411 
  412    rv = a_cmisc_echo(v, n_stdout, FAL0);
  413    NYD_LEAVE;
  414    return rv;
  415 }
  416 
  417 FL int
  418 c_echoerrn(void *v){
  419    int rv;
  420    NYD_ENTER;
  421 
  422    rv = a_cmisc_echo(v, n_stderr, FAL0);
  423    NYD_LEAVE;
  424    return rv;
  425 }
  426 
  427 FL int
  428 c_read(void * volatile vp){
  429    struct n_sigman sm;
  430    struct str trim;
  431    struct n_string s, *sp;
  432    char *linebuf;
  433    size_t linesize, i;
  434    int rv;
  435    char const *ifs, **argv, *cp;
  436    NYD2_ENTER;
  437 
  438    sp = n_string_creat_auto(&s);
  439    sp = n_string_reserve(sp, 64 -1);
  440 
  441    ifs = ok_vlook(ifs);
  442    linesize = 0;
  443    linebuf = NULL;
  444    argv = vp;
  445 
  446    n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL){
  447    case 0:
  448       break;
  449    default:
  450       n_pstate_err_no = n_ERR_INTR;
  451       rv = -1;
  452       goto jleave;
  453    }
  454 
  455    n_pstate_err_no = n_ERR_NONE;
  456    rv = n_go_input(((n_pstate & n_PS_COMPOSE_MODE
  457             ? n_GO_INPUT_CTX_COMPOSE : n_GO_INPUT_CTX_DEFAULT) |
  458          n_GO_INPUT_FORCE_STDIN | n_GO_INPUT_NL_ESC |
  459          n_GO_INPUT_PROMPT_NONE /* XXX POSIX: PS2: yes! */),
  460          NULL, &linebuf, &linesize, NULL, NULL);
  461    if(rv < 0){
  462       if(!n_go_input_is_eof())
  463          n_pstate_err_no = n_ERR_BADF;
  464       goto jleave;
  465    }else if(rv == 0){
  466       if(n_go_input_is_eof()){
  467          rv = -1;
  468          goto jleave;
  469       }
  470    }else{
  471       trim.s = linebuf;
  472       trim.l = rv;
  473 
  474       for(; *argv != NULL; ++argv){
  475          if(trim.l == 0 || n_str_trim_ifs(&trim, FAL0)->l == 0)
  476             break;
  477 
  478          /* The last variable gets the remaining line less trailing IFS-WS */
  479          if(argv[1] == NULL){
  480 jitall:
  481             sp = n_string_assign_buf(sp, trim.s, trim.l);
  482             trim.l = 0;
  483          }else for(cp = trim.s, i = 1;; ++cp, ++i){
  484             if(strchr(ifs, *cp) != NULL){
  485                sp = n_string_assign_buf(sp, trim.s, i - 1);
  486                trim.s += i;
  487                trim.l -= i;
  488                break;
  489             }
  490             if(i == trim.l)
  491                goto jitall;
  492          }
  493 
  494          if(!a_cmisc_read_set(*argv, n_string_cp(sp))){
  495             n_pstate_err_no = n_ERR_NOTSUP;
  496             rv = -1;
  497             break;
  498          }
  499       }
  500    }
  501 
  502    /* Set the remains to the empty string */
  503    for(; *argv != NULL; ++argv)
  504       if(!a_cmisc_read_set(*argv, n_empty)){
  505          n_pstate_err_no = n_ERR_NOTSUP;
  506          rv = -1;
  507          break;
  508       }
  509 
  510    n_sigman_cleanup_ping(&sm);
  511 jleave:
  512    if(linebuf != NULL)
  513       n_free(linebuf);
  514    NYD2_LEAVE;
  515    n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
  516    return rv;
  517 }
  518 
  519 FL int
  520 c_readall(void * vp){ /* TODO 64-bit retval */
  521    struct n_sigman sm;
  522    struct n_string s, *sp;
  523    char *linebuf;
  524    size_t linesize;
  525    int rv;
  526    char const **argv;
  527    NYD2_ENTER;
  528 
  529    sp = n_string_creat_auto(&s);
  530    sp = n_string_reserve(sp, 64 -1);
  531 
  532    linesize = 0;
  533    linebuf = NULL;
  534    argv = vp;
  535 
  536    n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL){
  537    case 0:
  538       break;
  539    default:
  540       n_pstate_err_no = n_ERR_INTR;
  541       rv = -1;
  542       goto jleave;
  543    }
  544 
  545    n_pstate_err_no = n_ERR_NONE;
  546 
  547    for(;;){
  548       rv = n_go_input(((n_pstate & n_PS_COMPOSE_MODE
  549                ? n_GO_INPUT_CTX_COMPOSE : n_GO_INPUT_CTX_DEFAULT) |
  550             n_GO_INPUT_FORCE_STDIN | /*n_GO_INPUT_NL_ESC |*/
  551             n_GO_INPUT_PROMPT_NONE),
  552             NULL, &linebuf, &linesize, NULL, NULL);
  553       if(rv < 0){
  554          if(!n_go_input_is_eof()){
  555             n_pstate_err_no = n_ERR_BADF;
  556             goto jleave;
  557          }
  558          if(sp->s_len == 0)
  559             goto jleave;
  560          break;
  561       }else if(rv == 0){ /* xxx will not get*/
  562          if(n_go_input_is_eof()){
  563             if(sp->s_len == 0){
  564                rv = -1;
  565                goto jleave;
  566             }
  567             break;
  568          }
  569       }else if(UICMP(32, SI32_MAX - sp->s_len, <=, rv)){
  570          n_pstate_err_no = n_ERR_OVERFLOW;
  571          rv = -1;
  572          goto jleave;
  573       }else{
  574          sp = n_string_push_buf(sp, linebuf, rv);
  575          if(n_pstate & n_PS_READLINE_NL)
  576             sp = n_string_push_c(sp, '\n');
  577       }
  578    }
  579 
  580    if(!a_cmisc_read_set(argv[0], n_string_cp(sp))){
  581       n_pstate_err_no = n_ERR_NOTSUP;
  582       rv = -1;
  583       goto jleave;
  584    }
  585    rv = sp->s_len;
  586 
  587    n_sigman_cleanup_ping(&sm);
  588 jleave:
  589    if(linebuf != NULL)
  590       n_free(linebuf);
  591    NYD2_LEAVE;
  592    n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
  593    return rv;
  594 }
  595 
  596 FL int
  597 c_version(void *vp){
  598    struct utsname ut;
  599    struct n_string s, *sp = &s;
  600    int rv;
  601    char *iop;
  602    char const *cp, **arr;
  603    size_t i, lnlen, j;
  604    NYD_ENTER;
  605 
  606    sp = n_string_creat_auto(sp);
  607    sp = n_string_book(sp, 1024);
  608 
  609    /* First line */
  610    sp = n_string_push_cp(sp, n_uagent);
  611    sp = n_string_push_c(sp, ' ');
  612    sp = n_string_push_cp(sp, ok_vlook(version));
  613    sp = n_string_push_c(sp, ',');
  614    sp = n_string_push_c(sp, ' ');
  615    sp = n_string_push_cp(sp, ok_vlook(version_date));
  616    sp = n_string_push_c(sp, ' ');
  617    sp = n_string_push_c(sp, '(');
  618    sp = n_string_push_cp(sp, _("build on "));
  619    sp = n_string_push_cp(sp, ok_vlook(build_osenv));
  620    sp = n_string_push_c(sp, ')');
  621    sp = n_string_push_cp(sp, _("\nFeatures included (+) or not (-)\n"));
  622 
  623    /* Some lines with the features.
  624     * *features* starts with dummy byte to avoid + -> *folder* expansions */
  625    i = strlen(cp = &ok_vlook(features)[1]) +1;
  626    iop = n_autorec_alloc(i);
  627    memcpy(iop, cp, i);
  628 
  629    arr = n_autorec_alloc(sizeof(cp) * VAL_FEATURES_CNT);
  630    for(i = 0; (cp = n_strsep(&iop, ',', TRU1)) != NULL; ++i)
  631       arr[i] = cp;
  632    qsort(arr, i, sizeof(cp), &a_cmisc_version_cmp);
  633 
  634    for(lnlen = 0; i-- > 0;){
  635       cp = *(arr++);
  636       j = strlen(cp);
  637 
  638       if((lnlen += j + 1) > 72){
  639          sp = n_string_push_c(sp, '\n');
  640          lnlen = j + 1;
  641       }
  642       sp = n_string_push_c(sp, ' ');
  643       sp = n_string_push_buf(sp, cp, j);
  644    }
  645    sp = n_string_push_c(sp, '\n');
  646 
  647    /* Trailing line with info of running machine */
  648    uname(&ut);
  649    sp = n_string_push_c(sp, '@');
  650    sp = n_string_push_cp(sp, ut.sysname);
  651    sp = n_string_push_c(sp, ' ');
  652    sp = n_string_push_cp(sp, ut.release);
  653    sp = n_string_push_c(sp, ' ');
  654    sp = n_string_push_cp(sp, ut.version);
  655    sp = n_string_push_c(sp, ' ');
  656    sp = n_string_push_cp(sp, ut.machine);
  657    sp = n_string_push_c(sp, '\n');
  658 
  659    /* Done */
  660    cp = n_string_cp(sp);
  661 
  662    if(n_pstate & n_PS_ARGMOD_VPUT){
  663       if(n_var_vset(*(char const**)vp, (uintptr_t)cp))
  664          rv = 0;
  665       else
  666          rv = -1;
  667    }else{
  668       if(fputs(cp, n_stdout) != EOF)
  669          rv = 0;
  670       else{
  671          clearerr(n_stdout);
  672          rv = 1;
  673       }
  674    }
  675    NYD_LEAVE;
  676    return rv;
  677 }
  678 
  679 /* s-it-mode */