home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-08-21 | 43.9 KB | 1,788 lines |
- Path: sparky!uunet!usc!sol.ctr.columbia.edu!ursa!buzz
- From: buzz@toxicavenger.bear.com (Buzz Moschetti)
- Newsgroups: comp.windows.open-look
- Subject: Re: Redirecting stdout/stderr: A SOLUTION Part01/01
- Message-ID: <BUZZ.92Aug21133203@toxicavenger.bear.com>
- Date: 21 Aug 92 17:32:03 GMT
- References: <1992Aug21.152603.17253@bmw.mayo.edu>
- Sender: news@ursa.UUCP
- Reply-To: buzz@fsrg.bear.com
- Organization: Bear, Stearns & Co. Inc.
- Lines: 1774
- In-reply-to: vdp@mayo.edu's message of 21 Aug 92 15:26:03 GMT
-
- Anyone concerned with running child programs from within an Xview app and
- properly managing stdout, stderr, the death of the child, and reclaiming
- file descriptor and other resources should take this shar and review xrun.c.
- Two other C sources are supplied to provide the xrun package with two
- different front-ends: xcmd, the GUI command executor and cmd, the
- Notifier-based but *not* windows dependent version of the same.
-
- All this has been tested and runs fine on SunOS 4.1.1 with OW3.0. The xcmd
- UI was built with Devguide 3.0.
-
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 1)."
- # Contents: Makefile cmd.c xcmd.G xcmd.c xcmd.h xcmd_ui.c xcmd_ui.h
- # xrun.c xrun.h
- # Wrapped by buzz@toxicavenger on Thu Aug 20 08:53:51 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(1592 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# This file was generated by `gxv' from `xcmd.G'.
- X
- X# Parameters.
- X
- XPROGRAM = xcmd
- XSOURCES.c = xcmd.c xrun.c
- XSOURCES.h =
- XSOURCES.G = xcmd.G
- XSTUBS.G =
- X
- X# Derived parameters.
- X
- XSOURCES = \
- X $(SOURCES.G) \
- X $(SOURCES.h) \
- X $(SOURCES.l) \
- X $(SOURCES.y) \
- X $(SOURCES.cps) \
- X $(SOURCES.c)
- X
- XTARGETS.c = \
- X $(SOURCES.G:%.G=%_ui.c) \
- X $(STUBS.G:%.G=%_stubs.c)
- X
- XTARGETS.h = \
- X $(SOURCES.G:%.G=%_ui.h) \
- X $(SOURCES.l:%.l=%.h) \
- X $(SOURCES.y:%.y=%.h) \
- X $(SOURCES.cps:%.cps=%.h)
- X
- XTARGETS.other = \
- X $(SOURCES.G:%.G=%.info)
- X
- XTARGETS = \
- X $(TARGETS.other) \
- X $(TARGETS.h) \
- X $(TARGETS.c)
- X
- XOBJECTS = \
- X $(SOURCES.c:%.c=%.o) \
- X $(TARGETS.c:%.c=%.o)
- X
- X# Compiler flags.
- X
- XCFLAGS += -g
- XCPPFLAGS += -I$(GUIDEHOME)/include -I$(OPENWINHOME)/include -DMAIN -I.
- XLDFLAGS += -L$(GUIDEHOME)/lib -L$(OPENWINHOME)/lib
- XLDLIBS += -lguidexv -lguide -lxview -lolgx -lX11
- X
- X# Standard targets.
- X
- Xall: $(TARGETS.other) $(PROGRAM)
- Xobjects: $(SOURCES.c) $(TARGETS.c) $(TARGETS.h) $(OBJECTS)
- Xsources: $(SOURCES)
- Xtargets: $(SOURCES) $(TARGETS)
- X
- X$(PROGRAM): $(SOURCES.c) $(TARGETS.c) $(TARGETS.h) $(OBJECTS)
- X $(LINK.c) -o $@ $(OBJECTS) $(LDLIBS)
- X
- Xlint:
- X lint $(CPPFLAGS) $(SOURCES.c)
- X
- X# Targets to be used by Saber-C.
- X
- Xsaber_src:
- X #load $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) \
- X $(SOURCES.c) $(TARGETS.c) $(LDLIBS)
- X
- Xsaber_obj:
- X #load $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $(OBJECTS) $(LDLIBS)
- X
- Xclean:
- X $(RM) $(SOURCES.G:%.G=%_ui.c) $(TARGETS.other) $(TARGETS.h) $(OBJECTS) *.BAK *.delta core
- X
- X%_ui.c: %.G
- X $(GUIDEHOME)/bin/gxv $*
- X
- X%_ui.h: %_ui.c
- X @touch $@
- X
- X%_stubs.c: %_ui.c
- X @touch $@
- X
- X%.info: %_ui.c
- X @touch $@
- END_OF_FILE
- if test 1592 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'cmd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cmd.c'\"
- else
- echo shar: Extracting \"'cmd.c'\" \(3870 characters\)
- sed "s/^X//" >'cmd.c' <<'END_OF_FILE'
- X/*
- X * cmd.c
- X *
- X * The non-GUI xrun testbed.
- X
- Xcc -g -I/usr/openwin/include cmd.c xrun.o -o cmd -L/usr/openwin/lib -lxview -lX11
- X
- X */
- X
- X
- X
- X#include <stdio.h>
- X#include <errno.h>
- X
- X#include <sys/param.h>
- X#include <sys/wait.h>
- X#include <sys/ioctl.h>
- X#include <sys/types.h>
- X
- X#include <xview/notify.h>
- X
- X#include "xrun.h"
- X
- X
- XNotify_value data_reader(), sigchldcatcher();
- X
- X
- X/* This is the transfer buffer. The union with the double dummy forces
- X * restrictive alignment of the buffer.
- X */
- X#define INBUFSIZE 4096
- Xstatic union {
- X double dummy;
- X char buf[INBUFSIZE];
- X} XX;
- X
- X
- X/* 23 is an arbitrary value: */
- XNotify_client cmd_client = (Notify_client)23;
- XNotify_value do_cmd();
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X int pid;
- X char buf[512];
- X
- X /* Wake up when we type at the program: */
- X notify_set_input_func(cmd_client, do_cmd, 0);
- X
- X
- X /* "Boot" the screen by printing the first prompt: */
- X (void) fprintf(stderr, "--> ");
- X
- X notify_start();
- X}
- X
- X
- XNotify_value
- Xdo_cmd(client, fd)
- XNotify_client client;
- Xint fd;
- X{
- X int i, bytes, pid;
- X
- X /* Point buf at the transfer block: */
- X char *buf = XX.buf;
- X
- X if (ioctl(fd, FIONREAD, &bytes) == -1) {
- X (void) sprintf(buf, "-- ioctl(%d, FIONREAD, &bytes)", fd);
- X perror(buf);
- X } else if(bytes != 0) {
- X i = read(fd, buf, INBUFSIZE);
- X
- X buf[i] = '\0';
- X (void) printf(stderr, "cmd: %s\n", buf);
- X
- X pid = xrunsh(buf, data_reader, data_reader, sigchldcatcher);
- X
- X switch(pid) {
- X case XRUN_SYS_ERR:
- X perror("system error spawning program");
- X break;
- X
- X case XRUN_MAX_PROCS_ERR:
- X (void) fprintf(stderr, "ERROR: max piped processes limit reached.\n");
- X break;
- X
- X default:
- X (void) fprintf(stderr, "process %d running!\n", pid);
- X break;
- X }
- X }
- X
- X (void) fprintf(stderr, "--> ");
- X
- X return NOTIFY_DONE;
- X}
- X
- X/*
- X * This callback is hit when a data client writes its stdout.
- X */
- XNotify_value
- Xdata_reader(client, fd)
- XNotify_client client;
- Xint fd;
- X{
- X int bytes, i;
- X char *buf, *stream;
- X
- X /* Point buf at the transfer block: */
- X buf = XX.buf;
- X
- X
- X if(client == STDOUT_CLIENT) {
- X stream = "stdout";
- X } else if(client == STDERR_CLIENT) {
- X stream = "stderr";
- X }
- X else {
- X stream = "--unknown--";
- X }
- X
- X
- X
- X /*
- X * The Notifier will dispatch to this function when data is ready.
- X * We must try to read ALL messages in the pipe before returning
- X * control to the Notifier:
- X */
- X if (ioctl(fd, FIONREAD, &bytes) == -1) {
- X (void) sprintf(buf, "-- ioctl(%d, FIONREAD, &bytes)", fd);
- X perror(buf);
- X } else if(bytes != 0) {
- X
- X /* We have bytes! That means at least one message: */
- X /*(void) printf("-- ioctl bytes: %d\n", bytes);*/
- X
- X /* Get a message! */
- X i = read(fd, buf, INBUFSIZE);
- X
- X switch(i) {
- X case -1:
- X perror("error reading pipe");
- X exit(1);
- X
- X case 0:
- X (void) fprintf(stderr, "no bytes...?\n");
- X break;
- X
- X default:
- X buf[i] = '\0';
- X (void) fprintf(stderr, "%s: [%s]", stream, buf);
- X break;
- X }
- X }
- X
- X return NOTIFY_DONE;
- X}
- X
- X
- X
- X/*
- X * Handle death of data client.
- X */
- XNotify_value
- Xsigchldcatcher(client, pid, status, rusage)
- XNotify_client client;
- Xint pid;
- Xunion wait *status;
- Xstruct rusage *rusage;
- X{
- X char rcbuf[8];
- X
- X if(WIFEXITED(*status)) {
- X (void) fprintf(stderr, "child pid %d exited w/code %d\n",
- X pid, WEXITSTATUS(*status));
- X (void) sprintf(rcbuf, "%d", WEXITSTATUS(*status));
- X } else if(WIFSIGNALED(*status)) {
- X (void) fprintf(stderr, "child pid %d recv'd signal %d\n",
- X pid, WTERMSIG(*status));
- X (void) sprintf(rcbuf, "%d", WTERMSIG(*status));
- X } else {
- X fprintf(stderr, "child did something else!\n");
- X (void) strcpy(rcbuf, "???");
- X }
- X
- X return NOTIFY_DONE;
- X}
- X
- END_OF_FILE
- if test 3870 -ne `wc -c <'cmd.c'`; then
- echo shar: \"'cmd.c'\" unpacked with wrong size!
- fi
- # end of 'cmd.c'
- fi
- if test -f 'xcmd.G' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xcmd.G'\"
- else
- echo shar: Extracting \"'xcmd.G'\" \(6768 characters\)
- sed "s/^X//" >'xcmd.G' <<'END_OF_FILE'
- X;GIL-3
- X(
- X(
- X :type :base-window
- X :name window1
- X :owner nil
- X :width 509
- X :height 473
- X :background-color ""
- X :foreground-color ""
- X :label "Base Window"
- X :label-type :string
- X :initial-state :open
- X :show-footer t
- X :resizable t
- X :icon-file ""
- X :icon-label ""
- X :icon-mask-file ""
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X(
- X :type :control-area
- X :name controls1
- X :owner window1
- X :help ""
- X :x 0
- X :y 0
- X :width 509
- X :height 101
- X :background-color ""
- X :foreground-color ""
- X :initial-state :visible
- X :show-border nil
- X :menu nil
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X(
- X :type :text-field
- X :name cmd_fld
- X :owner controls1
- X :help ""
- X :x 24
- X :y 24
- X :width 335
- X :height 15
- X :value-x 103
- X :value-y 24
- X :value-length 32
- X :stored-length 80
- X :rows 3
- X :foreground-color ""
- X :text-type :alphanumeric
- X :label "Command:"
- X :label-type :string
- X :layout-type :horizontal
- X :value-underlined t
- X :initial-value ""
- X :initial-state :active
- X :read-only nil
- X :notify-handler cmb_btn_cbk
- X :event-handler nil
- X :user-data ()
- X :actions (
- X (
- X :from (window1 cmd_fld)
- X :when (Notify )
- X :to (window1 cmd_fld)
- X :function_type CallFunction
- X :arg_type ()
- X :action (cmb_btn_cbk)
- X )
- X )
- X)
- X(
- X :type :message
- X :name status_msg
- X :owner controls1
- X :help ""
- X :x 392
- X :y 24
- X :width 45
- X :height 13
- X :foreground-color ""
- X :label "READY"
- X :label-type :string
- X :label-bold t
- X :initial-state :active
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X(
- X :type :text-field
- X :name pid_fld
- X :owner controls1
- X :help ""
- X :x 48
- X :y 56
- X :width 82
- X :height 15
- X :value-x 82
- X :value-y 56
- X :value-length 6
- X :stored-length 6
- X :rows 3
- X :foreground-color ""
- X :text-type :alphanumeric
- X :label "PID:"
- X :label-type :string
- X :layout-type :horizontal
- X :value-underlined t
- X :initial-value ""
- X :initial-state :active
- X :read-only t
- X :notify-handler nil
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X(
- X :type :text-field
- X :name retval_fld
- X :owner controls1
- X :help ""
- X :x 152
- X :y 56
- X :width 90
- X :height 15
- X :value-x 206
- X :value-y 56
- X :value-length 4
- X :stored-length 4
- X :rows 3
- X :foreground-color ""
- X :text-type :alphanumeric
- X :label "Retval:"
- X :label-type :string
- X :layout-type :horizontal
- X :value-underlined t
- X :initial-value ""
- X :initial-state :active
- X :read-only t
- X :notify-handler nil
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X(
- X :type :button
- X :name button1
- X :owner controls1
- X :help ""
- X :x 328
- X :y 56
- X :width 66
- X :height 20
- X :constant-width nil
- X :button-type :normal
- X :foreground-color ""
- X :label "Button1"
- X :label-type :string
- X :initial-state :active
- X :menu nil
- X :notify-handler button1_cbk
- X :event-handler nil
- X :user-data ()
- X :actions (
- X (
- X :from (window1 button1)
- X :when (Notify )
- X :to (window1 button1)
- X :function_type CallFunction
- X :arg_type ()
- X :action (button1_cbk)
- X )
- X )
- X)
- X(
- X :type :button
- X :name button2
- X :owner controls1
- X :help ""
- X :x 424
- X :y 56
- X :width 66
- X :height 20
- X :constant-width nil
- X :button-type :normal
- X :foreground-color ""
- X :label "Button2"
- X :label-type :string
- X :initial-state :active
- X :menu nil
- X :notify-handler button2_cbk
- X :event-handler nil
- X :user-data ()
- X :actions (
- X (
- X :from (window1 button2)
- X :when (Notify )
- X :to (window1 button2)
- X :function_type CallFunction
- X :arg_type ()
- X :action (button2_cbk)
- X )
- X )
- X)
- X(
- X :type :text-pane
- X :name stdout_txt
- X :owner window1
- X :help ""
- X :x 0
- X :y 116
- X :width 509
- X :height 169
- X :background-color ""
- X :foreground-color ""
- X :initial-state :visible
- X :show-border t
- X :read-only t
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X(
- X :type :text-pane
- X :name stderr_txt
- X :owner window1
- X :help ""
- X :x 0
- X :y 301
- X :width 509
- X :height 172
- X :background-color ""
- X :foreground-color ""
- X :initial-state :visible
- X :show-border t
- X :read-only t
- X :event-handler nil
- X :user-data ()
- X :actions ()
- X)
- X)
- END_OF_FILE
- if test 6768 -ne `wc -c <'xcmd.G'`; then
- echo shar: \"'xcmd.G'\" unpacked with wrong size!
- fi
- # end of 'xcmd.G'
- fi
- if test -f 'xcmd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xcmd.c'\"
- else
- echo shar: Extracting \"'xcmd.c'\" \(5394 characters\)
- sed "s/^X//" >'xcmd.c' <<'END_OF_FILE'
- X/*
- X * xcmd.c
- X *
- X * The testbed for xrun
- X */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X
- X#include <sys/param.h>
- X#include <sys/wait.h>
- X#include <sys/ioctl.h>
- X#include <sys/types.h>
- X
- X#include <xview/xview.h>
- X#include <xview/panel.h>
- X#include <xview/textsw.h>
- X#include <xview/xv_xrect.h>
- X
- X#include "xcmd_ui.h"
- X
- X#include "xrun.h"
- X
- X#include <xview/notice.h>
- X#include <xview/notify.h>
- X
- X
- X#define INBUFSIZE 4096 /* No msg may be bigger than this! */
- X
- X/*
- X * Global object definitions.
- X */
- Xxcmd_window1_objects *Xcmd_window1;
- X
- X
- X
- XNotify_value data_reader(), sigchldcatcher();
- X
- X
- X/* This is the transfer buffer. The union with the double dummy forces
- X * restrictive alignment of the buffer.
- X */
- Xstatic union {
- X double dummy;
- X char buf[INBUFSIZE];
- X} XX;
- X
- X
- X
- X
- X/*
- X * Instance XV_KEY_DATA key. An instance is a set of related
- X * user interface objects. A pointer to an object's instance
- X * is stored under this key in every object. This must be a
- X * global variable.
- X */
- XAttr_attribute INSTANCE;
- X
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X /*
- X * Initialize XView.
- X */
- X xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
- X INSTANCE = xv_unique_key();
- X
- X /*
- X * Initialize user interface components.
- X * Do NOT edit the object initializations by hand.
- X */
- X Xcmd_window1 = xcmd_window1_objects_initialize(NULL, NULL);
- X
- X
- X /*
- X * Turn control over to XView.
- X */
- X xv_main_loop(Xcmd_window1->window1);
- X exit(0);
- X}
- X
- X
- Xvoid
- Xbutton1_cbk(item, event)
- X Panel_item item;
- X Event *event;
- X{
- X xcmd_window1_objects *ip = (xcmd_window1_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
- X
- X fputs("xcmd: button1_cbk\n", stderr);
- X}
- X
- Xvoid
- Xbutton2_cbk(item, event)
- X Panel_item item;
- X Event *event;
- X{
- X xcmd_window1_objects *ip = (xcmd_window1_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
- X
- X fputs("xcmd: button2_cbk\n", stderr);
- X}
- X
- X
- X
- X
- X/*
- X * Notify callback function for `cmd_fld'.
- X */
- XPanel_setting
- Xcmb_btn_cbk(item, event)
- X Panel_item item;
- X Event *event;
- X{
- X char pidbuf[8];
- X char *s;
- X int pid;
- X
- X xcmd_window1_objects *ip = (xcmd_window1_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
- X char * value = (char *) xv_get(item, PANEL_VALUE);
- X
- X fprintf(stderr, "xcmd: cmb_btn_cbk: value: %s\n", value);
- X
- X textsw_reset(ip->stdout_txt, 0, 0);
- X xv_set(ip->stdout_txt, TEXTSW_MEMORY_MAXIMUM, 50000, NULL);
- X textsw_reset(ip->stderr_txt, 0, 0);
- X xv_set(ip->stderr_txt, TEXTSW_MEMORY_MAXIMUM, 50000, NULL);
- X
- X
- X/* { */
- X/* char *v[2]; */
- X/* v[0] = value; */
- X/* v[1] = (char *)0; */
- X/* pid = xrunv(v, data_reader, data_reader, sigchldcatcher); */
- X/* } */
- X
- X pid = xrunsh(value, data_reader, data_reader, sigchldcatcher);
- X
- X switch(pid) {
- X case XRUN_SYS_ERR:
- X perror("system error spawning program");
- X break;
- X
- X case XRUN_MAX_PROCS_ERR:
- X (void) fprintf(stderr, "ERROR: max piped processes limit reached.\n");
- X break;
- X
- X default:
- X xv_set(ip->status_msg, PANEL_LABEL_STRING, "pending...", NULL);
- X (void) sprintf(pidbuf, "%d", pid);
- X xv_set(ip->pid_fld, PANEL_VALUE, pidbuf, NULL);
- X break;
- X }
- X
- X return panel_text_notify(item, event);
- X}
- X
- X/*
- X * This callback is hit when a data client writes its stdout.
- X */
- XNotify_value
- Xdata_reader(client, fd)
- XNotify_client client;
- Xint fd;
- X{
- X int bytes, i;
- X char *buf, *stream;
- X Xv_opaque txt;
- X
- X /* Point buf at the transfer block: */
- X buf = XX.buf;
- X
- X
- X if(client == STDOUT_CLIENT) {
- X stream = "stdout";
- X txt = Xcmd_window1->stdout_txt;
- X } else if(client == STDERR_CLIENT) {
- X stream = "stderr";
- X txt = Xcmd_window1->stderr_txt;
- X }
- X else {
- X stream = "--unknown--";
- X }
- X
- X
- X
- X /*
- X * The Notifier will dispatch to this function when data is ready.
- X * We must try to read ALL messages in the pipe before returning
- X * control to the Notifier:
- X */
- X if (ioctl(fd, FIONREAD, &bytes) == -1) {
- X (void) sprintf(buf, "-- ioctl(%d, FIONREAD, &bytes)", fd);
- X perror(buf);
- X } else if(bytes != 0) {
- X
- X /* We have bytes! That means at least one message: */
- X /*(void) printf("-- ioctl bytes: %d\n", bytes);*/
- X
- X /* Get a message! */
- X i = read(fd, buf, INBUFSIZE);
- X
- X switch(i) {
- X case -1:
- X perror("error reading pipe");
- X exit(1);
- X
- X case 0:
- X (void) fprintf(stderr, "no bytes...?\n");
- X break;
- X
- X default:
- X buf[i] = '\0';
- X textsw_insert(txt, buf, i);
- X break;
- X }
- X }
- X
- X return NOTIFY_DONE;
- X}
- X
- X
- X
- X/*
- X * Handle death of data client.
- X */
- XNotify_value
- Xsigchldcatcher(client, pid, status, rusage)
- XNotify_client client;
- Xint pid;
- Xunion wait *status;
- Xstruct rusage *rusage;
- X{
- X char rcbuf[8];
- X
- X if(WIFEXITED(*status)) {
- X (void) fprintf(stderr, "child pid %d exited w/code %d\n",
- X pid, WEXITSTATUS(*status));
- X (void) sprintf(rcbuf, "%d", WEXITSTATUS(*status));
- X } else if(WIFSIGNALED(*status)) {
- X (void) fprintf(stderr, "child pid %d recv'd signal %d\n",
- X pid, WTERMSIG(*status));
- X (void) sprintf(rcbuf, "%d", WTERMSIG(*status));
- X } else {
- X fprintf(stderr, "child did something else!\n");
- X (void) strcpy(rcbuf, "???");
- X }
- X
- X xv_set(Xcmd_window1->status_msg, PANEL_LABEL_STRING, "READY", NULL);
- X xv_set(Xcmd_window1->retval_fld, PANEL_VALUE, rcbuf, NULL);
- X
- X return NOTIFY_DONE;
- X}
- X
- END_OF_FILE
- if test 5394 -ne `wc -c <'xcmd.c'`; then
- echo shar: \"'xcmd.c'\" unpacked with wrong size!
- fi
- # end of 'xcmd.c'
- fi
- if test -f 'xcmd.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xcmd.h'\"
- else
- echo shar: Extracting \"'xcmd.h'\" \(107 characters\)
- sed "s/^X//" >'xcmd.h' <<'END_OF_FILE'
- X
- Xtypedef struct Comm {
- X int pid;
- X int pipe_out;
- X int pipe_in;
- X int pipe_errin;
- X} Comm;
- END_OF_FILE
- if test 107 -ne `wc -c <'xcmd.h'`; then
- echo shar: \"'xcmd.h'\" unpacked with wrong size!
- fi
- # end of 'xcmd.h'
- fi
- if test -f 'xcmd_ui.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xcmd_ui.c'\"
- else
- echo shar: Extracting \"'xcmd_ui.c'\" \(5788 characters\)
- sed "s/^X//" >'xcmd_ui.c' <<'END_OF_FILE'
- X/*
- X * xcmd_ui.c - User interface object initialization functions.
- X * This file was generated by `gxv' from `xcmd.G'.
- X * DO NOT EDIT BY HAND.
- X */
- X
- X#include <stdio.h>
- X#include <sys/param.h>
- X#include <sys/types.h>
- X#include <xview/xview.h>
- X#include <xview/canvas.h>
- X#include <xview/panel.h>
- X#include <xview/scrollbar.h>
- X#include <xview/svrimage.h>
- X#include <xview/termsw.h>
- X#include <xview/text.h>
- X#include <xview/tty.h>
- X#include <xview/xv_xrect.h>
- X#include "xcmd_ui.h"
- X
- X/*
- X * Initialize an instance of object `window1'.
- X */
- Xxcmd_window1_objects *
- Xxcmd_window1_objects_initialize(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X if (!ip && !(ip = (xcmd_window1_objects *) calloc(1, sizeof (xcmd_window1_objects))))
- X return (xcmd_window1_objects *) NULL;
- X if (!ip->window1)
- X ip->window1 = xcmd_window1_window1_create(ip, owner);
- X if (!ip->controls1)
- X ip->controls1 = xcmd_window1_controls1_create(ip, ip->window1);
- X if (!ip->cmd_fld)
- X ip->cmd_fld = xcmd_window1_cmd_fld_create(ip, ip->controls1);
- X if (!ip->status_msg)
- X ip->status_msg = xcmd_window1_status_msg_create(ip, ip->controls1);
- X if (!ip->pid_fld)
- X ip->pid_fld = xcmd_window1_pid_fld_create(ip, ip->controls1);
- X if (!ip->retval_fld)
- X ip->retval_fld = xcmd_window1_retval_fld_create(ip, ip->controls1);
- X if (!ip->button1)
- X ip->button1 = xcmd_window1_button1_create(ip, ip->controls1);
- X if (!ip->button2)
- X ip->button2 = xcmd_window1_button2_create(ip, ip->controls1);
- X if (!ip->stdout_txt)
- X ip->stdout_txt = xcmd_window1_stdout_txt_create(ip, ip->window1);
- X if (!ip->stderr_txt)
- X ip->stderr_txt = xcmd_window1_stderr_txt_create(ip, ip->window1);
- X return ip;
- X}
- X
- X/*
- X * Create object `window1' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_window1_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, FRAME,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_WIDTH, 509,
- X XV_HEIGHT, 473,
- X XV_LABEL, "Base Window",
- X FRAME_SHOW_FOOTER, TRUE,
- X FRAME_SHOW_RESIZE_CORNER, TRUE,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `controls1' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_controls1_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 0,
- X XV_Y, 0,
- X XV_WIDTH, WIN_EXTEND_TO_EDGE,
- X XV_HEIGHT, 101,
- X WIN_BORDER, FALSE,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `cmd_fld' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_cmd_fld_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X extern Panel_setting cmb_btn_cbk();
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL_TEXT,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 24,
- X XV_Y, 24,
- X PANEL_VALUE_DISPLAY_LENGTH, 32,
- X PANEL_VALUE_STORED_LENGTH, 80,
- X PANEL_LABEL_STRING, "Command:",
- X PANEL_LAYOUT, PANEL_HORIZONTAL,
- X PANEL_READ_ONLY, FALSE,
- X PANEL_NOTIFY_PROC, cmb_btn_cbk,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `status_msg' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_status_msg_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL_MESSAGE,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 392,
- X XV_Y, 24,
- X PANEL_LABEL_STRING, "READY",
- X PANEL_LABEL_BOLD, TRUE,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `pid_fld' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_pid_fld_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL_TEXT,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 48,
- X XV_Y, 56,
- X PANEL_VALUE_DISPLAY_LENGTH, 6,
- X PANEL_VALUE_STORED_LENGTH, 6,
- X PANEL_LABEL_STRING, "PID:",
- X PANEL_LAYOUT, PANEL_HORIZONTAL,
- X PANEL_READ_ONLY, TRUE,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `retval_fld' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_retval_fld_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL_TEXT,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 152,
- X XV_Y, 56,
- X PANEL_VALUE_DISPLAY_LENGTH, 4,
- X PANEL_VALUE_STORED_LENGTH, 4,
- X PANEL_LABEL_STRING, "Retval:",
- X PANEL_LAYOUT, PANEL_HORIZONTAL,
- X PANEL_READ_ONLY, TRUE,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `button1' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_button1_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X extern void button1_cbk();
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL_BUTTON,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 328,
- X XV_Y, 56,
- X PANEL_LABEL_STRING, "Button1",
- X PANEL_NOTIFY_PROC, button1_cbk,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `button2' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_button2_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X extern void button2_cbk();
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, PANEL_BUTTON,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 424,
- X XV_Y, 56,
- X PANEL_LABEL_STRING, "Button2",
- X PANEL_NOTIFY_PROC, button2_cbk,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `stdout_txt' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_stdout_txt_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, TEXTSW,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 0,
- X XV_Y, 116,
- X XV_WIDTH, WIN_EXTEND_TO_EDGE,
- X XV_HEIGHT, 169,
- X OPENWIN_SHOW_BORDERS, TRUE,
- X TEXTSW_BROWSING, TRUE,
- X TEXTSW_DISABLE_LOAD, TRUE,
- X NULL);
- X return obj;
- X}
- X
- X/*
- X * Create object `stderr_txt' in the specified instance.
- X */
- XXv_opaque
- Xxcmd_window1_stderr_txt_create(ip, owner)
- X xcmd_window1_objects *ip;
- X Xv_opaque owner;
- X{
- X Xv_opaque obj;
- X
- X obj = xv_create(owner, TEXTSW,
- X XV_KEY_DATA, INSTANCE, ip,
- X XV_X, 0,
- X XV_Y, 301,
- X XV_WIDTH, WIN_EXTEND_TO_EDGE,
- X XV_HEIGHT, WIN_EXTEND_TO_EDGE,
- X OPENWIN_SHOW_BORDERS, TRUE,
- X TEXTSW_BROWSING, TRUE,
- X TEXTSW_DISABLE_LOAD, TRUE,
- X NULL);
- X return obj;
- X}
- X
- END_OF_FILE
- if test 5788 -ne `wc -c <'xcmd_ui.c'`; then
- echo shar: \"'xcmd_ui.c'\" unpacked with wrong size!
- fi
- # end of 'xcmd_ui.c'
- fi
- if test -f 'xcmd_ui.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xcmd_ui.h'\"
- else
- echo shar: Extracting \"'xcmd_ui.h'\" \(1044 characters\)
- sed "s/^X//" >'xcmd_ui.h' <<'END_OF_FILE'
- X#ifndef xcmd_HEADER
- X#define xcmd_HEADER
- X
- X/*
- X * xcmd_ui.h - User interface object and function declarations.
- X * This file was generated by `gxv' from `xcmd.G'.
- X * DO NOT EDIT BY HAND.
- X */
- X
- Xextern Attr_attribute INSTANCE;
- X
- X
- Xtypedef struct {
- X Xv_opaque window1;
- X Xv_opaque controls1;
- X Xv_opaque cmd_fld;
- X Xv_opaque status_msg;
- X Xv_opaque pid_fld;
- X Xv_opaque retval_fld;
- X Xv_opaque button1;
- X Xv_opaque button2;
- X Xv_opaque stdout_txt;
- X Xv_opaque stderr_txt;
- X} xcmd_window1_objects;
- X
- Xextern xcmd_window1_objects *xcmd_window1_objects_initialize();
- X
- Xextern Xv_opaque xcmd_window1_window1_create();
- Xextern Xv_opaque xcmd_window1_controls1_create();
- Xextern Xv_opaque xcmd_window1_cmd_fld_create();
- Xextern Xv_opaque xcmd_window1_status_msg_create();
- Xextern Xv_opaque xcmd_window1_pid_fld_create();
- Xextern Xv_opaque xcmd_window1_retval_fld_create();
- Xextern Xv_opaque xcmd_window1_button1_create();
- Xextern Xv_opaque xcmd_window1_button2_create();
- Xextern Xv_opaque xcmd_window1_stdout_txt_create();
- Xextern Xv_opaque xcmd_window1_stderr_txt_create();
- X#endif
- END_OF_FILE
- if test 1044 -ne `wc -c <'xcmd_ui.h'`; then
- echo shar: \"'xcmd_ui.h'\" unpacked with wrong size!
- fi
- # end of 'xcmd_ui.h'
- fi
- if test -f 'xrun.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xrun.c'\"
- else
- echo shar: Extracting \"'xrun.c'\" \(12963 characters\)
- sed "s/^X//" >'xrun.c' <<'END_OF_FILE'
- X/*
- X * DEXID
- X * xrun.3
- X *
- X * NAME
- X * xrunsh, xrunv - Notifier based program execution package
- X *
- X * SYNOPSIS
- X * #include <xrun.h>
- X *
- X * int xrunsh(cmd, fd1f, fd2f, reaper)
- X * char *cmd;
- X * Notify_value (*fd1f)();
- X * Notify_value (*fd2f)();
- X * Notify_value (*reaper)();
- X *
- X * int xrunv(v, fd1f, fd2f, reaper)
- X * char *v[];
- X * Notify_value (*fd1f)();
- X * Notify_value (*fd2f)();
- X * Notify_value (*reaper)();
- X *
- X * DESCRIPTION
- X * xrunsh() and xrunv() are front-ends to the classic "pipe-fork-exec"
- X * model of child program execution. xrunsh() passes cmd_ as an argument
- X * to the Bourne shell (sh -c) and therefore may be used to run commands
- X * that might contain metacharacters; xrunv() takes a vector of arguments v_
- X * and runs v[0] directly. execvp() is used to start cmd_.
- X *
- X * The application supplies callback handlers for the child process'
- X * stdout (fd1f), stderr (fd2f), and signals (reaper). Any of these
- X * handlers may be NULL, indicating that the parent has no interest in
- X * handling these events. Both the file descriptor handlers and the
- X * child reaper handler have declarations identical to "regular" Xview
- X * handlers:
- X *
- X * Notify_value fd_handler(client, fd)
- X * Notify_client client;
- X * int fd;
- X *
- X * Notify_value reaper(client, pid, status, rusage)
- X * Notify_client client;
- X * int pid;
- X * union wait *status;
- X * struct rusage *rusage;
- X *
- X * In the case of the file descriptor handlers, client will always equal
- X * either STDOUT_CLIENT or STDERR_CLIENT, depending on which stream
- X * activated the callback. The calling program can therefore pass the
- X * same handler to xrunsh()/xrunv() for both fd1f and fd2f and
- X * distinguish between the two streams via the value of the client
- X * argument. The child reaper is always called with client equal to
- X * REAPER_CLIENT.
- X *
- X * The main features of the package are:
- X * 1. All the piping and forking is hidden away (finally...)
- X * 2. File descriptor resources are properly reclaimed.
- X *
- X * Point (2) warrants a bit of explanation. Consider the following code:
- X *
- X * main()
- X * {
- X * (void) fprintf(stdout, "I am stdout.\n")
- X * (void) fprintf(stderr, "I am stderr.\n")
- X * return 0;
- X * }
- X *
- X * All the Xview manuals (including the O'Reilly series) provide examples
- X * of how to spawn this program from a X parent and get a hold of the
- X * child's stdin, out, and err, but they make an important -- and
- X * incorrect -- assumption that the streams will be drained *before* the
- X * child exits and is reaped. The file descriptors are usually closed
- X * and the events de-registered at the time the child is reaped. The
- X * order in which the events are received, however, *cannot* be assumed.
- X * For example, upon first inspection the program above would appear to
- X * first wake up the stdout callback, then the stderr callback, and
- X * finally the child reaper callback. In fact, it is possible to have the
- X * events triggered in exactly the reverse order! If the reaper is
- X * reclaiming resources, the data pending in the streams will be lost.
- X * Even worse is the permutation where the child reaper callback wakes up
- X * in the middle. In this case, the descriptors will be closed and when
- X * the last stream callback gets hit, the descriptor will no longer be
- X * valid and an internal Xview error will be generated. This has nothing
- X * to do with flushing streams, by the way. It is simply a matter of
- X * properly managing a set of asynchronous resources within a synchronous
- X * context (whew!).
- X *
- X * xrunsh()/xrunv() provides utility by quietly checking the status of
- X * the child and the pipes after each event callback is processed. If
- X * the child has exited and there is no data left to be read on the
- X * pipes, then at that time and at that time only will the descriptors be
- X * closed and the callbacks de-registered. The calling application
- X * should not perform these operations.
- X *
- X * DIAGNOSTICS
- X * If the integer returned by xrunsh()/xrunv() is > 0, then the child has
- X * started successfully and the integer is the PID of the child. A
- X * return value of XRUN_MAX_PROCS_ERR indicates that the maximum number
- X * of processes that may be managed simultaneously has been exceeded (see
- X * BUGS). A return value of XRUN_SYS_ERR indicates that either some
- X * system call failed during the pipe-fork-exec process OR the process
- X * cannot be started; errno will be set.
- X *
- X * If the fork succeeds but the child process cannot be execed, then the
- X * fork will exit with a return value XRUN_EXEC_ERR. The reaper process
- X * should check for this return value, although a successful exec could
- X * also return this value.
- X *
- X * NOTES
- X * As always, running a command via sh -c prevents the calling app from
- X * determining if the command is in fact executable. The shell will
- X * write
- X * sh: program: not found
- X * to stderr and return 1 to the caller, but that's about it. What
- X * you're really looking for is errno ENOENT. The tightest way? Check
- X * your program accessibility *before* calling xrunsh() or xrunv().
- X *
- X * BUGS
- X * The maximum number of processes that may be managed simultaneously is
- X * dependent on a bunch of operating systems parameters known at compile
- X * time plus run-time usage of file descriptors in other parts of the
- X * calling program. I have elected to punt on this issue and have set an
- X * arbitrary limit of 16 processes; see the explanation near the
- X * definition of the MAX_PROCS symbol.
- X *
- X * AUTHOR
- X * Buzz Moschetti, BSC 08/12/92
- X *
- X */
- X/* LINTLIBRARY */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X
- X#include <sys/param.h>
- X#include <sys/wait.h>
- X#include <sys/ioctl.h>
- X#include <sys/types.h>
- X
- X#include <xview/notify.h>
- X
- X#include <xrun.h>
- X
- X
- Xstatic Notify_value fd_reader(), child_reaper();
- X
- Xstatic Comm *map_fd2comm();
- Xstatic Comm *map_pid2comm();
- Xstatic Comm *get_comm();
- X
- Xstatic void free_comm();
- Xstatic void clean_up();
- Xstatic void drain();
- X
- Xstatic int xrun();
- X
- X
- X
- Xstatic Notify_client fd1_client = STDOUT_CLIENT;
- Xstatic Notify_client fd2_client = STDERR_CLIENT;
- Xstatic Notify_client reaper_client = REAPER_CLIENT;
- X
- X/*
- X * This is a hardcode, but I'm too lazy to go into operating system
- X * junk to dynamically arrive at the size. Assume that a max of 64
- X * descriptors are available, and that stdin, stdout, stderr, X, and
- X * other crap takes up fd 0-7. Each proc creates (temporarily) six
- X * descriptors (3 pipes), after which three are closed, so the theoretical
- X * max we can have is 17. Why? Steady state after 16 opens is 16 * 3 = 48.
- X * The 17th open temporarily adds 6, 48 + 6 = 54. 54 + 8 overhead = 62,
- X * which is within the limit.
- X *
- X * NOTE: Since 17 is *UGLY*, we will drop the max to 16. :-)
- X */
- X#define MAX_PROCS 16
- X
- Xstatic Comm cxx[MAX_PROCS];
- X
- X
- X/*
- X * This buffer is used to drain pipes when the app does not provide handlers
- X * for stdout and stderr. These streams MUST be drained or the child will
- X * hang after 4096 bytes have been written.
- X */
- X#define PLAYBUFSIZE 512
- Xstatic char pbuf[PLAYBUFSIZE];
- X
- X
- X
- X
- X
- Xint
- Xxrunsh(cmd, fd1f, fd2f, reaper)
- Xchar *cmd;
- XNotify_value (*fd1f)();
- XNotify_value (*fd2f)();
- XNotify_value (*reaper)();
- X{
- X int rc;
- X char *v[4];
- X
- X v[0] = "sh";
- X v[1] = "-c";
- X v[2] = cmd;
- X v[3] = (char *)0;
- X
- X rc = xrunv(v, fd1f, fd2f, reaper);
- X
- X return rc;
- X}
- X
- X
- Xint
- Xxrunv(v, fd1f, fd2f, reaper)
- Xchar *v[];
- XNotify_value (*fd1f)();
- XNotify_value (*fd2f)();
- XNotify_value (*reaper)();
- X{
- X Comm *w;
- X int pipe_io[3][2];
- X int pid, i;
- X
- X
- X /*
- X * Find an open channel:
- X */
- X w = get_comm();
- X
- X /* Did we overrun the table? */
- X if(!w) {
- X return XRUN_MAX_PROCS_ERR;
- X }
- X
- X
- X
- X if(pipe(pipe_io[0]) == -1) {
- X return XRUN_SYS_ERR;
- X }
- X if(pipe(pipe_io[1]) == -1) {
- X (void) close(pipe_io[0][0]);
- X (void) close(pipe_io[0][1]);
- X return XRUN_SYS_ERR;
- X }
- X if(pipe(pipe_io[2]) == -1) {
- X (void) close(pipe_io[0][0]);
- X (void) close(pipe_io[0][1]);
- X (void) close(pipe_io[1][0]);
- X (void) close(pipe_io[1][1]);
- X return XRUN_SYS_ERR;
- X }
- X
- X
- X
- X switch(pid = fork()) {
- X case -1:
- X return XRUN_SYS_ERR;
- X
- X
- X case 0: /* child! */
- X /* Redirected child's std{in,out,err}: */
- X (void) dup2(pipe_io[0][0], 0);
- X (void) dup2(pipe_io[1][1], 1);
- X (void) dup2(pipe_io[2][1], 2);
- X
- X /* Shut down all other open fd's in child: */
- X for(i = getdtablesize(); i > 2; i--)
- X (void) close(i);
- X
- X (void) execvp(v[0], v);
- X
- X /*
- X * If we're here then it didn't execute. Since we're the child
- X * and can't "return" XRUN_SYS_ERR to the calling function,
- X * we will cheat by exiting with a value of XRUN_EXEC_ERR. The
- X * parent can then check for this value when it reaps the child.
- X */
- X _exit(XRUN_EXEC_ERR);
- X
- X
- X default: /* parent! */
- X (void) close(pipe_io[0][0]);
- X (void) close(pipe_io[1][1]);
- X (void) close(pipe_io[2][1]);
- X break;
- X }
- X
- X
- X /*
- X * Set communications resources:
- X */
- X w->pid = pid;
- X w->pipe_out = pipe_io[0][1];
- X w->pipe_in = pipe_io[1][0];
- X w->pipe_errin = pipe_io[2][0];
- X
- X
- X w->child_up = 1;
- X
- X w->fd1f = fd1f;
- X w->fd2f = fd2f;
- X w->reaper = reaper;
- X
- X notify_set_input_func(fd1_client, fd_reader, w->pipe_in);
- X notify_set_input_func(fd2_client, fd_reader, w->pipe_errin);
- X
- X notify_set_wait3_func(reaper_client, child_reaper, w->pid);
- X
- X return pid;
- X}
- X
- X
- X
- X/*
- X * This callback is hit when a data client writes its stdout.
- X */
- Xstatic Notify_value
- Xfd_reader(client, fd)
- XNotify_client client;
- Xint fd;
- X{
- X Notify_value v;
- X Notify_value (*f)();
- X Comm *w;
- X
- X /* Map fd to Comm: */
- X w = map_fd2comm(fd);
- X
- X /*
- X * Incoming client value can only be fd1_client or fd2_client since
- X * this module set it up.
- X */
- X f = (client == fd1_client) ? w->fd1f : w->fd2f;
- X
- X if(f) {
- X v = (*f)(client, fd);
- X } else {
- X drain(fd);
- X v = NOTIFY_DONE;
- X }
- X
- X /* Perform mandatory cleanup: */
- X clean_up(w);
- X
- X return v;
- X}
- X
- X
- X/*
- X * Handle death of data client.
- X */
- Xstatic Notify_value
- Xchild_reaper(client, pid, status, rusage)
- XNotify_client client;
- Xint pid;
- Xunion wait *status;
- Xstruct rusage *rusage;
- X{
- X Notify_value v;
- X Comm *w;
- X
- X /* Map pid to Comm: */
- X w = map_pid2comm(pid);
- X
- X /* Child is no longer active: */
- X w->child_up = 0;
- X
- X /*
- X * Unlike the fd reader, there is no special "drain" that needs to
- X * be called.
- X */
- X v = w->reaper ? w->reaper(client, pid, status, rusage) : NOTIFY_DONE;
- X
- X /* Perform mandatory cleanup: */
- X clean_up(w);
- X
- X return v;
- X}
- X
- X
- X
- X
- Xstatic Comm *
- Xget_comm()
- X{
- X int w;
- X
- X for(w = 0; w < MAX_PROCS; w++) {
- X if(cxx[w].pid == 0) {
- X return &cxx[w];
- X }
- X }
- X
- X return (Comm *)0;
- X}
- X
- X
- Xstatic void
- Xfree_comm(w)
- XComm *w;
- X{
- X if(w) {
- X w->pid = 0;
- X }
- X}
- X
- Xstatic Comm *
- Xmap_fd2comm(fd)
- Xint fd;
- X{
- X int i;
- X
- X for(i = 0; i < MAX_PROCS; i++) {
- X if(cxx[i].pipe_in == fd ||
- X cxx[i].pipe_errin == fd) {
- X return &cxx[i];
- X }
- X }
- X
- X /* This should never happen! */
- X return (Comm *)0;
- X}
- X
- X
- Xstatic Comm *
- Xmap_pid2comm(pid)
- Xint pid;
- X{
- X int i;
- X
- X for(i = 0; i < MAX_PROCS; i++) {
- X if(cxx[i].pid == pid) {
- X return &cxx[i];
- X }
- X }
- X
- X /* This should never happen! */
- X return (Comm *)0;
- X}
- X
- X
- X
- Xstatic void
- Xclean_up(w)
- XComm *w;
- X{
- X int fd1b, fd2b;
- X
- X /*
- X * If there is no data left to be read on either stdout or stderr
- X * AND the child has exited, then we are truly finished -- free up
- X * the resources.
- X *
- X * In order to maximize performance, we'll check child status first
- X * followed by bytes-pending tests on the pipes:
- X */
- X if(w->child_up == 0) {
- X
- X if (ioctl(w->pipe_in, FIONREAD, &fd1b) == -1) {
- X (void) sprintf(pbuf, "clean_up: ioctl error fd %d",w->pipe_in);
- X perror(pbuf);
- X }
- X if (ioctl(w->pipe_errin, FIONREAD, &fd2b) == -1) {
- X (void) sprintf(pbuf, "clean_up: ioctl error fd %d",w->pipe_errin);
- X perror(pbuf);
- X }
- X
- X if(fd1b == 0 && fd2b == 0) {
- X
- X /* Deregister and close! */
- X notify_set_input_func(fd1_client, NOTIFY_FUNC_NULL,w->pipe_in);
- X notify_set_input_func(fd2_client, NOTIFY_FUNC_NULL,w->pipe_errin);
- X notify_set_wait3_func(reaper_client, NOTIFY_FUNC_NULL, w->pid);
- X
- X (void) close(w->pipe_out);
- X (void) close(w->pipe_in);
- X (void) close(w->pipe_errin);
- X
- X /* Reset the slot: */
- X free_comm(w);
- X }
- X }
- X}
- X
- X
- Xstatic void
- Xdrain(fd)
- Xint fd;
- X{
- X int bytes;
- X
- X if (ioctl(fd, FIONREAD, &bytes) == -1) {
- X (void) sprintf(pbuf, "drain: ioctl error fd %d", fd);
- X perror(pbuf);
- X } else if(bytes != 0) {
- X /* We have bytes! Eat them: */
- X (void) read(fd, pbuf, PLAYBUFSIZE);
- X }
- X}
- X
- END_OF_FILE
- if test 12963 -ne `wc -c <'xrun.c'`; then
- echo shar: \"'xrun.c'\" unpacked with wrong size!
- fi
- # end of 'xrun.c'
- fi
- if test -f 'xrun.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xrun.h'\"
- else
- echo shar: Extracting \"'xrun.h'\" \(773 characters\)
- sed "s/^X//" >'xrun.h' <<'END_OF_FILE'
- X/*
- X * xrun.h
- X */
- X
- X#if !defined(XRUN_H_INCLUDED)
- X#define XRUN_H_INCLUDED
- X
- X#include <xview/notify.h>
- X
- X#define XRUN_SYS_ERR (-1)
- X#define XRUN_MAX_PROCS_ERR (0)
- X
- X#define XRUN_EXEC_ERR (254)
- X
- X
- X/*
- X * Arbitrary values 10, 11, 12, but we must put them in xrun.h
- X * so that the app level call can distinguish between the two fd
- X * streams should it elect to have a common callback.
- X */
- X#define STDOUT_CLIENT ((Notify_client)10)
- X#define STDERR_CLIENT ((Notify_client)11)
- X#define REAPER_CLIENT ((Notify_client)12)
- X
- X
- Xtypedef struct Comm {
- X int pid;
- X int pipe_out;
- X int pipe_in;
- X int pipe_errin;
- X
- X Notify_value (*fd1f)();
- X Notify_value (*fd2f)();
- X Notify_value (*reaper)();
- X
- X char child_up;
- X} Comm;
- X
- X#endif /* XRUN_H_INCLUDED */
- END_OF_FILE
- if test 773 -ne `wc -c <'xrun.h'`; then
- echo shar: \"'xrun.h'\" unpacked with wrong size!
- fi
- # end of 'xrun.h'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-