1/* detach.c
2   Detach from the controlling terminal.
3
4   Copyright (C) 1992, 1993, 1995 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#include "uudefs.h"
28#include "system.h"
29#include "sysdep.h"
30
31#include <errno.h>
32
33#if HAVE_SYS_IOCTL_H
34#include <sys/ioctl.h>
35#endif
36
37#ifdef TIOCNOTTY
38#define HAVE_TIOCNOTTY 1
39#else
40#define HAVE_TIOCNOTTY 0
41#endif
42
43#if HAVE_FCNTL_H
44#include <fcntl.h>
45#else
46#if HAVE_SYS_FILE_H
47#include <sys/file.h>
48#endif
49#endif
50
51#ifndef O_RDONLY
52#define O_RDONLY 0
53#define O_WRONLY 1
54#define O_RDWR 2
55#endif
56
57#if HAVE_BROKEN_SETSID
58#undef HAVE_SETSID
59#define HAVE_SETSID 0
60#endif
61
62/* Detach from the controlling terminal.  This is called by uucico if
63   it is calling out to another system, so that it can receive SIGHUP
64   signals from the port it calls out on.  It is also called by uucico
65   just before it starts uuxqt, so that uuxqt is completely
66   independent of the terminal.  */
67
68void
69usysdep_detach ()
70{
71  pid_t igrp;
72
73  /* Make sure that we can open the log file.  We do this now so that,
74     if we can't, a message will be written to stderr.  After we leave
75     this routine, stderr will be closed.  */
76  ulog (LOG_NORMAL, (const char *) NULL);
77
78  /* Make sure we are not a process group leader.  */
79#if HAVE_BSD_PGRP
80  igrp = getpgrp (0);
81#else
82  igrp = getpgrp ();
83#endif
84
85  if (igrp == getpid ())
86    {
87      boolean fignored;
88      pid_t ipid;
89
90      /* Ignore SIGHUP, since our process group leader is about to
91	 die.  */
92      usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored);
93
94      ipid = ixsfork ();
95      if (ipid < 0)
96	ulog (LOG_FATAL, "fork: %s", strerror (errno));
97
98      if (ipid != 0)
99	_exit (EXIT_SUCCESS);
100
101      /* We'll always wind up as a child of process number 1, right?
102	 Right?  We have to wait for our parent to die before
103	 reenabling SIGHUP.  */
104      while (getppid () != 1)
105	sleep (1);
106
107      ipid = getpid ();
108      ulog_id (ipid);
109
110      /* Restore SIGHUP catcher if it wasn't being ignored.  */
111      if (! fignored)
112	usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
113
114      DEBUG_MESSAGE2 (DEBUG_PORT,
115		      "usysdep_detach: Forked; old PID %ld, new pid %ld",
116		      (long) igrp, (long) ipid);
117    }
118
119#if ! HAVE_SETSID && HAVE_TIOCNOTTY
120  /* Lose the original controlling terminal as well as our process
121     group.  */
122  {
123    int o;
124
125    o = open ((char *) "/dev/tty", O_RDONLY);
126    if (o >= 0)
127      {
128	(void) ioctl (o, TIOCNOTTY, (char *) NULL);
129	(void) close (o);
130      }
131  }
132#endif /* ! HAVE_SETSID && HAVE_TIOCNOTTY */
133
134  /* Close stdin, stdout and stderr and reopen them on /dev/null, to
135     make sure we have no connection at all to the terminal.  */
136  (void) close (0);
137  (void) close (1);
138  (void) close (2);
139  if (open ((char *) "/dev/null", O_RDONLY) != 0
140      || open ((char *) "/dev/null", O_WRONLY) != 1
141      || open ((char *) "/dev/null", O_WRONLY) != 2)
142    ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno));
143
144#if HAVE_SETSID
145
146  /* Under POSIX the setsid call creates a new session for which we
147     are the process group leader.  It also detaches us from our
148     controlling terminal.  */
149  if (setsid () < 0)
150    ulog (LOG_ERROR, "setsid: %s", strerror (errno));
151
152#else /* ! HAVE_SETSID */
153
154#if ! HAVE_SETPGRP
155 #error Cannot detach from controlling terminal
156#endif
157
158  /* If we don't have setsid, we must use setpgrp.  On an old System V
159     system setpgrp will make us the leader of a new process group and
160     detach the controlling terminal.  On an old BSD system the call
161     setpgrp (0, 0) will set our process group to 0 so that we can
162     acquire a new controlling terminal (TIOCNOTTY may or may not have
163     already done that anyhow).  */
164#if HAVE_BSD_PGRP
165  if (setpgrp (0, 0) < 0)
166#else
167  if (setpgrp () < 0)
168#endif
169    {
170      /* Some systems seem to give EPERM errors inappropriately.  */
171      if (errno != EPERM)
172	ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
173    }
174
175#endif /* ! HAVE_SETSID */
176
177  /* At this point we have completely detached from our controlling
178     terminal.  The next terminal device we open will probably become
179     our controlling terminal.  */
180}
181