Annotation of GNUtools/emacs/src/callproc.c, revision 1.1.1.1

1.1       root        1: /* Synchronous subprocess invocation for GNU Emacs.
                      2:    Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 1, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU Emacs is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU Emacs; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: 
                     21: /* This must precede sys/signal.h on certain machines.  */
                     22: #include <sys/types.h>
                     23: #include <signal.h>
                     24: 
                     25: #include "config.h"
                     26: 
                     27: #define PRIO_PROCESS 0
                     28: #include <sys/file.h>
                     29: #ifdef USG5
                     30: #include <fcntl.h>
                     31: #endif
                     32: 
                     33: #ifndef O_RDONLY
                     34: #define O_RDONLY 0
                     35: #endif
                     36: 
                     37: #ifndef O_WRONLY
                     38: #define O_WRONLY 1
                     39: #endif
                     40: 
                     41: #include "lisp.h"
                     42: #include "commands.h"
                     43: #include "buffer.h"
                     44: #include "paths.h"
                     45: 
                     46: #define max(a, b) ((a) > (b) ? (a) : (b))
                     47: 
                     48: Lisp_Object Vexec_path, Vexec_directory;
                     49: 
                     50: Lisp_Object Vshell_file_name;
                     51: 
                     52: #ifndef MAINTAIN_ENVIRONMENT
                     53: /* List of strings to append to front of environment of
                     54:    all subprocesses when they are started.  */
                     55: 
                     56: Lisp_Object Vprocess_environment;
                     57: #endif
                     58: 
                     59: #ifdef BSD4_1
                     60: /* Set nonzero when a synchronous subprocess is made,
                     61:    and set to zero again when it is observed to die.
                     62:    We wait for this to be zero in order to wait for termination.  */
                     63: int synch_process_pid;
                     64: #endif /* BSD4_1 */
                     65: 
                     66: /* True iff we are about to fork off a synchronous process or if we
                     67:    are waiting for it.  */
                     68: int synch_process_alive;
                     69: 
                     70: /* Nonzero => this is a string explaining death of synchronous subprocess.  */
                     71: char *synch_process_death;
                     72: 
                     73: /* Exit code of synchronous subprocess if positive,
                     74:    minus the signal number if negative.  */
                     75: int synch_process_retcode;
                     76: 
                     77: Lisp_Object
                     78: call_process_cleanup (fdpid)
                     79:      Lisp_Object fdpid;
                     80: {
                     81:   register Lisp_Object fd, pid;
                     82:   fd = Fcar (fdpid);
                     83:   pid = Fcdr (fdpid);
                     84:   close (XFASTINT (fd));
                     85:   kill (XFASTINT (pid), SIGKILL);
                     86:   return Qnil;
                     87: }
                     88: 
                     89: #ifdef VMS
                     90: #ifdef __GNUC__
                     91: #define        environ $$PsectAttributes_NOSHR$$environ
                     92: extern char **environ;
                     93: #else
                     94: extern noshare char **environ;
                     95: #endif
                     96: #else
                     97: extern char **environ;
                     98: #endif
                     99: 
                    100: DEFUN ("call-process", Fcall_process, Scall_process, 1, MANY, 0,
                    101:   "Call PROGRAM in separate process.\n\
                    102: Program's input comes from file INFILE (nil means /dev/null).\n\
                    103: Insert output in BUFFER before point; t means current buffer;\n\
                    104:  nil for BUFFER means discard it; 0 means discard and don't wait.\n\
                    105: Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\
                    106: Remaining arguments are strings passed as command arguments to PROGRAM.\n\
                    107: Returns nil if BUFFER is 0; otherwise waits for PROGRAM to terminate\n\
                    108: and returns a numeric exit status or a signal description string.\n\
                    109: If you quit, the process is killed with SIGKILL.")
                    110:   (nargs, args)
                    111:      int nargs;
                    112:      register Lisp_Object *args;
                    113: {
                    114:   Lisp_Object display, buffer, path;
                    115:   int fd[2];
                    116:   int filefd;
                    117:   register int pid;
                    118:   char buf[1024];
                    119:   int count = specpdl_ptr - specpdl;
                    120:   register unsigned char **new_argv
                    121:     = (unsigned char **) alloca ((max (2, nargs - 2)) * sizeof (char *));
                    122:   struct buffer *old = current_buffer;
                    123: 
                    124:   CHECK_STRING (args[0], 0);
                    125: 
                    126:   if (nargs <= 1 || NULL (args[1]))
                    127: #ifdef VMS
                    128:     args[1] = build_string ("NLA0:");
                    129: #else
                    130:     args[1] = build_string ("/dev/null");
                    131: #endif /* not VMS */
                    132:   else
                    133:     args[1] = Fexpand_file_name (args[1], current_buffer->directory);
                    134: 
                    135:   CHECK_STRING (args[1], 1);
                    136: 
                    137:   {
                    138:     register Lisp_Object tem;
                    139:     buffer = tem = args[2];
                    140:     if (nargs <= 2)
                    141:       buffer = Qnil;
                    142:     else if (!(EQ (tem, Qnil) || EQ (tem, Qt)
                    143:               || XFASTINT (tem) == 0))
                    144:       {
                    145:        buffer = Fget_buffer (tem);
                    146:        CHECK_BUFFER (buffer, 2);
                    147:       }
                    148:   }
                    149: 
                    150:   display = nargs > 3 ? args[3] : Qnil;
                    151: 
                    152:   {
                    153:     register int i;
                    154:     for (i = 4; i < nargs; i++)
                    155:       {
                    156:        CHECK_STRING (args[i], i);
                    157:        new_argv[i - 3] = XSTRING (args[i])->data;
                    158:       }
                    159:     /* Program name is first command arg */
                    160:     new_argv[0] = XSTRING (args[0])->data;
                    161:     new_argv[i - 3] = 0;
                    162:   }
                    163: 
                    164:   filefd = open (XSTRING (args[1])->data, O_RDONLY, 0);
                    165:   if (filefd < 0)
                    166:     {
                    167:       report_file_error ("Opening process input file", Fcons (args[1], Qnil));
                    168:     }
                    169:   /* Search for program; barf if not found.  */
                    170:   openp (Vexec_path, args[0], "", &path, 1);
                    171:   if (NULL (path))
                    172:     {
                    173:       close (filefd);
                    174:       report_file_error ("Searching for program", Fcons (args[0], Qnil));
                    175:     }
                    176:   new_argv[0] = XSTRING (path)->data;
                    177: 
                    178:   if (XTYPE (buffer) == Lisp_Int)
                    179: #ifdef VMS
                    180:     fd[1] = open ("NLA0:", 0), fd[0] = -1;
                    181: #else
                    182:     fd[1] = open ("/dev/null", O_WRONLY), fd[0] = -1;
                    183: #endif /* not VMS */
                    184:   else
                    185:     {
                    186:       pipe (fd);
                    187: #if 0
                    188:       /* Replaced by close_process_descs */
                    189:       set_exclusive_use (fd[0]);
                    190: #endif
                    191:     }
                    192: 
                    193:   synch_process_death = 0;
                    194:   synch_process_retcode = 0;
                    195: 
                    196:   {
                    197:     /* child_setup must clobber environ in systems with true vfork.
                    198:        Protect it from permanent change.  */
                    199:     register char **save_environ = environ;
                    200:     register int fd1 = fd[1];
                    201:     char **env;
                    202: 
                    203: #ifdef MAINTAIN_ENVIRONMENT
                    204:     env = (char **) alloca (size_of_current_environ ());
                    205:     get_current_environ (env);
                    206: #else
                    207:     env = environ;
                    208: #endif /* MAINTAIN_ENVIRONMENT */
                    209: 
                    210:     pid = vfork ();
                    211: #ifdef BSD4_1
                    212:     /* cause SIGCHLD interrupts to look for this pid. */
                    213:     synch_process_pid = pid;
                    214: #endif /* BSD4_1 */
                    215: 
                    216:     if (pid == 0)
                    217:       {
                    218:        if (fd[0] >= 0)
                    219:          close (fd[0]);
                    220: #ifdef USG
                    221: #ifdef HAVE_PTYS
                    222:        setpgrp ();
                    223: #endif
                    224: #endif
                    225:        child_setup (filefd, fd1, fd1, new_argv, env);
                    226:       }
                    227: 
                    228:     environ = save_environ;
                    229: 
                    230:     close (filefd);
                    231:     close (fd1);
                    232:   }
                    233: 
                    234:   if (pid < 0)
                    235:     {
                    236:       close (fd[0]);
                    237:       report_file_error ("Doing vfork", Qnil);
                    238:     }
                    239: 
                    240:   if (XTYPE (buffer) == Lisp_Int)
                    241:     {
                    242: #ifndef subprocesses
                    243:       wait_without_blocking ();
                    244: #endif subprocesses
                    245:       return Qnil;
                    246:     }
                    247: 
                    248:   record_unwind_protect (call_process_cleanup,
                    249:                         Fcons (make_number (fd[0]), make_number (pid)));
                    250: 
                    251: 
                    252:   if (XTYPE (buffer) == Lisp_Buffer)
                    253:     Fset_buffer (buffer);
                    254: 
                    255:   immediate_quit = 1;
                    256:   QUIT;
                    257: 
                    258:   {
                    259:     register int nread;
                    260: 
                    261:     while ((nread = read (fd[0], buf, sizeof buf)) > 0)
                    262:       {
                    263:        immediate_quit = 0;
                    264:        if (!NULL (buffer))
                    265:          insert (buf, nread);
                    266:        if (!NULL (display) && FROM_KBD)
                    267:          redisplay_preserve_echo_area ();
                    268:        immediate_quit = 1;
                    269:        QUIT;
                    270:       }
                    271:   }
                    272: 
                    273:   /* Wait for it to terminate, unless it already has.  */
                    274:   wait_for_termination (pid);
                    275: 
                    276:   immediate_quit = 0;
                    277: 
                    278:   set_buffer_internal (old);
                    279: 
                    280:   unbind_to (count);
                    281: 
                    282:   if (synch_process_death)
                    283:     return build_string (synch_process_death);
                    284:   return make_number (synch_process_retcode);
                    285: }
                    286: 
                    287: DEFUN ("call-process-region", Fcall_process_region, Scall_process_region,
                    288:   3, MANY, 0,
                    289:   "Send text from START to END to a process running PROGRAM.\n\
                    290: Delete the text if DELETE is non-nil.\n\
                    291: Insert output in BUFFER before point; t means current buffer;\n\
                    292:  nil for BUFFER means discard it; 0 means discard and don't wait.\n\
                    293: Sixth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\
                    294: Remaining arguments are strings passed as command arguments to PROGRAM.\n\
                    295: Returns nil if BUFFER is 0; otherwise waits for PROGRAM to terminate\n\
                    296: and returns a numeric exit status or a signal description string.\n\
                    297: If you quit, the process is killed with SIGKILL.")
                    298:   (nargs, args)
                    299:      int nargs;
                    300:      register Lisp_Object *args;
                    301: {
                    302:   register Lisp_Object filename_string, start, end, status;
                    303:   char tempfile[20];
                    304: 
                    305:   strcpy (tempfile, "/tmp/emacsXXXXXX");
                    306:   mktemp (tempfile);
                    307: 
                    308:   filename_string = build_string (tempfile);
                    309:   start = args[0];
                    310:   end = args[1];
                    311:   Fwrite_region (start, end, filename_string, Qnil, Qlambda);
                    312: 
                    313:   if (!NULL (args[3]))
                    314:     Fdelete_region (start, end);
                    315: 
                    316:   args[3] = filename_string;
                    317:   status = Fcall_process (nargs - 2, args + 2);
                    318:   unlink (tempfile);
                    319:   return status;
                    320: }
                    321: 
                    322: /* This is the last thing run in a newly forked inferior
                    323:    either synchronous or asynchronous.
                    324:    Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2.
                    325:    Initialize inferior's priority, pgrp, connected dir and environment.
                    326:    then exec another program based on new_argv.
                    327: 
                    328:    This function may change environ for the superior process.
                    329:    Therefore, the superior process must save and restore the value
                    330:    of environ around the vfork and the call to this function.
                    331: 
                    332:    ENV is the environment */
                    333: 
                    334: child_setup (in, out, err, new_argv, env)
                    335:      int in, out, err;
                    336:      register char **new_argv;
                    337:      char **env;
                    338: {
                    339:   register int pid = getpid();
                    340: 
                    341:   setpriority (PRIO_PROCESS, pid, 0);
                    342: 
                    343: #ifdef subprocesses
                    344:   /* Close Emacs's descriptors that this process should not have.  */
                    345:   close_process_descs ();
                    346: #endif
                    347: 
                    348:   /* Note that use of alloca is always safe here.  It's obvious for systems
                    349:      that do not have true vfork or that have true (stack) alloca.
                    350:      If using vfork and C_ALLOCA it is safe because that changes
                    351:      the superior's static variables as if the superior had done alloca
                    352:      and will be cleaned up in the usual way.  */
                    353: 
                    354:   if (XTYPE (current_buffer->directory) == Lisp_String)
                    355:     {
                    356:       register unsigned char *temp;
                    357:       register int i;
                    358: 
                    359:       i = XSTRING (current_buffer->directory)->size;
                    360:       temp = (unsigned char *) alloca (i + 2);
                    361:       bcopy (XSTRING (current_buffer->directory)->data, temp, i);
                    362:       if (temp[i - 1] != '/') temp[i++] = '/';
                    363:       temp[i] = 0;
                    364:       chdir (temp);
                    365:     }
                    366: 
                    367: #ifndef MAINTAIN_ENVIRONMENT
                    368:   /* Set `env' to a vector of the strings in Vprocess_environment.  */
                    369:   {
                    370:     register Lisp_Object tem;
                    371:     register char **new_env;
                    372:     register int new_length;
                    373: 
                    374:     new_length = 0;
                    375:     for (tem = Vprocess_environment;
                    376:         (XTYPE (tem) == Lisp_Cons
                    377:          && XTYPE (XCONS (tem)->car) == Lisp_String);
                    378:         tem = XCONS (tem)->cdr)
                    379:       new_length++;
                    380: 
                    381:     /* new_length + 1 to include terminating 0 */
                    382:     env = new_env = (char **) alloca ((new_length + 1) * sizeof (char *));
                    383: 
                    384:     /* Copy the env strings into new_env.  */
                    385:     for (tem = Vprocess_environment;
                    386:         (XTYPE (tem) == Lisp_Cons
                    387:          && XTYPE (XCONS (tem)->car) == Lisp_String);
                    388:         tem = XCONS (tem)->cdr)
                    389:       *new_env++ = (char *) XSTRING (XCONS (tem)->car)->data;
                    390:     *new_env = 0;
                    391:   }
                    392: #endif /* Not MAINTAIN_ENVIRONMENT */
                    393: 
                    394:   close (0);
                    395:   close (1);
                    396:   close (2);
                    397: 
                    398:   dup2 (in, 0);
                    399:   dup2 (out, 1);
                    400:   dup2 (err, 2);
                    401:   close (in);
                    402:   close (out);
                    403:   close (err);
                    404: 
                    405: #ifdef USG
                    406: #ifndef HAVE_PTYS
                    407:   setpgrp ();                  /* No arguments but equivalent in this case */
                    408: #endif
                    409: #else
                    410:   setpgrp (pid, pid);
                    411: #endif /* USG */
                    412:   setpgrp_of_tty (pid);
                    413: 
                    414: #ifdef vipc
                    415:   something missing here;
                    416: #endif vipc
                    417: 
                    418:   /* execvp does not accept an environment arg so the only way
                    419:      to pass this environment is to set environ.  Our caller
                    420:      is responsible for restoring the ambient value of environ.  */
                    421:   environ = env;
                    422:   execvp (new_argv[0], new_argv);
                    423: 
                    424:   write (1, "Couldn't exec the program ", 26);
                    425:   write (1, new_argv[0], strlen (new_argv[0]));
                    426:   _exit (1);
                    427: }
                    428: 
                    429: init_callproc ()
                    430: {
                    431:   register char * sh;
                    432:   extern char **environ;
                    433:   register char **envp;
                    434:   Lisp_Object execdir;
                    435: 
                    436:   /* Turn PATH_EXEC into a path.  Don't look at environment.  */
                    437:   Vexec_path = decode_env_path (0, PATH_EXEC);
                    438:   Vexec_directory = Ffile_name_as_directory (Fcar (Vexec_path));
                    439:   Vexec_path = nconc2 (decode_env_path ("PATH", ""), Vexec_path);
                    440: 
                    441:   execdir = Fdirectory_file_name (Vexec_directory);
                    442:   if (access (XSTRING (execdir)->data, 0) < 0)
                    443:     {
                    444:       printf ("Warning: executable/documentation dir (%s) does not exist.\n",
                    445:              XSTRING (Vexec_directory)->data);
                    446:       sleep (2);
                    447:     }
                    448: 
                    449:   sh = (char *) egetenv ("SHELL");
                    450:   Vshell_file_name = build_string (sh ? sh : "/bin/sh");
                    451: 
                    452: #ifndef MAINTAIN_ENVIRONMENT
                    453:   /* The equivalent of this operation was done
                    454:      in init_environ in environ.c if MAINTAIN_ENVIRONMENT */
                    455:   Vprocess_environment = Qnil;
                    456: #ifndef CANNOT_DUMP
                    457:   if (initialized)
                    458: #endif
                    459:     for (envp = environ; *envp; envp++)
                    460:       Vprocess_environment = Fcons (build_string (*envp),
                    461:                                    Vprocess_environment);
                    462: #endif /* MAINTAIN_ENVIRONMENT */
                    463: }
                    464: 
                    465: syms_of_callproc ()
                    466: {
                    467:   DEFVAR_LISP ("shell-file-name", &Vshell_file_name,
                    468:     "*File name to load inferior shells from.\n\
                    469: Initialized from the SHELL environment variable.");
                    470: 
                    471:   DEFVAR_LISP ("exec-path", &Vexec_path,
                    472:     "*List of directories to search programs to run in subprocesses.\n\
                    473: Each element is a string (directory name) or nil (try default directory).");
                    474: 
                    475:   DEFVAR_LISP ("exec-directory", &Vexec_directory,
                    476:     "Directory that holds programs that come with GNU Emacs,\n\
                    477: intended for Emacs to invoke.");
                    478: 
                    479: #ifndef MAINTAIN_ENVIRONMENT
                    480:   DEFVAR_LISP ("process-environment", &Vprocess_environment,
                    481:     "List of strings to append to environment of subprocesses that are started.\n\
                    482: Each string should have the format ENVVARNAME=VALUE.");
                    483: #endif
                    484: 
                    485:   defsubr (&Scall_process);
                    486:   defsubr (&Scall_process_region);
                    487: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.