From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Stef Van Vlierberghe Newsgroups: gmane.emacs.devel Subject: Re: [rms@gnu.org: Re: [twurgler@goodyear.com: emacs-21.2.90 on HP 11.0]] Date: Fri, 12 Jul 2002 23:52:13 +0200 Sender: emacs-devel-admin@gnu.org Message-ID: <15663.20365.981234.89762@raven.sup.cfmu.eurocontrol.be> References: <5983E4DAC939D311B2F20008C7E62E7A075D2365@clsh01xch.office.cfmu.eurocontrol.be> <200207121112.g6CBCZr18311@aztec.santafe.edu> Reply-To: Stef.Van-Vlierberghe@eurocontrol.int NNTP-Posting-Host: localhost.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Trace: main.gmane.org 1026510768 32279 127.0.0.1 (12 Jul 2002 21:52:48 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Fri, 12 Jul 2002 21:52:48 +0000 (UTC) Cc: philippe.waroquiers@eurocontrol.int, twurgler@goodyear.com, emacs-devel@gnu.org, stef.van-vlierberghe@eurocontrol.int Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by main.gmane.org with esmtp (Exim 3.33 #1 (Debian)) id 17T8LH-0008OW-00 for ; Fri, 12 Jul 2002 23:52:47 +0200 Original-Received: from fencepost.gnu.org ([199.232.76.164]) by quimby.gnus.org with esmtp (Exim 3.12 #1 (Debian)) id 17T8VK-0004LR-00 for ; Sat, 13 Jul 2002 00:03:11 +0200 Original-Received: from localhost ([127.0.0.1] helo=fencepost.gnu.org) by fencepost.gnu.org with esmtp (Exim 3.35 #1 (Debian)) id 17T8Lj-00033L-00; Fri, 12 Jul 2002 17:53:15 -0400 Original-Received: from out01b.e-scan.net ([193.123.92.197]) by fencepost.gnu.org with esmtp (Exim 3.35 #1 (Debian)) id 17T8Kp-000302-00; Fri, 12 Jul 2002 17:52:20 -0400 Original-Received: from biscuit.eurocontrol.be (unverified) by out01b.e-scan.net (Content Technologies SMTPRS 4.2.10) with ESMTP id ; Fri, 12 Jul 2002 21:52:23 +0000 Original-Received: from CLSH01XCH.sup.cfmu.eurocontrol.be ([193.58.25.63]) by biscuit.eurocontrol.be (8.9.3 (PHNE_18546)/8.9.3) with ESMTP id XAA26026; Fri, 12 Jul 2002 23:52:16 +0200 (METDST) Original-Received: from raven.sup.cfmu.eurocontrol.be ([193.221.188.78]) by CLSH01XCH.sup.cfmu.eurocontrol.be with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2653.13) id 3DT4BP48; Fri, 12 Jul 2002 23:52:14 +0200 Original-Received: (from vvl@localhost) by raven.sup.cfmu.eurocontrol.be (8.8.6 (PHNE_17190)/8.8.6) id XAA21420; Fri, 12 Jul 2002 23:52:14 +0200 (METDST) Original-To: rms@gnu.org In-Reply-To: <200207121112.g6CBCZr18311@aztec.santafe.edu> X-Mailer: VM 7.00 under Emacs 21.1.2 Errors-To: emacs-devel-admin@gnu.org X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.0.11 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: Xref: main.gmane.org gmane.emacs.devel:5728 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:5728 Richard Stallman writes: > On hp-ux, ioctl TIOCGPGRP always fails with errno ENOTTY (this is normal, > explained in the USG part of create_process). > > I cannot find that explanation, and I am not sure what "the USG part > of create_process" refers to. Would you please show me the specific > code you mean? I'm trying to understand this. In particular, > I wonder why this code > > if (!NILP (p->subtty)) > err = ioctl (XFASTINT (p->subtty), TIOCGPGRP, &gid); > > does not get the right value. > > Does err get set to -1 when the ioctl fails? Below you will find the source code of create_process, where I have put a !!! in front of the lines that are executed in create_process when we use M-x shell (I'm a big fan of the emacs macro's and the gdb-mode). This explains how we have NILP (p->subtty), and hence the 'else' part of the 'if' you mentioned above is of interest : else err = ioctl (XINT (p->infd), TIOCGPGRP, &gid); Here err is returned -1 and errno is 25=ENOTTY, which makes sense because p->infd was set to inchannel, which is a PTY returned from allocate_pty (); (I thought a pty and a tty were like two ends of the same comms channel, but I guess this difference matters for the ioctl). This failure passes by unnoticed, because the err is not tested (unless if this #ifdef pfa kicks in, which does such a test and might already have worked around the same problem in a very awkward way). So, if the uninitialized gid is initially -1, then the error is discovered accidentally, no_pgrp = 1;, and this leads us to the kill (XFASTINT (p->pid), signo);, which send the signal to the shell, which does not interrupt the cat. If the uninitialized gid is initially 1, then the error is not discovered, gid is then set to -1 but that won't matter anymore, and we get to ioctl (XINT (p->infd), TIOCSIGSEND, signo); which does indeed kill the cat. Conclusion : setting gid initially to 1 is a workaround for us, but the way it works is major voodoo. P.S. neither of us understood what a USG system is, why HP is one, and why somebody believes HP can't have a pty/tty creation during a fork()/exec() construct, surely a program like xterm must accomplish this. Best regards. ============================================================= void create_process (process, new_argv, current_dir) Lisp_Object process; char **new_argv; Lisp_Object current_dir; { int pid, inchannel, outchannel; int sv[2]; #ifdef POSIX_SIGNALS sigset_t procmask; sigset_t blocked; struct sigaction sigint_action; struct sigaction sigquit_action; #ifdef AIX struct sigaction sighup_action; #endif #else /* !POSIX_SIGNALS */ #if 0 #ifdef SIGCHLD SIGTYPE (*sigchld)(); #endif #endif /* 0 */ #endif /* !POSIX_SIGNALS */ /* Use volatile to protect variables from being clobbered by longjmp. */ volatile int forkin, forkout; !!! volatile int pty_flag = 0; #ifndef USE_CRT_DLL extern char **environ; #endif !!! Lisp_Object buffer = XPROCESS (process)->buffer; !!! inchannel = outchannel = -1; #ifdef HAVE_PTYS !!! if (!NILP (Vprocess_connection_type)) !!! outchannel = inchannel = allocate_pty (); !!! if (inchannel >= 0) { #ifndef USG /* On USG systems it does not work to open the pty's tty here and then close and reopen it in the child. */ #ifdef O_NOCTTY /* Don't let this terminal become our controlling terminal (in case we don't have one). */ forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); #else forkout = forkin = emacs_open (pty_name, O_RDWR, 0); #endif if (forkin < 0) report_file_error ("Opening pty", Qnil); #else !!! forkin = forkout = -1; #endif /* not USG */ !!! pty_flag = 1; } else #endif /* HAVE_PTYS */ #ifdef SKTPAIR { if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0) report_file_error ("Opening socketpair", Qnil); outchannel = inchannel = sv[0]; forkout = forkin = sv[1]; } #else /* not SKTPAIR */ { int tem; tem = pipe (sv); if (tem < 0) report_file_error ("Creating pipe", Qnil); inchannel = sv[0]; forkout = sv[1]; tem = pipe (sv); if (tem < 0) { emacs_close (inchannel); emacs_close (forkout); report_file_error ("Creating pipe", Qnil); } outchannel = sv[1]; forkin = sv[0]; } #endif /* not SKTPAIR */ #if 0 /* Replaced by close_process_descs */ set_exclusive_use (inchannel); set_exclusive_use (outchannel); #endif /* Stride people say it's a mystery why this is needed as well as the O_NDELAY, but that it fails without this. */ #if defined (STRIDE) || (defined (pfa) && defined (HAVE_PTYS)) { int one = 1; ioctl (inchannel, FIONBIO, &one); } #endif #ifdef O_NONBLOCK !!! fcntl (inchannel, F_SETFL, O_NONBLOCK); !!! fcntl (outchannel, F_SETFL, O_NONBLOCK); #else #ifdef O_NDELAY fcntl (inchannel, F_SETFL, O_NDELAY); fcntl (outchannel, F_SETFL, O_NDELAY); #endif #endif /* Record this as an active process, with its channels. As a result, child_setup will close Emacs's side of the pipes. */ !!! chan_process[inchannel] = process; !!! XSETINT (XPROCESS (process)->infd, inchannel); !!! XSETINT (XPROCESS (process)->outfd, outchannel); /* Record the tty descriptor used in the subprocess. */ !!! if (forkin < 0) !!! XPROCESS (process)->subtty = Qnil; else XSETFASTINT (XPROCESS (process)->subtty, forkin); !!! XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil); !!! XPROCESS (process)->status = Qrun; !!! if (!proc_decode_coding_system[inchannel]) !!! proc_decode_coding_system[inchannel] = (struct coding_system *) xmalloc (sizeof (struct coding_system)); !!! setup_coding_system (XPROCESS (process)->decode_coding_system, proc_decode_coding_system[inchannel]); !!! if (!proc_encode_coding_system[outchannel]) !!! proc_encode_coding_system[outchannel] = (struct coding_system *) xmalloc (sizeof (struct coding_system)); !!! setup_coding_system (XPROCESS (process)->encode_coding_system, proc_encode_coding_system[outchannel]); /* Delay interrupts until we have a chance to store the new fork's pid in its process structure */ #ifdef POSIX_SIGNALS !!! sigemptyset (&blocked); #ifdef SIGCHLD !!! sigaddset (&blocked, SIGCHLD); #endif #ifdef HAVE_VFORK /* On many hosts (e.g. Solaris 2.4), if a vforked child calls `signal', this sets the parent's signal handlers as well as the child's. So delay all interrupts whose handlers the child might munge, and record the current handlers so they can be restored later. */ sigaddset (&blocked, SIGINT ); sigaction (SIGINT , 0, &sigint_action ); sigaddset (&blocked, SIGQUIT); sigaction (SIGQUIT, 0, &sigquit_action); #ifdef AIX sigaddset (&blocked, SIGHUP ); sigaction (SIGHUP , 0, &sighup_action ); #endif #endif /* HAVE_VFORK */ !!! sigprocmask (SIG_BLOCK, &blocked, &procmask); #else /* !POSIX_SIGNALS */ #ifdef SIGCHLD #ifdef BSD4_1 sighold (SIGCHLD); #else /* not BSD4_1 */ #if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX) sigsetmask (sigmask (SIGCHLD)); #else /* ordinary USG */ #if 0 sigchld_deferred = 0; sigchld = signal (SIGCHLD, create_process_sigchld); #endif #endif /* ordinary USG */ #endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ !!! FD_SET (inchannel, &input_wait_mask); !!! FD_SET (inchannel, &non_keyboard_wait_mask); !!! if (inchannel > max_process_desc) !!! max_process_desc = inchannel; /* Until we store the proper pid, enable sigchld_handler to recognize an unknown pid as standing for this process. It is very important not to let this `marker' value stay in the table after this function has returned; if it does it might cause call-process to hang and subsequent asynchronous processes to get their return values scrambled. */ !!! XSETINT (XPROCESS (process)->pid, -1); !!! BLOCK_INPUT; { /* child_setup must clobber environ on systems with true vfork. Protect it from permanent change. */ !!! char **save_environ = environ; !!! current_dir = ENCODE_FILE (current_dir); #ifndef WINDOWSNT !!! pid = vfork (); !!! if (pid == 0) #endif /* not WINDOWSNT */ { int xforkin = forkin; int xforkout = forkout; #if 0 /* This was probably a mistake--it duplicates code later on, but fails to handle all the cases. */ /* Make sure SIGCHLD is not blocked in the child. */ sigsetmask (SIGEMPTYMASK); #endif /* Make the pty be the controlling terminal of the process. */ #ifdef HAVE_PTYS /* First, disconnect its current controlling terminal. */ #ifdef HAVE_SETSID /* We tried doing setsid only if pty_flag, but it caused process_set_signal to fail on SGI when using a pipe. */ setsid (); /* Make the pty's terminal the controlling terminal. */ if (pty_flag) { #ifdef TIOCSCTTY /* We ignore the return value because faith@cs.unc.edu says that is necessary on Linux. */ ioctl (xforkin, TIOCSCTTY, 0); #endif } #else /* not HAVE_SETSID */ #ifdef USG /* It's very important to call setpgrp here and no time afterwards. Otherwise, we lose our controlling tty which is set when we open the pty. */ setpgrp (); #endif /* USG */ #endif /* not HAVE_SETSID */ #if defined (HAVE_TERMIOS) && defined (LDISC1) if (pty_flag && xforkin >= 0) { struct termios t; tcgetattr (xforkin, &t); t.c_lflag = LDISC1; if (tcsetattr (xforkin, TCSANOW, &t) < 0) emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39); } #else #if defined (NTTYDISC) && defined (TIOCSETD) if (pty_flag && xforkin >= 0) { /* Use new line discipline. */ int ldisc = NTTYDISC; ioctl (xforkin, TIOCSETD, &ldisc); } #endif #endif #ifdef TIOCNOTTY /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you can do TIOCSPGRP only to the process's controlling tty. */ if (pty_flag) { /* I wonder: would just ioctl (0, TIOCNOTTY, 0) work here? I can't test it since I don't have 4.3. */ int j = emacs_open ("/dev/tty", O_RDWR, 0); ioctl (j, TIOCNOTTY, 0); emacs_close (j); #ifndef USG /* In order to get a controlling terminal on some versions of BSD, it is necessary to put the process in pgrp 0 before it opens the terminal. */ #ifdef HAVE_SETPGID setpgid (0, 0); #else setpgrp (0, 0); #endif #endif } #endif /* TIOCNOTTY */ #if !defined (RTU) && !defined (UNIPLUS) && !defined (DONT_REOPEN_PTY) /*** There is a suggestion that this ought to be a conditional on TIOCSPGRP, or !(defined (HAVE_SETSID) && defined (TIOCSCTTY)). Trying the latter gave the wrong results on Debian GNU/Linux 1.1; that system does seem to need this code, even though both HAVE_SETSID and TIOCSCTTY are defined. */ /* Now close the pty (if we had it open) and reopen it. This makes the pty the controlling terminal of the subprocess. */ if (pty_flag) { #ifdef SET_CHILD_PTY_PGRP int pgrp = getpid (); #endif /* I wonder if emacs_close (emacs_open (pty_name, ...)) would work? */ if (xforkin >= 0) emacs_close (xforkin); xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0); if (xforkin < 0) { emacs_write (1, "Couldn't open the pty terminal ", 31); emacs_write (1, pty_name, strlen (pty_name)); emacs_write (1, "\n", 1); _exit (1); } #ifdef SET_CHILD_PTY_PGRP ioctl (xforkin, TIOCSPGRP, &pgrp); ioctl (xforkout, TIOCSPGRP, &pgrp); #endif } #endif /* not UNIPLUS and not RTU and not DONT_REOPEN_PTY */ #ifdef SETUP_SLAVE_PTY if (pty_flag) { SETUP_SLAVE_PTY; } #endif /* SETUP_SLAVE_PTY */ #ifdef AIX /* On AIX, we've disabled SIGHUP above once we start a child on a pty. Now reenable it in the child, so it will die when we want it to. */ if (pty_flag) signal (SIGHUP, SIG_DFL); #endif #endif /* HAVE_PTYS */ signal (SIGINT, SIG_DFL); signal (SIGQUIT, SIG_DFL); /* Stop blocking signals in the child. */ #ifdef POSIX_SIGNALS sigprocmask (SIG_SETMASK, &procmask, 0); #else /* !POSIX_SIGNALS */ #ifdef SIGCHLD #ifdef BSD4_1 sigrelse (SIGCHLD); #else /* not BSD4_1 */ #if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX) sigsetmask (SIGEMPTYMASK); #else /* ordinary USG */ #if 0 signal (SIGCHLD, sigchld); #endif #endif /* ordinary USG */ #endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ if (pty_flag) child_setup_tty (xforkout); #ifdef WINDOWSNT pid = child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir); #else /* not WINDOWSNT */ child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir); #endif /* not WINDOWSNT */ } !!! environ = save_environ; } !!! UNBLOCK_INPUT; /* This runs in the Emacs process. */ !!! if (pid < 0) { if (forkin >= 0) emacs_close (forkin); if (forkin != forkout && forkout >= 0) emacs_close (forkout); } else { /* vfork succeeded. */ !!! XSETFASTINT (XPROCESS (process)->pid, pid); #ifdef WINDOWSNT register_child (pid, inchannel); #endif /* WINDOWSNT */ /* If the subfork execv fails, and it exits, this close hangs. I don't know why. So have an interrupt jar it loose. */ { struct atimer *timer; EMACS_TIME offset; !!! stop_polling (); !!! EMACS_SET_SECS_USECS (offset, 1, 0); !!! timer = start_atimer (ATIMER_RELATIVE, offset, create_process_1, 0); !!! XPROCESS (process)->subtty = Qnil; !!! if (forkin >= 0) emacs_close (forkin); !!! cancel_atimer (timer); !!! start_polling (); } !!! if (forkin != forkout && forkout >= 0) emacs_close (forkout); #ifdef HAVE_PTYS !!! if (pty_flag) !!! XPROCESS (process)->tty_name = build_string (pty_name); else #endif XPROCESS (process)->tty_name = Qnil; } /* Restore the signal state whether vfork succeeded or not. (We will signal an error, below, if it failed.) */ #ifdef POSIX_SIGNALS #ifdef HAVE_VFORK /* Restore the parent's signal handlers. */ sigaction (SIGINT, &sigint_action, 0); sigaction (SIGQUIT, &sigquit_action, 0); #ifdef AIX sigaction (SIGHUP, &sighup_action, 0); #endif #endif /* HAVE_VFORK */ /* Stop blocking signals in the parent. */ !!! sigprocmask (SIG_SETMASK, &procmask, 0); #else /* !POSIX_SIGNALS */ #ifdef SIGCHLD #ifdef BSD4_1 sigrelse (SIGCHLD); #else /* not BSD4_1 */ #if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX) sigsetmask (SIGEMPTYMASK); #else /* ordinary USG */ #if 0 signal (SIGCHLD, sigchld); /* Now really handle any of these signals that came in during this function. */ if (sigchld_deferred) kill (getpid (), SIGCHLD); #endif #endif /* ordinary USG */ #endif /* not BSD4_1 */ #endif /* SIGCHLD */ #endif /* !POSIX_SIGNALS */ /* Now generate the error if vfork failed. */ !!! if (pid < 0) -- Stef Van Vlierberghe Eurocontrol - CFMU room 20115 stef.van-vlierberghe@eurocontrol.int Raketstraat 96 Tel: +32 2 729 97 32 B-1130 BRUSSELS Fax: +32 2 729 90 22 Belgium