home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_shell.c < prev    next >
Text File  |  1997-06-24  |  9KB  |  416 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)ex_shell.c    10.38 (Berkeley) 8/19/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/param.h>
  17. #include <sys/queue.h>
  18. #include <sys/wait.h>
  19.  
  20. #include <bitstring.h>
  21. #include <errno.h>
  22. #include <limits.h>
  23. #include <signal.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28.  
  29. #include "../common/common.h"
  30.  
  31. #if VI_DOSISH
  32. #include <process.h>
  33. #endif
  34.  
  35. static const char *sigmsg __P((int));
  36.  
  37. /*
  38.  * ex_shell -- :sh[ell]
  39.  *    Invoke the program named in the SHELL environment variable
  40.  *    with the argument -i.
  41.  *
  42.  * PUBLIC: int ex_shell __P((SCR *, EXCMD *));
  43.  */
  44. int
  45. ex_shell(sp, cmdp)
  46.     SCR *sp;
  47.     EXCMD *cmdp;
  48. {
  49.     int rval;
  50.     char buf[MAXPATHLEN];
  51.  
  52.     /* We'll need a shell. */
  53.     if (opts_empty(sp, O_SHELL, 0))
  54.         return (1);
  55.  
  56. #if VI_DOSISH
  57.     (void)snprintf(buf, sizeof(buf), "%s", O_STR(sp, O_SHELL));
  58. #else
  59.     /*
  60.      * XXX
  61.      * Assumes all shells use -i.
  62.      */
  63.     (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
  64. #endif
  65.  
  66.     /* Restore the window name. */
  67.     (void)sp->gp->scr_rename(sp, NULL, 0);
  68.  
  69.     /* If we're still in a vi screen, move out explicitly. */
  70.     rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
  71.  
  72.     /* Set the window name. */
  73.     (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
  74.  
  75.     /*
  76.      * !!!
  77.      * Historically, vi didn't require a continue message after the
  78.      * return of the shell.  Match it.
  79.      */
  80.     F_SET(sp, SC_EX_WAIT_NO);
  81.  
  82.     return (rval);
  83. }
  84.  
  85. /*
  86.  * ex_exec_proc --
  87.  *    Run a separate process.
  88.  *
  89.  * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
  90.  */
  91. int
  92. ex_exec_proc(sp, cmdp, cmd, msg, need_newline)
  93.     SCR *sp;
  94.     EXCMD *cmdp;
  95.     char *cmd;
  96.     const char *msg;
  97.     int need_newline;
  98. {
  99.     GS *gp;
  100.     const char *name;
  101. #if VI_DOSISH
  102.     const char *comspec;
  103. #endif
  104.     pid_t pid;
  105.  
  106.     gp = sp->gp;
  107.  
  108.     /* We'll need a shell. */
  109. #if VI_DOSISH
  110.     if (!(comspec = getenv("COMSPEC")))
  111.         return (1);
  112. #else
  113.     if (opts_empty(sp, O_SHELL, 0))
  114.         return (1);
  115. #endif
  116.  
  117.     /* Enter ex mode. */
  118.     if (F_ISSET(sp, SC_VI)) {
  119.         if (gp->scr_screen(sp, SC_EX)) {
  120.             ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
  121.             return (1);
  122.         }
  123.         (void)gp->scr_attr(sp, SA_ALTERNATE, 0);
  124.         F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
  125.     }
  126.  
  127.     /* Put out additional newline, message. */
  128.     if (need_newline)
  129.         (void)ex_puts(sp, "\n");
  130.     if (msg != NULL) {
  131.         (void)ex_puts(sp, msg);
  132.         (void)ex_puts(sp, "\n");
  133.     }
  134.     (void)ex_fflush(sp);
  135.  
  136. #if VI_DOSISH
  137.     /*
  138.      * "shell" defines the interactive shell; %COMSPEC% is noninteractive
  139.      * and not subject to user override.  This behavior is a tightrope
  140.      * walk between Unix, MS-whatsit, and OS/2 usage.  (MS uses COMSPEC for
  141.      * everything; OS/2 uses COMSPEC noninteractively and OS2_SHELL for
  142.      * interactive use, resolving the discrepancy between user shells and
  143.      * something programs can rely on behaving consistently.)
  144.      *
  145.      * We also handle both kinds of slashes, although not all EMX targets
  146.      * will tolerate / in COMSPEC.
  147.      */
  148.     if ((name = strrchr(comspec, '/')) != NULL)
  149.         ++name;
  150.     else if ((name = strrchr(comspec, '\\')) != NULL)
  151.         ++name;
  152.     else
  153.         name = comspec;
  154.     return (spawnl(P_WAIT, comspec, name, "/C", cmd, NULL));
  155. #else
  156.     switch (pid = vfork()) {
  157.     case -1:            /* Error. */
  158.         msgq(sp, M_SYSERR, "vfork");
  159.         return (1);
  160.     case 0:                /* Utility. */
  161.         if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
  162.             name = O_STR(sp, O_SHELL);
  163.         else
  164.             ++name;
  165.         execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
  166.         msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
  167.         _exit(127);
  168.         /* NOTREACHED */
  169.     default:            /* Parent. */
  170.         return (proc_wait(sp, (long)pid, cmd, 0, 0));
  171.     }
  172. #endif
  173.     /* NOTREACHED */
  174. }
  175.  
  176. /*
  177.  * proc_wait --
  178.  *    Wait for one of the processes.
  179.  *
  180.  * !!!
  181.  * The pid_t type varies in size from a short to a long depending on the
  182.  * system.  It has to be cast into something or the standard promotion
  183.  * rules get you.  I'm using a long based on the belief that nobody is
  184.  * going to make it unsigned and it's unlikely to be a quad.
  185.  *
  186.  * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
  187.  */
  188. int
  189. proc_wait(sp, pid, cmd, silent, okpipe)
  190.     SCR *sp;
  191.     long pid;
  192.     const char *cmd;
  193.     int silent, okpipe;
  194. {
  195.     size_t len;
  196.     int nf, pstat;
  197.     char *p;
  198.  
  199.     /* Wait for the utility, ignoring interruptions. */
  200.     for (;;) {
  201.         errno = 0;
  202.         if (waitpid((pid_t)pid, &pstat, 0) != -1)
  203.             break;
  204.         if (errno != EINTR) {
  205.             msgq(sp, M_SYSERR, "waitpid");
  206.             return (1);
  207.         }
  208.     }
  209.  
  210.     /*
  211.      * Display the utility's exit status.  Ignore SIGPIPE from the
  212.      * parent-writer, as that only means that the utility chose to
  213.      * exit before reading all of its input.
  214.      */
  215.     if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
  216.         for (; isblank(*cmd); ++cmd);
  217.         p = msg_print(sp, cmd, &nf);
  218.         len = strlen(p);
  219.         msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
  220.             MIN(len, 20), p, len > 20 ? " ..." : "",
  221.             sigmsg(WTERMSIG(pstat)),
  222.             WCOREDUMP(pstat) ? "; core dumped" : "");
  223.         if (nf)
  224.             FREE_SPACE(sp, p, 0);
  225.         return (1);
  226.     }
  227.  
  228.     if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
  229.         /*
  230.          * Remain silent for "normal" errors when doing shell file
  231.          * name expansions, they almost certainly indicate nothing
  232.          * more than a failure to match.
  233.          *
  234.          * Remain silent for vi read filter errors.  It's historic
  235.          * practice.
  236.          */
  237.         if (!silent) {
  238.             for (; isblank(*cmd); ++cmd);
  239.             p = msg_print(sp, cmd, &nf);
  240.             len = strlen(p);
  241.             msgq(sp, M_ERR, "%.*s%s: exited with status %d",
  242.                 MIN(len, 20), p, len > 20 ? " ..." : "",
  243.                 WEXITSTATUS(pstat));
  244.             if (nf)
  245.                 FREE_SPACE(sp, p, 0);
  246.         }
  247.         return (1);
  248.     }
  249.     return (0);
  250. }
  251.  
  252. /*
  253.  * XXX
  254.  * The sys_siglist[] table in the C library has this information, but there's
  255.  * no portable way to get to it.  (Believe me, I tried.)
  256.  */
  257. typedef struct _sigs {
  258.     int     number;        /* signal number */
  259.     char    *message;        /* related message */
  260. } SIGS;
  261.  
  262. SIGS const sigs[] = {
  263. #ifdef SIGABRT
  264.     SIGABRT,    "Abort trap",
  265. #endif
  266. #ifdef SIGALRM
  267.     SIGALRM,    "Alarm clock",
  268. #endif
  269. #ifdef SIGBUS
  270.     SIGBUS,        "Bus error",
  271. #endif
  272. #ifdef SIGCLD
  273.     SIGCLD,        "Child exited or stopped",
  274. #endif
  275. #ifdef SIGCHLD
  276.     SIGCHLD,    "Child exited",
  277. #endif
  278. #ifdef SIGCONT
  279.     SIGCONT,    "Continued",
  280. #endif
  281. #ifdef SIGDANGER
  282.     SIGDANGER,    "System crash imminent",
  283. #endif
  284. #ifdef SIGEMT
  285.     SIGEMT,        "EMT trap",
  286. #endif
  287. #ifdef SIGFPE
  288.     SIGFPE,        "Floating point exception",
  289. #endif
  290. #ifdef SIGGRANT
  291.     SIGGRANT,    "HFT monitor mode granted",
  292. #endif
  293. #ifdef SIGHUP
  294.     SIGHUP,        "Hangup",
  295. #endif
  296. #ifdef SIGILL
  297.     SIGILL,        "Illegal instruction",
  298. #endif
  299. #ifdef SIGINFO
  300.     SIGINFO,    "Information request",
  301. #endif
  302. #ifdef SIGINT
  303.     SIGINT,        "Interrupt",
  304. #endif
  305. #ifdef SIGIO
  306.     SIGIO,        "I/O possible",
  307. #endif
  308. #ifdef SIGIOT
  309.     SIGIOT,        "IOT trap",
  310. #endif
  311. #ifdef SIGKILL
  312.     SIGKILL,    "Killed",
  313. #endif
  314. #ifdef SIGLOST
  315.     SIGLOST,    "Record lock",
  316. #endif
  317. #ifdef SIGMIGRATE
  318.     SIGMIGRATE,    "Migrate process to another CPU",
  319. #endif
  320. #ifdef SIGMSG
  321.     SIGMSG,        "HFT input data pending",
  322. #endif
  323. #ifdef SIGPIPE
  324.     SIGPIPE,    "Broken pipe",
  325. #endif
  326. #ifdef SIGPOLL
  327.     SIGPOLL,    "I/O possible",
  328. #endif
  329. #ifdef SIGPRE
  330.     SIGPRE,        "Programming error",
  331. #endif
  332. #ifdef SIGPROF
  333.     SIGPROF,    "Profiling timer expired",
  334. #endif
  335. #ifdef SIGPWR
  336.     SIGPWR,        "Power failure imminent",
  337. #endif
  338. #ifdef SIGRETRACT
  339.     SIGRETRACT,    "HFT monitor mode retracted",
  340. #endif
  341. #ifdef SIGQUIT
  342.     SIGQUIT,    "Quit",
  343. #endif
  344. #ifdef SIGSAK
  345.     SIGSAK,        "Secure Attention Key",
  346. #endif
  347. #ifdef SIGSEGV
  348.     SIGSEGV,    "Segmentation fault",
  349. #endif
  350. #ifdef SIGSOUND
  351.     SIGSOUND,    "HFT sound sequence completed",
  352. #endif
  353. #ifdef SIGSTOP
  354.     SIGSTOP,    "Suspended (signal)",
  355. #endif
  356. #ifdef SIGSYS
  357.     SIGSYS,        "Bad system call",
  358. #endif
  359. #ifdef SIGTERM
  360.     SIGTERM,    "Terminated",
  361. #endif
  362. #ifdef SIGTRAP
  363.     SIGTRAP,    "Trace/BPT trap",
  364. #endif
  365. #ifdef SIGTSTP
  366.     SIGTSTP,    "Suspended",
  367. #endif
  368. #ifdef SIGTTIN
  369.     SIGTTIN,    "Stopped (tty input)",
  370. #endif
  371. #ifdef SIGTTOU
  372.     SIGTTOU,    "Stopped (tty output)",
  373. #endif
  374. #ifdef SIGURG
  375.     SIGURG,        "Urgent I/O condition",
  376. #endif
  377. #ifdef SIGUSR1
  378.     SIGUSR1,    "User defined signal 1",
  379. #endif
  380. #ifdef SIGUSR2
  381.     SIGUSR2,    "User defined signal 2",
  382. #endif
  383. #ifdef SIGVTALRM
  384.     SIGVTALRM,    "Virtual timer expired",
  385. #endif
  386. #ifdef SIGWINCH
  387.     SIGWINCH,    "Window size changes",
  388. #endif
  389. #ifdef SIGXCPU
  390.     SIGXCPU,    "Cputime limit exceeded",
  391. #endif
  392. #ifdef SIGXFSZ
  393.     SIGXFSZ,    "Filesize limit exceeded",
  394. #endif
  395. };
  396.  
  397. /*
  398.  * sigmsg --
  399.  *     Return a pointer to a message describing a signal.
  400.  */
  401. static const char *
  402. sigmsg(signo)
  403.     int signo;
  404. {
  405.     static char buf[40];
  406.     const SIGS *sigp;
  407.     int n;
  408.  
  409.     for (n = 0,
  410.         sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp)
  411.         if (sigp->number == signo)
  412.             return (sigp->message);
  413.     (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo);
  414.     return (buf);
  415. }
  416.