/usr/share/doc/xviewg/examples/notifier/ntfy_pipe.c is in xview-examples 3.2p1.4-28.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | /*
* notify_pipe.c -- fork and set up a pipe to read the IO from the
* forked process. The program to run is specified on the command
* line. The functions notify_set_input_func() and
* notify_set_output_func() are used to install functions which read
* and write to the process' stdin and stdout.
* The program does not use any xview code -- just the notifier.
*/
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <xview/notify.h>
#ifdef SVR4
#include <sys/filio.h>
#endif
Notify_client client1 = (Notify_client)10;
Notify_client client2 = (Notify_client)11;
int pipe_io[2][2]; /* see diagram */
/*
* [0] [1]
* child reads: |========= pipe_io[0] ========| <- parent writes
* pipe_io[0][0] pipe_io[0][1]
*
* parent reads: |========= pipe_io[1] ========| <- child writes
* pipe_io[1][0] pipe_io[1][1]
*
* The parent process reads the output of the child process by reading
* pipe_io[1][0] because the child is writing to pipe_io[1][1].
* The child process gets its input from pipe_io[0][0] because the
* parent writes to pipe_io[0][1]. Thus, one process is reading from
* one end of the pipe while the other is writing at the other end.
*/
main(argc, argv)
char *argv[];
{
Notify_value read_it(), write_it(), sigchldcatcher();
int i, pid;
FILE *fp;
if (!*++argv)
puts("specify a program [w/args]"), exit(1);
pipe(pipe_io[0]); /* set up input pipe */
pipe(pipe_io[1]); /* set up output pipe */
switch (pid = fork()) {
case -1:
close(pipe_io[0][0]);
close(pipe_io[0][1]);
close(pipe_io[1][0]);
close(pipe_io[1][1]);
perror("fork failed");
exit(1);
case 0: /* child */
/* redirect child's stdin (0), stdout (1) and stderr(2) */
dup2(pipe_io[0][0], 0);
dup2(pipe_io[1][1], 1);
dup2(pipe_io[1][1], 2);
#ifdef SVR4
{
struct rlimit rlim;
getrlimit(RLIMIT_NOFILE, &rlim);
for (i = rlim.rlim_cur; i > 2; i--)
(void) close(i);
}
#else
for (i = getdtablesize(); i > 2; i--)
(void) close(i);
#endif
for (i = 0; i < NSIG; i++)
(void) signal(i, SIG_DFL);
execvp(*argv, argv);
if (errno == ENOENT)
printf("%s: command not found.\n", *argv);
else
perror(*argv);
perror("execvp");
_exit(-1);
default: /* parent */
close(pipe_io[0][0]); /* close unused portions of pipes */
close(pipe_io[1][1]);
}
/* when the process outputs data, read it */
notify_set_input_func(client1, read_it, pipe_io[1][0]);
notify_set_wait3_func(client1, sigchldcatcher, pid);
/* wait for user input -- then write data to pipe */
notify_set_input_func(client2, write_it, 0);
notify_set_wait3_func(client2, sigchldcatcher, pid);
notify_start();
}
/*
* callback routine for when there is data on the parent's stdin to
* read. Read it and then write the data to the child process via
* the pipe.
*/
Notify_value
write_it(client, fd)
Notify_client client;
int fd;
{
char buf[BUFSIZ];
int bytes, i;
/* only write to pipe (child's stdin) if user typed anything */
if (ioctl(fd, FIONREAD, &bytes) == -1 || bytes == 0) {
notify_set_input_func(client, NOTIFY_FUNC_NULL, pipe_io[0][1]);
close(pipe_io[0][1]);
} else
while (bytes > 0) {
if ((i = read(fd, buf, sizeof buf)) > 0) {
printf("[Sending %d bytes to pipe (fd=%d)]\n",
i, pipe_io[0][1]);
write(pipe_io[0][1], buf, i);
} else if (i == -1)
break;
bytes -= i;
}
return NOTIFY_DONE;
}
/*
* callback routine for when there is data on the child's stdout to
* read. Read, then write the data to stdout (owned by the parent).
*/
Notify_value
read_it(client, fd)
Notify_client client;
register int fd;
{
char buf[BUFSIZ];
int bytes, i;
if (ioctl(fd, FIONREAD, &bytes) == 0)
while (bytes > 0) {
if ((i = read(fd, buf, sizeof buf)) > 0) {
printf("[Reading %d bytes from pipe (fd=%d)]\n",
i, fd);
(void) write(1, buf, i);
bytes -= i;
}
}
return NOTIFY_DONE;
}
/*
* handle the death of the child. If the process dies, the child
* dies and generates a SIGCHLD signal. Capture it and disable the
* functions that talk to the pipes.
*/
Notify_value
sigchldcatcher(client, pid, status, rusage)
Notify_client client; /* the client noted in main() */
int pid; /* the pid that died */
#ifdef SVR4
int *status;
#else
union wait *status; /* the status of the process (unused here) */
#endif
struct rusage *rusage; /* resources used by this process (unused) */
{
if (WIFEXITED(*status)) {
#ifdef SVR4
printf("Process termined with status %d\n", *status);
#else
printf("Process termined with status %d\n", status->w_retcode);
#endif
/* unregister input func with appropriate file descriptor */
notify_set_input_func(client, NOTIFY_FUNC_NULL,
(client == client1)? pipe_io[1][0] : 0);
return NOTIFY_DONE;
}
puts("SIGCHLD not handled");
return NOTIFY_IGNORED;
}
|