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