1/* pipe.c
2   The pipe port communication routines for Unix.
3   Contributed by Marc Boucher <marc@CAM.ORG>.
4
5   Copyright (C) 1993, 2002 Ian Lance Taylor
6
7   This file is part of the Taylor UUCP package.
8
9   This program is free software; you can redistribute it and/or
10   modify it under the terms of the GNU General Public License as
11   published by the Free Software Foundation; either version 2 of the
12   License, or (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
22
23   The author of the program may be contacted at ian@airs.com.
24   */
25
26#include "uucp.h"
27
28#if USE_RCS_ID
29const char pipe_rcsid[] = "$Id: pipe.c,v 1.10 2002/03/05 19:10:42 ian Rel $";
30#endif
31
32#include "uudefs.h"
33#include "uuconf.h"
34#include "system.h"
35#include "conn.h"
36#include "sysdep.h"
37
38#include <errno.h>
39
40#if HAVE_FCNTL_H
41#include <fcntl.h>
42#else
43#if HAVE_SYS_FILE_H
44#include <sys/file.h>
45#endif
46#endif
47
48/* Local functions.  */
49
50static void uspipe_free P((struct sconnection *qconn));
51static boolean fspipe_open P((struct sconnection *qconn, long ibaud,
52			      boolean fwait, boolean fuser));
53static boolean fspipe_close P((struct sconnection *qconn,
54			       pointer puuconf,
55			       struct uuconf_dialer *qdialer,
56			       boolean fsuccess));
57static boolean fspipe_dial P((struct sconnection *qconn, pointer puuconf,
58			      const struct uuconf_system *qsys,
59			      const char *zphone,
60			      struct uuconf_dialer *qdialer,
61			      enum tdialerfound *ptdialer));
62
63/* The command table for standard input ports.  */
64
65static const struct sconncmds spipecmds =
66{
67  uspipe_free,
68  NULL, /* pflock */
69  NULL, /* pfunlock */
70  fspipe_open,
71  fspipe_close,
72  fspipe_dial,
73  fsdouble_read,
74  fsdouble_write,
75  fsysdep_conn_io,
76  NULL, /* pfbreak */
77  NULL, /* pfset */
78  NULL, /* pfcarrier */
79  fsdouble_chat,
80  NULL  /* pibaud */
81};
82
83/* Initialize a pipe connection.  */
84
85boolean
86fsysdep_pipe_init (qconn)
87     struct sconnection *qconn;
88{
89  struct ssysdep_conn *q;
90
91  q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
92  q->o = -1;
93  q->ord = -1;
94  q->owr = -1;
95  q->zdevice = NULL;
96  q->iflags = -1;
97  q->iwr_flags = -1;
98  q->fterminal = FALSE;
99  q->ftli = FALSE;
100  q->ibaud = 0;
101  q->ipid = -1;
102  qconn->psysdep = (pointer) q;
103  qconn->qcmds = &spipecmds;
104  return TRUE;
105}
106
107static void
108uspipe_free (qconn)
109     struct sconnection *qconn;
110{
111  xfree (qconn->psysdep);
112}
113
114/* Open a pipe port.  */
115
116/*ARGSUSED*/
117static boolean
118fspipe_open (qconn, ibaud, fwait, fuser)
119     struct sconnection *qconn ATTRIBUTE_UNUSED;
120     long ibaud ATTRIBUTE_UNUSED;
121     boolean fwait;
122     boolean fuser ATTRIBUTE_UNUSED;
123{
124  /* We don't do incoming waits on pipes.  */
125  if (fwait)
126    return FALSE;
127
128  return TRUE;
129}
130
131/* Close a pipe port.  */
132
133/*ARGSUSED*/
134static boolean
135fspipe_close (qconn, puuconf, qdialer, fsuccess)
136     struct sconnection *qconn;
137     pointer puuconf ATTRIBUTE_UNUSED;
138     struct uuconf_dialer *qdialer ATTRIBUTE_UNUSED;
139     boolean fsuccess ATTRIBUTE_UNUSED;
140{
141  struct ssysdep_conn *qsysdep;
142  boolean fret;
143
144  qsysdep = (struct ssysdep_conn *) qconn->psysdep;
145  fret = TRUE;
146
147  /* Close our sides of the pipe.  */
148  if (qsysdep->ord >= 0 && close (qsysdep->ord) < 0)
149    {
150      ulog (LOG_ERROR, "fspipe_close: close read fd: %s", strerror (errno));
151      fret = FALSE;
152    }
153  if (qsysdep->owr != qsysdep->ord
154      && qsysdep->owr >= 0
155      && close (qsysdep->owr) < 0)
156    {
157      ulog (LOG_ERROR, "fspipe_close: close write fd: %s", strerror (errno));
158      fret = FALSE;
159    }
160  qsysdep->ord = -1;
161  qsysdep->owr = -1;
162
163  /* Kill dangling child process.  */
164  if (qsysdep->ipid >= 0)
165    {
166      if (kill (qsysdep->ipid, SIGHUP) == 0)
167        usysdep_sleep (2);
168#ifdef SIGPIPE
169      if (kill (qsysdep->ipid, SIGPIPE) == 0)
170        usysdep_sleep (2);
171#endif
172      if (kill (qsysdep->ipid, SIGKILL) < 0 && errno == EPERM)
173	{
174	  ulog (LOG_ERROR, "fspipe_close: Cannot kill child pid %lu: %s",
175		(unsigned long) qsysdep->ipid, strerror (errno));
176	  fret = FALSE;
177	}
178      else
179	(void) ixswait ((unsigned long) qsysdep->ipid, (const char *) NULL);
180    }
181  qsysdep->ipid = -1;
182  return fret;
183}
184
185/* Dial out on a pipe port, so to speak: launch connection program
186   under us.  The code alternates q->o between q->ord and q->owr as
187   appropriate.  It is always q->ord before any call to fsblock.  */
188
189/*ARGSUSED*/
190static boolean
191fspipe_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
192     struct sconnection *qconn;
193     pointer puuconf;
194     const struct uuconf_system *qsys ATTRIBUTE_UNUSED;
195     const char *zphone ATTRIBUTE_UNUSED;
196     struct uuconf_dialer *qdialer;
197     enum tdialerfound *ptdialer;
198{
199  struct ssysdep_conn *q;
200  int aidescs[3];
201  const char **pzprog;
202
203  q = (struct ssysdep_conn *) qconn->psysdep;
204
205  *ptdialer = DIALERFOUND_FALSE;
206
207  pzprog = (const char **) qconn->qport->uuconf_u.uuconf_spipe.uuconf_pzcmd;
208
209  if (pzprog == NULL)
210    {
211      ulog (LOG_ERROR, "No command for pipe connection");
212      return FALSE;
213    }
214
215  aidescs[0] = SPAWN_WRITE_PIPE;
216  aidescs[1] = SPAWN_READ_PIPE;
217  aidescs[2] = SPAWN_NULL;
218
219  /* Pass fkeepuid, fkeepenv and fshell as TRUE.  This puts the
220     responsibility of security on the connection program.  */
221  q->ipid = ixsspawn (pzprog, aidescs, TRUE, TRUE, (const char *) NULL,
222		      FALSE, TRUE, (const char *) NULL,
223		      (const char *) NULL, (const char *) NULL);
224  if (q->ipid < 0)
225    {
226      ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
227      return FALSE;
228    }
229
230  q->owr = aidescs[0];
231  q->ord = aidescs[1];
232  q->o = q->ord;
233
234  q->iflags = fcntl (q->ord, F_GETFL, 0);
235  q->iwr_flags = fcntl (q->owr, F_GETFL, 0);
236  if (q->iflags < 0 || q->iwr_flags < 0)
237    {
238      ulog (LOG_ERROR, "fspipe_dial: fcntl: %s", strerror (errno));
239      (void) fspipe_close (qconn, puuconf, qdialer, FALSE);
240      return FALSE;
241    }
242
243  return TRUE;
244}
245
246#if 0
247
248/* Marc Boucher's contributed code used an alarm to avoid waiting too
249   long when closing the pipe.  However, I believe that it is not
250   possible for the kernel to sleep when closing a pipe; it is only
251   possible when closing a device.  Therefore, I have removed the
252   code, but am preserving it in case I am wrong.  To reenable it, the
253   two calls to close in fspipe_close should be changed to call
254   fspipe_alarmclose.  */
255
256static RETSIGTYPE
257usalarm (isig)
258     int isig;
259{
260#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
261  (void) signal (isig, usalarm);
262#endif
263
264#if HAVE_RESTARTABLE_SYSCALLS
265  longjmp (sSjmp_buf, 1);
266#endif
267}
268
269static int
270fspipe_alarmclose (fd)
271     int fd;
272{
273  int iret = -1;
274  int ierrno = 0;
275
276  if (fsysdep_catch ())
277    {
278      usysdep_start_catch ();
279      usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
280      (void) alarm (30);
281
282      iret = close (fd);
283      ierrno = errno;
284    }
285
286  usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
287  (void) alarm (0);
288  usysdep_end_catch ();
289
290  errno = ierrno;
291  return iret;
292}
293
294#endif /* 0 */
295