psfales@cbnewsc.ATT.COM (Peter Fales) (11/10/89)
In article <256@telxon.UUCP>, dank@telxon.UUCP (Dan Kelley) writes: > > I am looking for an idea to duplicate output on different terminals. > Obviously, the choice at first is easy, just use the "tee" program > in this manner: > program | tee /dev/tty??? > > Well, I have done this and am still having problems getting everything > to the device(s). The trick I saw to do this recently really made me sit up and take notice... The "teacher" executes the following command: cu XXXX | tee /tmp/tmpfile where XXX is a phone number or machine name for the computer to be demonstrated (this may result in logging in to the same machine running the cu command, but not necessarily). The "students" run tail -f /tmp/tmpfile I don't totally understand why this works, but it does. You can even see all the "teacher's" key strokes in real time. -- Peter Fales AT&T, Room 5B-420 N9IYJ 2000 N. Naperville Rd. UUCP: ...att!peter.fales Naperville, IL 60566 Domain: peter.fales@att.com work: (312) 979-8031
cpcahil@virtech.uucp (Conor P. Cahill) (11/10/89)
In article <4647@cbnewsc.ATT.COM>, psfales@cbnewsc.ATT.COM (Peter Fales) writes: > cu XXXX | tee /tmp/tmpfile > > [text deleted...] > > tail -f /tmp/tmpfile > > I don't totally understand why this works, but it does. You can even > see all the "teacher's" key strokes in real time. The reason that this works is that cu starts up two programs, one that takes all of you're keyboard input and writes it out the communications port and one that reads all of the data comming in the comm port and writes it to stdout. In your example stdout is the tee, which copies the data to the logfile and writes it to the terminal. Since the data is being written to the log file, the students that read the log file will see all data comming from the comm port. You don't see all of the teacher's keystrokes, you see all of the data ouput from the system to the terminal. Many of the teacher's keystrokes are echoed back by the system so that is why you see most of them. -- +-----------------------------------------------------------------------+ | Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 ! | Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 | +-----------------------------------------------------------------------+
tom@ismdqa.intel.com (Tom Soukup ~) (11/12/89)
In article <4647@cbnewsc.ATT.COM> psfales@cbnewsc.ATT.COM (Peter Fales) writes: >In article <256@telxon.UUCP>, dank@telxon.UUCP (Dan Kelley) writes: >> I am looking for an idea to duplicate output on different terminals. >The "teacher" executes the following command: > cu XXXX | tee /tmp/tmpfile >The "students" run > tail -f /tmp/tmpfile >I don't totally understand why this works, but it does. You can even >see all the "teacher's" key strokes in real time. This works because tail -f writes the contents of the file to the standard output (the screen) and then waits. As additional characters are put into the file, tail -f continues writing them to the screen. It will continue waiting forever (I think) unless interupted. So the cu | tee copies everything that the cu echos into tmpfile and the tail prints everything that goes into tmpfile on thr students screen. Good idea, I wish I'd thought of it :-). >Peter Fales AT&T, Room 5B-420 Tom ________________________________________________________________________________ DISCLAMER: Intel doesn't agree with much of anything that I say. UUCP: {amdcad,decwrl,hplabs,oliveb,pur-ee,qantel}!intelca!mipos3!ismdqa!tom ARPA: tom%ismdqa.intel.com@relay.cs.net CSNET: tom@ismdqa.intel.com
mercer@ncrcce.StPaul.NCR.COM (Dan Mercer) (11/13/89)
In article <353@bilver.UUCP> bill@bilver.UUCP (Bill Vermillion) writes: :In article <256@telxon.UUCP-> dank@telxon.UUCP (Dan Kelley) writes: :-> :->I am looking for an idea to duplicate output on different terminals. :->Obviously, the choice at first is easy, just use the "tee" program :->in this manner: :-> program | tee /dev/tty??? :-> :->Well, I have done this and am still having problems getting everything :->to the device(s). Seems when I run something like a database package, :->I do not get the duplication as I should. In fact, I do not get the :->proper I/O from the program on my own tty. Seems "tee" is not dealing :->with I/O properly and there also may be a buffering problem. : :How about a hardware solution, and take the output going to terminal A and put :it to terminal B through a diode. : :I had a serial board fail in the mode. So that anthing on A went to A & B, :but anything directed to B stayed at B. : : : :-- :Bill Vermillion - UUCP: {uiucuxc,hoptoad,petsd}!peora!tarpit!bilver!bill : : bill@bilver.UUCP In order for tee to work, the program must use stdout and stderr for output. Vi and many other programs require a terminal, so thet open /dev/tty directly. If they are using rawmode input and output, they frequently will do ioctl against stdin, stdout or stderr. If this is a pipe, it will fail (but few people have the sense to check for the failure) and your machines termio will be all screwed up. I had to demo a programming environment that used a rawmode menuing system laid over vi. Consequently, tee would not work. Cu could not handle the high speed of the lines and the large number of rawmode transactions. So I rolled my own, called demo2tty. I can mail it to you if you like. Standard disclaimers apply (SysVr1). To all the net.policeman objecting to this type of entry, may I remind you that management looks askance at any alt groups appearing on the net, and many of us do not have alt.sources.d. -- Dan Mercer Reply-To: mercer@ncrcce.StPaul.NCR.COM (Dan Mercer)
mercer@ncrcce.StPaul.NCR.COM (Dan Mercer) (11/13/89)
I forgot to add to the last article, the use of /dev/tty by many programs makes programs that log out users logged in but not working almost impossible to implement. We're using one on our news machine that has timed me out several times while transferring files using kermit and once while editting a long article in vi. (that was the worst, cause vi didn't hang up and when I logged back on I got into vi when the machine was supposed to be asking for the dialup password. The times for /dev/tty get updated, of course, not the times for /dev/ttyxx. -- Dan Mercer Reply-To: mercer@ncrcce.StPaul.NCR.COM (Dan Mercer)
drw@schubert.math.mit.edu (Dale R. Worley) (11/14/89)
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"); }