1: /* Synchronous subprocess invocation for GNU Emacs. 2: Copyright (C) 1985 Richard M. Stallman. 3: 4: This file is part of GNU Emacs. 5: 6: GNU Emacs is distributed in the hope that it will be useful, 7: but WITHOUT ANY WARRANTY. No author or distributor 8: accepts responsibility to anyone for the consequences of using it 9: or for whether it serves any particular purpose or works at all, 10: unless he says so in writing. Refer to the GNU Emacs General Public 11: License for full details. 12: 13: Everyone is granted permission to copy, modify and redistribute 14: GNU Emacs, but only under the conditions described in the 15: GNU Emacs General Public License. A copy of this license is 16: supposed to have been given to you along with GNU Emacs so you 17: can know your rights and responsibilities. It should be in a 18: file named COPYING. Among other things, the copyright notice 19: and this notice must be preserved on all copies. */ 20: 21: 22: #include <signal.h> 23: 24: #include "config.h" 25: 26: #include <sys/types.h> 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: #include "lisp.h" 38: #include "commands.h" 39: #include "buffer.h" 40: #include "paths.h" 41: 42: #define max(a, b) ((a) > (b) ? (a) : (b)) 43: 44: Lisp_Object Vexec_path, Vexec_directory; 45: 46: Lisp_Object Vshell_file_name; 47: 48: #ifdef BSD4_1 49: /* Set nonzero when a synchronous subprocess is made, 50: and set to zero again when it is observed to die. 51: We wait for this to be zero in order to wait for termination. */ 52: int synch_process_pid; 53: #endif /* BSD4_1 */ 54: 55: Lisp_Object 56: call_process_cleanup (fdpid) 57: Lisp_Object fdpid; 58: { 59: Lisp_Object fd, pid; 60: fd = Fcar (fdpid); 61: pid = Fcdr (fdpid); 62: close (XFASTINT (fd)); 63: kill (XFASTINT (pid), SIGKILL); 64: return Qnil; 65: } 66: 67: DEFUN ("call-process", Fcall_process, Scall_process, 1, MANY, 0, 68: "Call PROGRAM in separate process.\n\ 69: Program's input comes from file INFILE (nil means /dev/null).\n\ 70: Insert output in BUFFER before point; t means current buffer;\n\ 71: nil for BUFFER means discard it; 0 means discard and don't wait.\n\ 72: Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\ 73: Remaining arguments are strings passed as command arguments to PROGRAM.\n\ 74: This function waits for PROGRAM to terminate;\n\ 75: if you quit, the process is killed.") 76: (nargs, args) 77: int nargs; 78: Lisp_Object *args; 79: { 80: Lisp_Object display, buffer, tem, tem1; 81: int fd[2]; 82: int filefd; 83: int pid; 84: register int nread; 85: char buf[1024]; 86: int count = specpdl_ptr - specpdl; 87: register int i; 88: register unsigned char **new_argv 89: = (unsigned char **) alloca ((max (2, nargs - 2)) * sizeof (char *)); 90: struct buffer *old = bf_cur; 91: 92: tem = args[0]; 93: CHECK_STRING (tem, 0); 94: 95: if (nargs <= 1 || NULL (args[1])) 96: args[1] = build_string ("/dev/null"); 97: else 98: tem = args[1], 99: args[1] = Fexpand_file_name (tem, bf_cur->directory); 100: tem = args[1]; 101: CHECK_STRING (tem, 1); 102: 103: if (nargs <= 2 || NULL (args[2])) 104: buffer = Qnil; 105: else if (EQ (args[2], Qt)) 106: buffer = Qt; 107: else if (XFASTINT (args[2]) == 0) 108: buffer = args[2]; 109: else 110: { 111: tem = args[2]; 112: buffer = Fget_buffer (tem); 113: CHECK_BUFFER (buffer, 2); 114: } 115: 116: display = nargs >= 3 ? args[3] : Qnil; 117: 118: for (i = 4; i < nargs; i++) 119: { 120: tem = args[i]; 121: CHECK_STRING (tem, i); 122: new_argv[i - 3] = XSTRING (args[i])->data; 123: } 124: /* Program name is first command arg */ 125: new_argv[0] = XSTRING (args[0])->data; 126: new_argv[i - 3] = 0; 127: 128: filefd = open (XSTRING (args[1])->data, O_RDONLY, 0); 129: if (filefd < 0) 130: { 131: tem = args[1]; 132: report_file_error ("Opening process input file", Fcons (tem, Qnil)); 133: } 134: /* Search for program; barf if not found. */ 135: tem1 = args[0]; 136: openp (Vexec_path, tem1, "", &tem, 1); 137: if (NULL (tem)) 138: { 139: close (filefd); 140: report_file_error ("Searching for program", Fcons (tem1, Qnil)); 141: } 142: new_argv[0] = XSTRING (tem)->data; 143: 144: if (XTYPE (buffer) == Lisp_Int) 145: fd[1] = open ("/dev/null", 0), fd[0] = -1; 146: else 147: { 148: pipe (fd); 149: set_exclusive_use (fd[0]); 150: } 151: 152: pid = vfork(); 153: #ifdef BSD4_1 154: /* cause SIGCHLD interrupts to look for this pid. */ 155: synch_process_pid = pid; 156: #endif /* BSD4_1 */ 157: 158: if (!pid) 159: child_setup (filefd, fd[1], fd[1], new_argv); 160: 161: close (filefd); 162: close (fd[1]); 163: 164: if (pid < 0) 165: { 166: close (fd[0]); 167: report_file_error ("Doing vfork", Qnil); 168: } 169: 170: if (XTYPE (buffer) == Lisp_Int) 171: { 172: #ifndef subprocesses 173: wait_without_blocking (); 174: #endif subprocesses 175: return Qnil; 176: } 177: 178: record_unwind_protect (call_process_cleanup, 179: Fcons (make_number (fd[0]), make_number (pid))); 180: 181: 182: if (XTYPE (buffer) == Lisp_Buffer) 183: Fset_buffer (buffer); 184: 185: immediate_quit = 1; 186: QUIT; 187: while ((nread = read (fd[0], buf, sizeof buf)) > 0) 188: { 189: immediate_quit = 0; 190: if (!NULL (buffer)) 191: InsCStr (buf, nread); 192: if (!NULL (display) && INTERACTIVE) 193: DoDsp (1); 194: immediate_quit = 1; 195: QUIT; 196: } 197: 198: /* Wait for it to terminate, unless it already has. */ 199: wait_for_termination (pid); 200: 201: immediate_quit = 0; 202: 203: SetBfp (old); 204: 205: unbind_to (count); 206: 207: return Qnil; 208: } 209: 210: child_setup (in, out, err, new_argv) 211: int in, out, err; 212: char **new_argv; 213: { 214: int pid = getpid(); 215: register int i; 216: unsigned char *temp; 217: 218: child_setup_tty (out); 219: 220: setpriority (PRIO_PROCESS, pid, 0); 221: 222: if (XTYPE (bf_cur->directory) == Lisp_String) 223: { 224: temp = (unsigned char *) alloca (XSTRING (bf_cur->directory)->size + 2); 225: bcopy (XSTRING (bf_cur->directory)->data, temp, 226: XSTRING (bf_cur->directory)->size); 227: i = XSTRING (bf_cur->directory)->size; 228: if (temp[i - 1] != '/') temp[i++] = '/'; 229: temp[i] = 0; 230: chdir (temp); 231: } 232: 233: close (0); 234: close (1); 235: close (2); 236: 237: dup2 (in, 0); 238: dup2 (out, 1); 239: dup2 (err, 2); 240: 241: #ifdef USG 242: setpgrp (); /* No arguments but equivalent in this case */ 243: #else 244: setpgrp (pid, pid); 245: #endif /* USG */ 246: setpgrp_of_tty (pid); 247: 248: #ifdef vipc 249: something missing here; 250: #endif vipc 251: 252: execvp (new_argv[0], new_argv); 253: write (1, "Couldn't exec the program ", 26); 254: write (1, new_argv[0], strlen (new_argv[0])); 255: _exit (1); 256: } 257: 258: DEFUN ("call-process-region", Fcall_process_region, Scall_process_region, 259: 3, MANY, 0, 260: "Send text from START to END to a process running PROGRAM.\n\ 261: Delete the text if DELETE is non-nil.\n\ 262: Put output in BUFFER, before point. nil => discard it, t => current buffer.\n\ 263: Sixth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\ 264: Remaining args are passed to PROGRAM at startup as command args.\n\ 265: This function normally waits for the process to terminate;\n\ 266: if you quit, the process is killed.") 267: (nargs, args) 268: int nargs; 269: Lisp_Object *args; 270: { 271: Lisp_Object filename_string, start, end; 272: char tempfile[20]; 273: 274: strcpy (tempfile, "/tmp/emacsXXXXXX"); 275: mktemp (tempfile); 276: 277: filename_string = build_string (tempfile); 278: start = args[0]; 279: end = args[1]; 280: Fwrite_region (start, end, filename_string, Qnil, Qlambda); 281: 282: if (!NULL (args[3])) 283: Fdelete_region (start, end); 284: 285: args[3] = filename_string; 286: Fcall_process (nargs - 2, args + 2); 287: unlink (tempfile); 288: return Qnil; 289: } 290: 291: init_callproc () 292: { 293: char *sh; 294: 295: Vexec_path = nconc2 (decode_env_path ("PATH", ""), 296: decode_env_path ("%$&*#", PATH_EXEC)); 297: Vexec_directory = build_string (PATH_EXEC); 298: Vexec_directory = concat2 (Vexec_directory, build_string ("/")); 299: 300: sh = (char *) getenv ("SHELL"); 301: Vshell_file_name = build_string (sh ? sh : "/bin/sh"); 302: } 303: 304: syms_of_callproc () 305: { 306: DefLispVar ("shell-file-name", &Vshell_file_name, 307: "*File name to load inferior shells from.\n\ 308: Initialized from the SHELL environment variable."); 309: 310: DefLispVar ("exec-path", &Vexec_path, 311: "*List of directories to search programs to run in subprocesses.\n\ 312: Each element is a string (directory name) or nil (try default directory)."); 313: 314: DefLispVar ("exec-directory", &Vexec_directory, 315: "Directory that holds programs that come with GNU Emacs,\n\ 316: intended for Emacs to invoke."); 317: 318: defsubr (&Scall_process); 319: defsubr (&Scall_process_region); 320: }