📄 pipe.c
字号:
/* pipe.c - for opening a process as a pipe and reading both stderr and stdout together Copyright (C) 1996-2000 Paul Sheer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include "global.h"#include "pipe-headers.h"#include <my_string.h>#include "pool.h"#include "mad.h"#ifndef _PATH_DEV#define _PATH_DEV "/dev/"#endif#define _PATH_DEV_PTYXX _PATH_DEV "ptyXX"int data_read_ready (int f);int data_read_wait (int f);int data_write_ready (int f);int data_write_wait (int f);pid_t triple_pipe_open (int *in, int *out, int *err, int mix, const char *file, char *const argv[]);char *read_pipe (int fd, int *len);#undef min#define min(x,y) (((x) < (y)) ? (x) : (y))void set_signal_handlers_to_default (void){ signal (SIGHUP, SIG_DFL); signal (SIGQUIT, SIG_DFL); signal (SIGINT, SIG_DFL); signal (SIGTERM, SIG_DFL); signal (SIGABRT, SIG_DFL); signal (SIGCHLD, SIG_DFL); signal (SIGALRM, SIG_IGN);}/* This opens a process as a pipe. 'in', 'out' and 'err' are pointers to file handles which are filled in by popen. 'in' refers to stdin of the process, to which you can write. 'out' and 'err' refer to stdout and stderr of the process from which you can read. 'in', 'out' and 'err' can be passed as NULL if you want to ignore output or input of those pipes. If 'mix' is non-zero, then both stderr and stdout of the process can be read from 'out'. If mix is non-zero, then 'err' must be passed as NULL. Popen forks and then calls execvp (see execvp(3)) --- which must also take argv[0] and args must terminate with a NULL. Returns -1 if the fork failed, and -2 if pipe() failed. Otherwise returns the pid of the child. */pid_t triple_pipe_open (int *in, int *out, int *err, int mix, const char *file, char *const argv[]){ pid_t p; int e; int f0[2], f1[2], f2[2]; e = (pipe (f0) | pipe (f1) | pipe (f2)); if (e) { close (f0[0]); close (f0[1]); close (f1[0]); close (f1[1]); close (f2[0]); close (f2[1]); return -2; } p = fork (); if (p == -1) { close (f0[0]); close (f0[1]); close (f1[0]); close (f1[1]); close (f2[0]); close (f2[1]); return -1; } if (p) { if (in) { *in = f0[1]; } else { close (f0[1]); } if (out) { *out = f1[0]; } else { close (f1[0]); } if (err) { *err = f2[0]; } else { close (f2[0]); } close (f0[0]); close (f1[1]); close (f2[1]); return p; } else { int nulldevice_wr, nulldevice_rd; nulldevice_wr = open ("/dev/null", O_WRONLY); nulldevice_rd = open ("/dev/null", O_RDONLY); close (0); if (in) dup (f0[0]); else dup (nulldevice_rd); close (1); if (out) dup (f1[1]); else dup (nulldevice_wr); close (2); if (err) dup (f2[1]); else { if (mix) dup (f1[1]); else dup (nulldevice_wr); } close (f0[0]); close (f0[1]); close (f1[0]); close (f1[1]); close (f2[0]); close (f2[1]); close (nulldevice_rd); close (nulldevice_wr); set_signal_handlers_to_default (); execvp (file, argv); exit (1); } return 0; /* prevents warning */}#if 0#ifndef HAVE_FORKPTY/* This is stolen from libc-5.4.46 with the intention of having this all still work on systems that do not have the forkpty() function (like non-BSD systems like solaris). No idea if it will actually work on these systems. */static int my_openpty (int *amaster, int *aslave, char *name){ char line[] = _PATH_DEV_PTYXX; const char *p, *q; int master, slave, ttygid; struct group *gr; if ((gr = getgrnam ("tty")) != NULL) ttygid = gr->gr_gid; else ttygid = -1; for (p = "pqrstuvwxyzabcde"; *p; p++) { line[sizeof (_PATH_DEV_PTYXX) - 3] = *p; for (q = "0123456789abcdef"; *q; q++) { line[sizeof (_PATH_DEV_PTYXX) - 2] = *q; if ((master = open (line, O_RDWR, 0)) == -1) { if (errno == ENOENT) return -1; } else { line[sizeof (_PATH_DEV) - 1] = 't'; chown (line, getuid (), ttygid); chmod (line, S_IRUSR | S_IWUSR | S_IWGRP); if ((slave = open (line, O_RDWR, 0)) != -1) { *amaster = master; *aslave = slave; strcpy (name, line); return 0; } close (master); line[sizeof (_PATH_DEV) - 1] = 'p'; } } } errno = ENOENT; return -1;}static int forkpty (int *amaster, char *name,...){ int master, slave; pid_t pid; if (my_openpty (&master, &slave, name) == -1) return -1; switch (pid = fork ()) { case -1: return -1; case 0: close (master);#ifdef HAVE_SETSID pid = setsid ();#define HAVE_PID_THIS_TTY#elif defined (HAVE_SETPGRP) pid = setpgrp (0, 0);#define HAVE_PID_THIS_TTY#endif#ifdef TIOCSCTTY ioctl (slave, TIOCSCTTY, 0);#ifdef HAVE_PID_THIS_TTY#elif defined (HAVE_TCSETPGRP) tcsetpgrp (slave, pid);#elif defined (TIOCSPGRP) ioctl (slave, TIOCSPGRP, &pid);#endif#endif close (0); dup (slave); close (1); dup (slave); close (2); dup (slave); if (slave > 2) close (slave); return 0; } *amaster = master; close (slave); return pid;}#endif /* ! HAVE_FORKPTY */static void set_termios (int fd){#ifdef HAVE_TCGETATTR struct termios tios; memset (&tios, 0, sizeof (tios)); if (tcgetattr (fd, &tios) != 0) return;#ifdef B19200#ifdef OCRNL tios.c_oflag &= ~(ONLCR | OCRNL);#else tios.c_oflag &= ~ONLCR;#endif tios.c_lflag &= ~(ECHO | ICANON | ISIG); tios.c_iflag &= ~(ICRNL);#ifdef VTIME tios.c_cc[VTIME] = 1;#endif#ifdef VMIN tios.c_cc[VMIN] = 1;#endif tios.c_iflag &= ~(ISTRIP);#if defined(TABDLY) && defined(TAB3) if ((tios.c_oflag & TABDLY) == TAB3) tios.c_oflag &= ~TAB3;#endif/* disable interpretation of ^S: */ tios.c_iflag &= ~IXON;#ifdef VDISCARD tios.c_cc[VDISCARD] = 255;#endif#ifdef VEOL2 tios.c_cc[VEOL2] = 255;#endif#ifdef VEOL tios.c_cc[VEOL] = 255;#endif#ifdef VLNEXT tios.c_cc[VLNEXT] = 255;#endif#ifdef VREPRINT tios.c_cc[VREPRINT] = 255;#endif#ifdef VSUSP tios.c_cc[VSUSP] = 255;#endif#ifdef VWERASE tios.c_cc[VWERASE] = 255;#endif tcsetattr (fd, TCSADRAIN, &tios);#endif#endif /* HAVE_TCGETATTR */}pid_t open_under_pty (int *in, int *out, char *line, const char *file, char *const argv[]){ int master = 0; char l[80]; pid_t p;#ifdef HAVE_FORKPTY#ifdef NEED_WINSIZE struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsigned short ws_ypixel; } win;#else struct winsize win;#endif memset (&win, 0, sizeof (win)); p = (pid_t) forkpty (&master, l, NULL, &win);#else p = (pid_t) forkpty (&master, l);#endif if (p == -1) return -1;#if 0 ioctl (master, FIONBIO, &yes); ioctl (master, FIONBIO, &yes);#endif strcpy (line, l); if (p) { *in = dup (master); *out = dup (master); close (master); return p; } set_termios (0); execvp (file, argv); exit (1); return 0;}#endif#define CHUNK 8192/* Reads all available data and mallocs space for it plus one byte, and sets that byte to zero. If len is non-NULL bytes read is placed in len. If *len is passed non-zero then reads that amount max. */char *read_pipe (int fd, int *len){ POOL *p; int c, count = 0; int l = CHUNK; p = pool_init (); if (len) if (*len) if (l > *len) l = *len; for (;;) { if (pool_freespace (p) < l + 1) pool_advance (p, l + 1); do { c = read (fd, pool_current (p), l); } while (c < 0 && errno == EINTR); if (c <= 0) break; count += c; pool_current (p) += c; if (len) if (*len) if (pool_length (p) >= l) break; } pool_null (p); if (len) *len = pool_length (p); return (char *) pool_break (p);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -