Duplicate output to multiple terminals

Dale R. Worley drw at schubert.math.mit.edu
Tue Nov 14 14:53:23 AEST 1989


Here's a program I use that uses interprocessor communications.  It
seems to work fine.  It was hacked up from the Emacs client/server
code.

To run the master program, do:

	program | broadcast

Then just:

	receiver

to run a slave.  broadcast and receiver have to be run in the same
account.  These could be hacked up to use Internet IPC, etc. to make
them more useful, but they do what I needed done.

Dale
---------------------------------------- broadcast.c
/* Broadcast stdin to everybody who wants to listen */

/* Communication subprocess for GNU Emacs acting as server.
   Copyright (C) 1986, 1987 Free Software Foundation, Inc.

This file is part of GNU Emacs.

GNU Emacs is distributed in the hope that it will be useful,
but without any warranty.  No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing.

Everyone is granted permission to copy, modify and redistribute
GNU Emacs, but only under the conditions described in the
document "GNU Emacs copying permission notice".   An exact copy
of the document is supposed to have been given to you along with
GNU Emacs so that you can know how you may redistribute it all.
It should be in a file named COPYING.  Among other things, the
copyright notice and this notice must be preserved on all copies.  */


/* The GNU Emacs edit server process is run as a subprocess of Emacs
   under control of the file lisp/server.el.
   This program accepts communication from client (program emacsclient.c)
   and passes their commands (consisting of keyboard characters)
   up to the Emacs which then executes them.  */

/* This code is BSD only. */

#include <sys/file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/un.h>
#include <stdio.h>
#include <errno.h>

#include <fcntl.h>

extern int errno;

main ()
{
  int s, infd, fromlen;
  struct sockaddr_un server, fromunix;
  char *homedir;
  char *str, string[BUFSIZ], code[BUFSIZ];
  FILE *infile;
  FILE **openfiles;
  int openfiles_size;
  int i;

  char *getenv ();

  openfiles_size = 20;
  openfiles = (FILE **) malloc (openfiles_size * sizeof (FILE *));
  if (openfiles == 0)
    abort ();
  for (i = 0; i < openfiles_size; i++)
    openfiles[i] == NULL;

  /* 
   * Open up an AF_UNIX socket in this person's home directory
   */

  if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
      perror ("socket");
      exit (1);
    }
  server.sun_family = AF_UNIX;
  if ((homedir = getenv ("HOME")) == NULL)
    {
      fprintf (stderr,"No home directory\n");
      exit (1);
    }
  strcpy (server.sun_path, homedir);
  strcat (server.sun_path, "/.broadcast");
  unlink(server.sun_path);
  if (bind (s, &server, strlen (server.sun_path) + 2) < 0)
    {
      perror ("bind");
      exit (1);
    }
  /*
   * Now, just wait for everything to come in..
   */
  if (listen (s, 5) < 0)
    {
      perror ("listen");
      exit (1);
    }

  fprintf(stderr, "[Waiting for clients.]\n");

  /* Disable sigpipes in case luser kills client... */
  signal (SIGPIPE, SIG_IGN);

  /* Make stdin non-blocking */
  fcntl(stdin->_file, F_SETFL, FNDELAY);

  for (;;)
    {
      int rmask = (1 << s) + 1;

      /* wait for input from new client or stdin */
      if (select (s + 1, &rmask, 0, 0, 0) < 0)
	perror ("select");
      if (rmask & (1 << s))	/* client sends list of filenames */
	{
	  /* new client calling */
	  fromlen = sizeof (fromunix);
	  fromunix.sun_family = AF_UNIX;
	  infd = accept (s, &fromunix, &fromlen); /* open socket fd */
	  if (infd < 0)
	    {
	      if (errno == EMFILE || errno == ENFILE)
		fprintf (stderr, "Too many clients.\n");
	      else
		perror ("accept");
	      continue;
	    }

	  while (infd >= openfiles_size)
	    {
	      int i;

	      openfiles_size *= 2;
	      openfiles = (FILE **) realloc (openfiles,
					     openfiles_size * sizeof (FILE *));
	      if (openfiles == 0)
		abort ();
	      for (i = openfiles_size/2; i < openfiles_size; i++)
		openfiles[i] == NULL;
	    }

	  infile = fdopen (infd, "r+"); /* open stream */
	  if (infile == NULL)
	    {
	      fprintf (stderr, "Too many clients.\n");
	      write (infd, "Too many clients.\n", 18);
	      close (infd);		/* Prevent descriptor leak.. */
	      continue;
	    }
	  openfiles[infd] = infile;
	  fprintf (stderr, "[Client: %d]\n", infd);
	  fflush (stderr);
	  continue;
	}
      else if (rmask & 1)
	{
	  /* text from stdin -- broadcast it to all clients */
	  /* Read from stdin and copy to the streams until we get 'wouldblock'
	   * or EOF. */
	  while (1)
	    {
	      int c;
	      int i;
	      int retcode;
#define BUFSIZE 100
	      char buffer[BUFSIZE];

	      /* Read some input. */
	      errno = 0;
	      retcode = read(stdin->_file, buffer, BUFSIZE);

	      /* Handle errors and EOF. */
	      if (retcode == -1 || retcode == 0)
		{
		  if (errno == EWOULDBLOCK)
		    /* wouldblock -- go back to waiting */
		    break;
		  else
		    {
		      /* EOF on input -- exit */
		      fprintf(stderr, "[Exiting]\n");
		      exit(0);
		    }
		}

	      /* Write characters to all open streams */
	      for (i = 0; i < openfiles_size; i++)
		{
		  if (openfiles[i] != NULL)
		    write (openfiles[i]->_file, buffer, retcode);
		}
	      /* Copy to stdout */
	      write (stdout->_file, buffer, retcode);
	    }
	  continue;
	} 
    }
}
---------------------------------------- receiver.c
/* Client process that communicates with GNU Emacs acting as server.
   Copyright (C) 1986, 1987 Free Software Foundation, Inc.

This file is part of GNU Emacs.

GNU Emacs is distributed in the hope that it will be useful,
but without any warranty.  No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing.

Everyone is granted permission to copy, modify and redistribute
GNU Emacs, but only under the conditions described in the
document "GNU Emacs copying permission notice".   An exact copy
of the document is supposed to have been given to you along with
GNU Emacs so that you can know how you may redistribute it all.
It should be in a file named COPYING.  Among other things, the
copyright notice and this notice must be preserved on all copies.  */

/* This code is BSD only. */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>

main (argc, argv)
     int argc;
     char **argv;
{
  int s, n, i;
  FILE *out;
  struct sockaddr_un server;
  char *homedir, *cwd, *str;
  char string[BUFSIZ];
  int c;

  char *getenv (), *getwd ();

  /* 
   * Open up an AF_UNIX socket in this person's home directory
   */

  if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
      perror ("socket");
      exit (1);
    }
  server.sun_family = AF_UNIX;
  if ((homedir = getenv ("HOME")) == NULL)
    {
      fprintf (stderr, "No home directory\n");
      exit (1);
    }
  strcpy (server.sun_path, homedir);
  strcat (server.sun_path, "/.broadcast");
  if (connect (s, &server, strlen (server.sun_path) + 2) < 0)
    {
      perror ("connect");
      exit (1);
    }
  if ((out = fdopen (s, "r+")) == NULL)
    {
      perror ("fdopen");
      exit (1);
    }

  cwd = getwd (string);
  if (cwd == 0)
    abort ();

  fprintf(stderr, "[Connected.]\n");

  setbuf(stdout, NULL);

  while (1)
    {
      int retcode;
#define BUFSIZE 100
      char buffer[BUFSIZE];

      /* Read some input. */
      retcode = read(s, buffer, BUFSIZE);

      /* Handle errors and EOF. */
      if (retcode == -1 || retcode == 0)
	break;

      /* Copy to stdout */
      write (stdout->_file, buffer, retcode);
    }
  printf("\n[Disconnected]\n");
}



More information about the Alt.sources mailing list