|
|
1.1 ! root 1: /* Synchronous subprocess invocation for GNU Emacs. ! 2: Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. ! 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: #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: Lisp_Object ! 67: call_process_cleanup (fdpid) ! 68: Lisp_Object fdpid; ! 69: { ! 70: register Lisp_Object fd, pid; ! 71: fd = Fcar (fdpid); ! 72: pid = Fcdr (fdpid); ! 73: close (XFASTINT (fd)); ! 74: kill (XFASTINT (pid), SIGKILL); ! 75: return Qnil; ! 76: } ! 77: ! 78: #ifdef VMS ! 79: extern noshare char **environ; ! 80: #else ! 81: extern char **environ; ! 82: #endif ! 83: ! 84: DEFUN ("call-process", Fcall_process, Scall_process, 1, MANY, 0, ! 85: "Call PROGRAM in separate process.\n\ ! 86: Program's input comes from file INFILE (nil means /dev/null).\n\ ! 87: Insert output in BUFFER before point; t means current buffer;\n\ ! 88: nil for BUFFER means discard it; 0 means discard and don't wait.\n\ ! 89: Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\ ! 90: Remaining arguments are strings passed as command arguments to PROGRAM.\n\ ! 91: This function waits for PROGRAM to terminate;\n\ ! 92: if you quit, the process is killed.") ! 93: (nargs, args) ! 94: int nargs; ! 95: register Lisp_Object *args; ! 96: { ! 97: Lisp_Object display, buffer, path; ! 98: int fd[2]; ! 99: int filefd; ! 100: register int pid; ! 101: char buf[1024]; ! 102: int count = specpdl_ptr - specpdl; ! 103: register unsigned char **new_argv ! 104: = (unsigned char **) alloca ((max (2, nargs - 2)) * sizeof (char *)); ! 105: struct buffer *old = bf_cur; ! 106: ! 107: CHECK_STRING (args[0], 0); ! 108: ! 109: if (nargs <= 1 || NULL (args[1])) ! 110: #ifdef VMS ! 111: args[1] = build_string ("NLA0:"); ! 112: #else ! 113: args[1] = build_string ("/dev/null"); ! 114: #endif /* not VMS */ ! 115: else ! 116: args[1] = Fexpand_file_name (args[1], bf_cur->directory); ! 117: ! 118: CHECK_STRING (args[1], 1); ! 119: ! 120: { ! 121: register Lisp_Object tem; ! 122: buffer = tem = args[2]; ! 123: if (nargs <= 2) ! 124: buffer = Qnil; ! 125: else if (!(EQ (tem, Qnil) || EQ (tem, Qt) ! 126: || XFASTINT (tem) == 0)) ! 127: { ! 128: buffer = Fget_buffer (tem); ! 129: CHECK_BUFFER (buffer, 2); ! 130: } ! 131: } ! 132: ! 133: display = nargs >= 3 ? args[3] : Qnil; ! 134: ! 135: { ! 136: register int i; ! 137: for (i = 4; i < nargs; i++) ! 138: { ! 139: CHECK_STRING (args[i], i); ! 140: new_argv[i - 3] = XSTRING (args[i])->data; ! 141: } ! 142: /* Program name is first command arg */ ! 143: new_argv[0] = XSTRING (args[0])->data; ! 144: new_argv[i - 3] = 0; ! 145: } ! 146: ! 147: filefd = open (XSTRING (args[1])->data, O_RDONLY, 0); ! 148: if (filefd < 0) ! 149: { ! 150: report_file_error ("Opening process input file", Fcons (args[1], Qnil)); ! 151: } ! 152: /* Search for program; barf if not found. */ ! 153: openp (Vexec_path, args[0], "", &path, 1); ! 154: if (NULL (path)) ! 155: { ! 156: close (filefd); ! 157: report_file_error ("Searching for program", Fcons (args[0], Qnil)); ! 158: } ! 159: new_argv[0] = XSTRING (path)->data; ! 160: ! 161: if (XTYPE (buffer) == Lisp_Int) ! 162: #ifdef VMS ! 163: fd[1] = open ("NLA0:", 0), fd[0] = -1; ! 164: #else ! 165: fd[1] = open ("/dev/null", O_WRONLY), fd[0] = -1; ! 166: #endif /* not VMS */ ! 167: else ! 168: { ! 169: pipe (fd); ! 170: #if 0 ! 171: /* Replaced by close_process_descs */ ! 172: set_exclusive_use (fd[0]); ! 173: #endif ! 174: } ! 175: ! 176: { ! 177: /* child_setup must clobber environ in systems with true vfork. ! 178: Protect it from permanent change. */ ! 179: register char **save_environ = environ; ! 180: register int fd1 = fd[1]; ! 181: char **env; ! 182: ! 183: #ifdef MAINTAIN_ENVIRONMENT ! 184: env = (char **) alloca (size_of_current_environ ()); ! 185: get_current_environ (env); ! 186: #else ! 187: env = environ; ! 188: #endif /* MAINTAIN_ENVIRONMENT */ ! 189: ! 190: pid = vfork (); ! 191: #ifdef BSD4_1 ! 192: /* cause SIGCHLD interrupts to look for this pid. */ ! 193: synch_process_pid = pid; ! 194: #endif /* BSD4_1 */ ! 195: ! 196: if (pid == 0) ! 197: { ! 198: if (fd[0] >= 0) ! 199: close (fd[0]); ! 200: #ifdef USG ! 201: #ifdef HAVE_PTYS ! 202: setpgrp (); ! 203: #endif ! 204: #endif ! 205: child_setup (filefd, fd1, fd1, new_argv, env); ! 206: } ! 207: ! 208: environ = save_environ; ! 209: ! 210: close (filefd); ! 211: close (fd1); ! 212: } ! 213: ! 214: if (pid < 0) ! 215: { ! 216: close (fd[0]); ! 217: report_file_error ("Doing vfork", Qnil); ! 218: } ! 219: ! 220: if (XTYPE (buffer) == Lisp_Int) ! 221: { ! 222: #ifndef subprocesses ! 223: wait_without_blocking (); ! 224: #endif subprocesses ! 225: return Qnil; ! 226: } ! 227: ! 228: record_unwind_protect (call_process_cleanup, ! 229: Fcons (make_number (fd[0]), make_number (pid))); ! 230: ! 231: ! 232: if (XTYPE (buffer) == Lisp_Buffer) ! 233: Fset_buffer (buffer); ! 234: ! 235: immediate_quit = 1; ! 236: QUIT; ! 237: ! 238: { ! 239: register int nread; ! 240: ! 241: while ((nread = read (fd[0], buf, sizeof buf)) > 0) ! 242: { ! 243: immediate_quit = 0; ! 244: if (!NULL (buffer)) ! 245: InsCStr (buf, nread); ! 246: if (!NULL (display) && INTERACTIVE) ! 247: DoDsp (1); ! 248: immediate_quit = 1; ! 249: QUIT; ! 250: } ! 251: } ! 252: ! 253: /* Wait for it to terminate, unless it already has. */ ! 254: wait_for_termination (pid); ! 255: ! 256: immediate_quit = 0; ! 257: ! 258: SetBfp (old); ! 259: ! 260: unbind_to (count); ! 261: ! 262: return Qnil; ! 263: } ! 264: ! 265: DEFUN ("call-process-region", Fcall_process_region, Scall_process_region, ! 266: 3, MANY, 0, ! 267: "Send text from START to END to a process running PROGRAM.\n\ ! 268: Delete the text if DELETE is non-nil.\n\ ! 269: Put output in BUFFER, before point. nil => discard it, t => current buffer.\n\ ! 270: Sixth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\ ! 271: Remaining args are passed to PROGRAM at startup as command args.\n\ ! 272: This function normally waits for the process to terminate;\n\ ! 273: if you quit, the process is killed.") ! 274: (nargs, args) ! 275: int nargs; ! 276: register Lisp_Object *args; ! 277: { ! 278: register Lisp_Object filename_string, start, end; ! 279: char tempfile[20]; ! 280: ! 281: strcpy (tempfile, "/tmp/emacsXXXXXX"); ! 282: mktemp (tempfile); ! 283: ! 284: filename_string = build_string (tempfile); ! 285: start = args[0]; ! 286: end = args[1]; ! 287: Fwrite_region (start, end, filename_string, Qnil, Qlambda); ! 288: ! 289: if (!NULL (args[3])) ! 290: Fdelete_region (start, end); ! 291: ! 292: args[3] = filename_string; ! 293: Fcall_process (nargs - 2, args + 2); ! 294: unlink (tempfile); ! 295: return Qnil; ! 296: } ! 297: ! 298: /* This is the last thing run in a newly forked inferior ! 299: either synchronous or asynchronous. ! 300: Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2. ! 301: Initialize inferior's priority, pgrp, connected dir and environment. ! 302: then exec another program based on new_argv. ! 303: ! 304: This function may change environ for the superior process. ! 305: Therefore, the superior process must save and restore the value ! 306: of environ around the vfork and the call to this function. ! 307: ! 308: ENV is the environment */ ! 309: ! 310: child_setup (in, out, err, new_argv, env) ! 311: int in, out, err; ! 312: register char **new_argv; ! 313: char **env; ! 314: { ! 315: register int pid = getpid(); ! 316: ! 317: setpriority (PRIO_PROCESS, pid, 0); ! 318: ! 319: #ifdef subprocesses ! 320: /* Close Emacs's descriptors that this process should not have. */ ! 321: close_process_descs (); ! 322: #endif ! 323: ! 324: /* Note that use of alloca is always safe here. It's obvious for systems ! 325: that do not have true vfork or that have true (stack) alloca. ! 326: If using vfork and C_ALLOCA it is safe because that changes ! 327: the superior's static variables as if the superior had done alloca ! 328: and will be cleaned up in the usual way. */ ! 329: ! 330: if (XTYPE (bf_cur->directory) == Lisp_String) ! 331: { ! 332: register unsigned char *temp; ! 333: register int i; ! 334: ! 335: i = XSTRING (bf_cur->directory)->size; ! 336: temp = (unsigned char *) alloca (i + 2); ! 337: bcopy (XSTRING (bf_cur->directory)->data, temp, i); ! 338: if (temp[i - 1] != '/') temp[i++] = '/'; ! 339: temp[i] = 0; ! 340: chdir (temp); ! 341: } ! 342: ! 343: #ifndef MAINTAIN_ENVIRONMENT ! 344: /* Set `env' to a vector of the strings in Vprocess_environment. */ ! 345: { ! 346: register Lisp_Object tem; ! 347: register char **new_env; ! 348: register int new_length; ! 349: ! 350: new_length = 0; ! 351: for (tem = Vprocess_environment; ! 352: (XTYPE (tem) == Lisp_Cons ! 353: && XTYPE (XCONS (tem)->car) == Lisp_String); ! 354: tem = XCONS (tem)->cdr) ! 355: new_length++; ! 356: ! 357: /* new_length + 1 to include terminating 0 */ ! 358: env = new_env = (char **) alloca ((new_length + 1) * sizeof (char *)); ! 359: ! 360: /* Copy the env strings into new_env. */ ! 361: for (tem = Vprocess_environment; ! 362: (XTYPE (tem) == Lisp_Cons ! 363: && XTYPE (XCONS (tem)->car) == Lisp_String); ! 364: tem = XCONS (tem)->cdr) ! 365: *new_env++ = (char *) XSTRING (XCONS (tem)->car)->data; ! 366: *new_env = 0; ! 367: } ! 368: #endif /* Not MAINTAIN_ENVIRONMENT */ ! 369: ! 370: close (0); ! 371: close (1); ! 372: close (2); ! 373: ! 374: dup2 (in, 0); ! 375: dup2 (out, 1); ! 376: dup2 (err, 2); ! 377: close (in); ! 378: close (out); ! 379: close (err); ! 380: ! 381: #ifdef USG ! 382: #ifndef HAVE_PTYS ! 383: setpgrp (); /* No arguments but equivalent in this case */ ! 384: #endif ! 385: #else ! 386: setpgrp (pid, pid); ! 387: #endif /* USG */ ! 388: setpgrp_of_tty (pid); ! 389: ! 390: #ifdef vipc ! 391: something missing here; ! 392: #endif vipc ! 393: ! 394: /* execvp does not accept an environment arg so the only way ! 395: to pass this environment is to set environ. Our caller ! 396: is responsible for restoring the ambient value of environ. */ ! 397: environ = env; ! 398: execvp (new_argv[0], new_argv); ! 399: ! 400: write (1, "Couldn't exec the program ", 26); ! 401: write (1, new_argv[0], strlen (new_argv[0])); ! 402: _exit (1); ! 403: } ! 404: ! 405: init_callproc () ! 406: { ! 407: register char * sh; ! 408: extern char **environ; ! 409: register char **envp; ! 410: Lisp_Object execdir; ! 411: ! 412: /* Turn PATH_EXEC into a path. `==' is just a string which we know ! 413: will not be the name of an environment variable. */ ! 414: Vexec_path = decode_env_path ("==", PATH_EXEC); ! 415: Vexec_directory = Ffile_name_as_directory (Fcar (Vexec_path)); ! 416: Vexec_path = nconc2 (decode_env_path ("PATH", ""), Vexec_path); ! 417: ! 418: execdir = Fdirectory_file_name (Vexec_directory); ! 419: if (access (XSTRING (execdir)->data, 0) < 0) ! 420: { ! 421: printf ("Warning: executable/documentation dir (%s) does not exist.\n", ! 422: XSTRING (Vexec_directory)->data); ! 423: sleep (2); ! 424: } ! 425: ! 426: sh = (char *) egetenv ("SHELL"); ! 427: Vshell_file_name = build_string (sh ? sh : "/bin/sh"); ! 428: ! 429: #ifndef MAINTAIN_ENVIRONMENT ! 430: /* The equivalent of this operation was done ! 431: in init_environ in environ.c if MAINTAIN_ENVIRONMENT */ ! 432: Vprocess_environment = Qnil; ! 433: #ifndef CANNOT_DUMP ! 434: if (initialized) ! 435: #endif ! 436: for (envp = environ; *envp; envp++) ! 437: Vprocess_environment = Fcons (build_string (*envp), ! 438: Vprocess_environment); ! 439: #endif /* MAINTAIN_ENVIRONMENT */ ! 440: } ! 441: ! 442: syms_of_callproc () ! 443: { ! 444: DEFVAR_LISP ("shell-file-name", &Vshell_file_name, ! 445: "*File name to load inferior shells from.\n\ ! 446: Initialized from the SHELL environment variable."); ! 447: ! 448: DEFVAR_LISP ("exec-path", &Vexec_path, ! 449: "*List of directories to search programs to run in subprocesses.\n\ ! 450: Each element is a string (directory name) or nil (try default directory)."); ! 451: ! 452: DEFVAR_LISP ("exec-directory", &Vexec_directory, ! 453: "Directory that holds programs that come with GNU Emacs,\n\ ! 454: intended for Emacs to invoke."); ! 455: ! 456: #ifndef MAINTAIN_ENVIRONMENT ! 457: DEFVAR_LISP ("process-environment", &Vprocess_environment, ! 458: "List of strings to append to environment of subprocesses that are started.\n\ ! 459: Each string should have the format ENVVARNAME=VALUE."); ! 460: #endif ! 461: ! 462: defsubr (&Scall_process); ! 463: defsubr (&Scall_process_region); ! 464: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.