home *** CD-ROM | disk | FTP | other *** search
- From: talcott!seismo!enea!ttds!zap (Svante Lindahl)
- Subject: rsend - BSD communications program
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 3, Issue 73
- Submitted by: seismo!enea!ttds!zap (Svante Lindahl)
-
-
- Here is a program that we use all the time, instead of
- write and talk. It can be used for one-way communication
- (like write) and over a local network (like talk).
- It is very BSD:ish, sockets and all.
-
- We have it running on three VAXen and several SUNs on our
- ethernet, and communication between VAX and SUN works fine
- (unlike talk :-( (ours does work now!)).
-
- Please, no flames, this was my first UNIX-hack, my first
- C-hack and my first communications program. Accurate criticism
- is of course welcome.
-
- : This is a shar archive. Extract with sh, not csh.
- : This archive ends with exit, so do not worry about trailing junk.
- echo 'Extracting README'
- sed 's/^X//' > README << '+ END-OF-FILE README'
- XThis is the README file for rsend.
- XThe other files you need are:
- X rsend.h - the headerfile for rsend.c and rsendd.c
- X rsend.c - the user interface
- X rsendd.c - the rsend daemon
- X rsend.1 - the manual entry for rsend
- X Makefile - makes rsend and rsendd
- X
- Xrsend is a program for sending messages to other users on a local machine
- Xor other machines in a local area network. (cf. SEND on TOPS-10). It is
- Ximplemented using sockets and will thus only run on 4.xBSD (for x>=2).
- X
- XBefore typing make, take a look at the makefile and see which compile-
- Xtime flags you want to use.
- X
- XWhen installing it you need to do the following:
- X
- X make an entry for rsend in /etc/services looking something
- X like this:
- X rsend 777/udp
- X (Where 777 is an arbitrary address less than 1024)
- X
- X put the following in /etc/rc.local to start the daemon when
- X the machine boots:
- X if [ -f /usr/net/rsendd ]; then
- X /usr/net/rsendd & echo -n ' rsendd' > /dev/console
- X fi
- X (or at least something looking remotely like this, depending
- X on whether you echo the names of local daemons to the console,
- X and where you prefer to install rsendd)
- X
- XNote that the daemon has to be started by root.
- + END-OF-FILE README
- chmod 'u=rw,g=rw,o=r' 'README'
- echo ' -rw-rw-r-- 1 zap 1154 Dec 30 23:04 README (as sent)'
- echo -n ' '
- /bin/ls -l README
- echo 'Extracting Makefile'
- sed 's/^X//' > Makefile << '+ END-OF-FILE Makefile'
- XDAEMONDIR = /usr/net
- XDESTDIR = /usr/local
- X
- XOBJECTS = rsendd.o rsend.o
- XSOURCE = rsendd.c rsend.c
- XHEADRS = rsend.h
- X
- X#
- X# Possible defines in CFLAGS are:
- X#
- X# -DDEBUG when debugging the daemon, it will run attached to a terminal
- X# compile and load with -g instead of -O, and debug it
- X# -DTEST when testing the daemon, doesn't need to be root, but can't
- X# recieve from other machines (Entry in /etc/services not needed)
- X# -DINET_D if you let the daemon be invoked by inetd (the internet daemon)
- X# when its service is required
- X# -DUNIQUE if you want the user program to check rwho database for
- X# reciever on other hosts when not logged in on the local machine
- X# (i e one username is always the same person on all machines in
- X# the local area network)
- X
- XCFLAGS = -O -DUNIQUE
- X# LDFLAGS = -O # when debugging
- X
- Xall: rsend rsendd
- X
- Xrsend: rsend.o
- X cc ${LDFLAGS} -o rsend rsend.o
- X
- Xrsendd: rsendd.o
- X cc ${LDFLAGS} -o rsendd rsendd.o
- X
- Xrsend.o: ${HEADRS}
- X
- Xrsendd.o: ${HEADRS}
- X
- Xinstall: all
- X strip rsend rsendd
- X cp rsend ${DESTDIR}/rsend
- X cp rsendd ${DAEMONDIR}/rsendd
- X chmod 755 ${DESTDIR}/rsend
- X chmod 700 ${DAEMONDIR/rsendd
- X
- Xclean:
- X rm -f *.o
- + END-OF-FILE Makefile
- chmod 'u=rw,g=r,o=r' 'Makefile'
- echo ' -rw-r--r-- 1 zap 1138 Dec 30 23:11 Makefile (as sent)'
- echo -n ' '
- /bin/ls -l Makefile
- echo 'Extracting rsend.1'
- sed 's/^X//' > rsend.1 << '+ END-OF-FILE rsend.1'
- X.TH RSEND Local "30 December 1985"
- X.SH NAME
- X.B rsend
- X\- send a message to another (possibly remote) user
- X.SH SYNOPSIS
- X.B rsend
- Xperson [ \-ttyname ] [ message ]
- X.SH DESCRIPTION
- X.I Rsend
- Xsends a message to another user on your machine,
- Xor to a user on another machine in a
- Xlocal area network.
- X.PP
- XIf you wish to send to someone on you own machine, then
- X.I person
- Xis just the person's login name. If you wish to send to
- Xa user on another host, then
- X.I person
- Xis of the form:
- X.sp
- X.in +1.5i
- X.I user@host
- X\ or\
- X.I host!user
- X\ or
- X.br
- X.I host:user
- X\ or\
- X.I host.user
- X.br
- X.in -1.5i
- X.sp
- XIf you don't specify a host or the username isn't logged in on your
- Xmachine (or doesn't even exist on your machine), the rwho\-database
- Xis searched for that user on the other hosts in the local area network.
- XIf a user is logged in several times
- Xthe tty with the least idletime is choosen to recieve
- Xthe message.
- X.PP
- X.I Rsend
- Xcan be used either with a message on the commandline
- Xor interactively. Be aware that the shell will interpret
- Xmetacharacters on the commandline, so it may be wise to
- Xquote the message, or use
- X.I rsend
- Xinteractively.
- X.PP
- XIf a message, for example ``Hello'', is supplied on the commandline
- X.I rsend
- Xwill send a message, that looks like this:
- X.PP
- X <11:47 From yourname@yourhost (yourttyname): Hello>
- X.PP
- Xand then exit.
- XThe message is preceded by, and followed by a newline so that the
- Xreciever's screen doesn't get too messed up.
- XThere is also a bell (Control\-G) included in the message
- Xto alert the recipient.
- X.PP
- XTo run
- X.I rsend
- Xinteractively omit the message from the commandline.
- X.I Rsend
- Xwill prompt ``rsend>'' and at this time the message can
- Xbe typed. Nothing will be sent until the first line of
- Xthe message is completed (unlike write(1)).
- XThe first line sent looks exactly as if
- X.I rsend
- Xhad been used with the message on the commandline.
- XThe rsend\-prompt will return and subsequent non\-empty
- Xlines will be sent, looking like this:
- X.PP
- X <yourname: text being sent>
- X.PP
- Xpreceded and followed by a newline.
- XTo exit
- X.I rsend
- Xtype either the EOF\-character, or `.' as the first
- Xand only character on a line.
- XIf the character `!' is typed first on a line a subshell
- Xwill be invoked (as specified by the environment\-variable
- XSHELL, or /bin/sh if SHELL is undefined).
- XIf the `!' is the only character on the line, the shell
- Xwill be interactive, otherwise the rest of the line
- Xwill be interpreted as a command to the shell,
- Xand the shell will exit after executing the command.
- X.PP
- XIf the reciever is logged in more than once, the
- X.I \-ttyname
- Xargument can be used to specify the appropriate
- Xterminal, e.g.
- X.I ``rsend foo@bar \-ttyd3''
- Xor
- X.I ``rsend bar!foo \-d3''.
- XIt is also possible to replace
- X.I ``user''
- Xwith a specification of a terminal when specifying
- X.I ``person'',
- Xe.g.
- X.I ``rsend \-d3''
- Xor
- X.I ``rsend \-ttyd3@bar''.
- X.SH DIAGNOSTICS
- XIf a message couldn't be sent an appropriate
- Xwarning is written to the senders terminal.
- X.SH FILES
- X/etc/utmp searched for reciever
- X/usr/spool/rwho/whod.* searched for reciever
- X/bin/sh subshell if SHELL is not found
- X.SH "SEE ALSO"
- Xmesg(1), who(1), rwho(1C), talk(1), mail(1), write(1)
- X.SH AUTHOR
- XSvante Lindahl, Royal Institute of Technology, Stockholm
- X.SH BUGS
- XPossibly!
- + END-OF-FILE rsend.1
- chmod 'u=rw,g=r,o=r' 'rsend.1'
- echo ' -rw-r--r-- 1 zap 3230 Dec 30 22:35 rsend.1 (as sent)'
- echo -n ' '
- /bin/ls -l rsend.1
- echo 'Extracting rsend.h'
- sed 's/^X//' > rsend.h << '+ END-OF-FILE rsend.h'
- X/*
- X * $Header: rsend.h,v 1.7 85/09/12 15:07:15 zap Exp $
- X */
- X
- X/*
- X * Revision 1.2 85/08/17 01:44:22 zap
- X * New format for msg - request type field added, request types can be
- X * CHECK (check if reciver is logged in and tty writeable) and SEND
- X * (go ahead and send message).
- X *
- X * Revision 1.1 85/08/16 21:42:05 zap
- X * Initial revision
- X *
- X * rsend.h 1.0 zap@bogart 1985-07-02 03:39:48
- X */
- X
- X/*
- X** Copyright (C) 1985 by Svante Lindahl.
- X**
- X** rsend - send a message to a local or remote user
- X**
- X*/
- X
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <pwd.h>
- X#include <utmp.h>
- X#include <netdb.h>
- X#include <netinet/in.h>
- X#include <stdio.h>
- X#include <errno.h>
- X#include <signal.h>
- X#include <sys/wait.h>
- X#include <sys/stat.h>
- X#include <sys/dir.h>
- X#include <sys/time.h>
- X#include "/usr/src/net/rwhod/rwhod.h"
- X
- X#define TRUE 1
- X#define FALSE 0
- X#define ever ;;
- X
- X#ifdef TEST
- X#define RENDEZ_VOUS 11147
- X#endif
- X
- X#define NAME_SIZE 9
- X#define TTY_SIZE 8
- X#define LINE_LENGTH 80
- X#define BUF_SIZE 400
- X#define HOST_NAME_SIZE 32
- X
- X#define WHDRSIZE (sizeof(wd) - sizeof (wd.wd_we))
- X
- X/* request values */
- X#define CHECK 0
- X#define SEND 1
- X
- X/* response values */
- X#define SUCCESS 0
- X#define NO_USER 1
- X#define NOT_IN 2
- X#define NOT_TTY 3
- X#define WRNG_TTY 4
- X#define NOT_USED 5
- X#define DENIED 6
- X#define OP_UTMP 7
- X#define OP_TTY 8
- X#define WR_FAIL 9
- X#define CONFUSED 10
- X#define NO_ANSW 11
- X#define CHDIR 12
- X
- X/* Seems like nr of bytes must be divisible by 4 to work between Sun and VAX */
- Xstruct rsend_msg {
- X char rcv_name[NAME_SIZE]; /* 9 */
- X char rcv_tty[TTY_SIZE]; /* 8 */
- X char rqst_type; /* 1 */
- X char fill[2]; /* 2 */
- X char text[BUF_SIZE]; /* 400 */
- X} msg;
- X
- X/* Seems like nr of bytes must be divisible by 4 to work between Sun and VAX */
- Xstruct rsend_rsp {
- X char code; /* 1 */
- X char fill[2]; /* 2 */
- X char rcv_name[NAME_SIZE]; /* 9 */
- X char rcv_tty[TTY_SIZE]; /* 8 */
- X} rsp;
- X
- Xextern int errno;
- + END-OF-FILE rsend.h
- chmod 'u=r,g=r,o=r' 'rsend.h'
- echo ' -r--r--r-- 1 zap 1990 Sep 12 15:07 rsend.h (as sent)'
- echo -n ' '
- /bin/ls -l rsend.h
- echo 'Extracting rsendd.c'
- sed 's/^X//' > rsendd.c << '+ END-OF-FILE rsendd.c'
- X#ifndef lint
- Xstatic char *RCSid = "$Header: rsendd.c,v 1.8 85/12/30 22:56:16 zap Exp $";
- Xstatic char *Copyright = "rsendd.c Copyright (C) 1985 Svante Lindahl.";
- X#endif
- X
- X/*
- X * $Log: rsendd.c,v $
- X * Revision 1.8 85/12/30 22:56:16 zap
- X * Made lint happier.
- X *
- X * Revision 1.7 85/10/06 19:50:46 zap
- X * Problem: daemon would occasionally get hung, fix(?): timeout after 3
- X * seconds in wait and send a SIGKILL to the child.
- X *
- X * Revision 1.6 85/10/06 19:04:30 zap
- X * Bugfix; didn't recognize that a tty was unused, badly placed '!' removed.
- X *
- X * Revision 1.5 85/08/21 18:27:59 zap
- X * Better way of finding tty with least idletime.
- X *
- X * Revision 1.4 85/08/19 23:09:44 zap
- X * The daemon now tries to find reciver's job with least idletime if no
- X * particular tty is requested.
- X *
- X * Revision 1.3 85/08/19 21:10:34 zap
- X * Some small fixes.
- X *
- X * Revision 1.2 85/08/17 01:31:28 zap
- X * Checks if person is logged in and tty is writeable when called with
- X * request type CHECK, only writes on tty with request is set to SEND.
- X *
- X * Revision 1.1 85/08/16 21:40:20 zap
- X * Initial revision
- X *
- X * rsendd.c 1.0 zap@bogart 1985-07-05 18:00:30
- X *
- X */
- X
- X/*
- X** rsendd - daemon for rsend a message sending program
- X**
- X** This program, and any documentation for it, is copyrighted by Svante
- X** Lindahl. It may be copied for non-commercial use only, provided that
- X** any and all copyright notices are preserved.
- X**
- X** Please report any bugs and/or fixes to:
- X**
- X** UUCP: {seismo,mcvax,cernvax,diku,ircam,prlb2,tut,ukc,unido}!enea!ttds!zap
- X** ARPA: enea!ttds!zap@seismo.ARPA
- X** or Svante_Lindahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA
- X**
- X*/
- X
- X#include "rsend.h"
- X
- X#include <fcntl.h>
- X#include <sys/ioctl.h>
- X#include <sys/resource.h>
- X
- X#ifdef INET_D
- X#define TIMEOUT 30 /* let the daemon time out and exit if.. */
- X#define MAXIDLE 120 /* ..it is invoked by the inet-daemon */
- X#endif
- X
- Xstruct sockaddr_in sin, from ;
- Xint fromlen = sizeof(from) ;
- Xextern int doit() ;
- X
- X#ifndef DEBUG
- Xint pid ;
- Xlong lastmsgtime ;
- X#endif
- X
- Xmain ()
- X{
- X int s, f, cc, w;
- X union wait status;
- X int (*saveintr)(), (*savequit)();
- X struct passwd *getpwnam() ;
- X struct servent *sp ;
- X#ifndef DEBUG
- X extern void reaper(), chaser() ;
- X#endif
- X#ifdef INET_D
- X extern void timeout() ;
- X#endif
- X
- X sin.sin_addr.s_addr = INADDR_ANY ;
- X sin.sin_family = AF_INET ;
- X#ifndef TEST
- X if (getuid()) {
- X fprintf (stderr, "rsendd: not super user\n") ;
- X exit(1) ;
- X }
- X sp = getservbyname("rsend", "udp") ;
- X if (sp == NULL) {
- X fprintf (stderr, "rsendd: udp/rsend: unknown service\n") ;
- X exit(1) ;
- X }
- X sin.sin_port = sp->s_port ;
- X#else
- X sin.sin_port = htons(RENDEZ_VOUS) ;
- X#endif
- X#ifndef DEBUG
- X /* fork, parent quits, child dissociates itself from the tty */
- X if (fork())
- X _exit(0) ;
- X for (f = 0 ; f < 5 ; f++)
- X (void) close(f) ;
- X (void) open("/dev/null", O_RDONLY) ;
- X (void) open("/dev/null", O_WRONLY) ;
- X (void) dup(1) ;
- X if ((f = open("/dev/tty", O_RDWR)) > 0) {
- X (void) ioctl(f, (int) TIOCNOTTY, (char *) 0) ;
- X (void) close(f) ;
- X }
- X s = socket(AF_INET, SOCK_DGRAM, 0) ;
- X if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- X perror("rsendd: bind") ;
- X exit(1) ;
- X }
- X (void) signal(SIGCHLD, reaper) ; /* try not to leave zombies around */
- X for(ever) {
- X cc = recvfrom(s, (char *)&msg, sizeof(msg),
- X 0, (struct sockaddr *) &from, &fromlen);
- X if ((pid = vfork()) == 0)
- X exit(doit(s, cc)) ;
- X (void) time(&lastmsgtime) ;
- X saveintr = signal(SIGINT, SIG_IGN) ;
- X savequit = signal(SIGQUIT, SIG_IGN) ;
- X (void) signal(SIGALRM, chaser) ;
- X (void) alarm(3);
- X while ((w = wait(&status)) != pid && w != -1)
- X ;
- X (void) signal(SIGQUIT, saveintr) ;
- X (void) signal(SIGQUIT, savequit) ;
- X#ifdef INET_D
- X (void) signal(SIGALRM, timeout) ;
- X (void) alarm(TIMEOUT) ;
- X#else
- X (void) alarm(0) ;
- X#endif
- X }
- X#else
- X s = socket(AF_INET, SOCK_DGRAM, 0) ;
- X if (bind(s, &sin, sizeof(sin)) < 0) {
- X perror("rsendd: bind") ;
- X exit(1) ;
- X }
- X for(ever) {
- X cc = recvfrom(s, (char *)&msg, sizeof(msg), 0, &from, &fromlen) ;
- X doit(s, cc) ;
- X }
- X#endif
- X}
- X
- Xint
- Xdoit(s, cc)
- X int s, cc ;
- X{
- X int f, i, idle = -1 ;
- X struct stat st ;
- X struct utmp ut ;
- X struct passwd *pwp ;
- X long now ;
- X
- X if (cc != sizeof(msg)) {
- X if (cc < 0 && errno != EINTR)
- X perror("recvfrom") ;
- X return(1) ;
- X }
- X if (chdir("/dev") < 0)
- X rsp.code = CHDIR ;
- X else if (*msg.rcv_tty != '\0') {
- X (void) strcpy(rsp.rcv_tty, msg.rcv_tty) ;
- X if (stat(msg.rcv_tty, &st) < 0)
- X rsp.code = NOT_TTY ;
- X else if (((st.st_uid == 0) && (strcmp(msg.rcv_name, "root")))
- X || (pwp = getpwuid(st.st_uid)) == NULL)
- X rsp.code = NOT_USED ;
- X else if (*msg.rcv_name != '\0') {
- X (void) strcpy(rsp.rcv_name, msg.rcv_name) ;
- X if (getpwnam(msg.rcv_name) == NULL)
- X rsp.code = NO_USER ;
- X else if (strcmp(msg.rcv_name, pwp->pw_name) != 0)
- X rsp.code = WRNG_TTY ;
- X else if (!(st.st_mode & 2))
- X rsp.code = DENIED ;
- X else
- X rsp.code = SUCCESS ;
- X } else {
- X if (!(st.st_mode & 2))
- X rsp.code = DENIED ;
- X else {
- X rsp.code = SUCCESS ;
- X (void) strcpy(rsp.rcv_name, pwp->pw_name) ;
- X }
- X }
- X } else if (*msg.rcv_name != '\0') {
- X (void) strcpy(rsp.rcv_name, msg.rcv_name) ;
- X if (getpwnam(msg.rcv_name) == NULL)
- X rsp.code = NO_USER ;
- X else if ((f = open ("/etc/utmp", 0)) < 0)
- X rsp.code = OP_UTMP ;
- X else { /* search for reciver in /etc/utmp */
- X rsp.code = NOT_IN ;
- X (void) time(&now) ;
- X while (read (f, (char *)&ut, sizeof(ut)) > 0) {
- X if (strcmp(msg.rcv_name, ut.ut_name) == 0) {
- X if ((stat(ut.ut_line, &st) >= 0) && (st.st_mode & 2)
- X && (((i = now - st.st_mtime) < idle) || (idle = -1))) {
- X (void) strcpy(rsp.rcv_tty, ut.ut_line) ;
- X rsp.code = SUCCESS ;
- X idle = i ;
- X } else if (rsp.code != SUCCESS) {
- X (void) strcpy(rsp.rcv_tty, ut.ut_line) ;
- X rsp.code = DENIED ;
- X }
- X }
- X }
- X (void) close(f) ;
- X }
- X } else
- X rsp.code = CONFUSED ; /* hopefully not reached... */
- X
- X if (rsp.code == SUCCESS) { /* found somewhere to send it */
- X if ((f = open(rsp.rcv_tty, O_WRONLY)) < 0)
- X rsp.code = OP_TTY ;
- X else if (msg.rqst_type == SEND) {
- X if (write(f, msg.text, strlen(msg.text)) != strlen(msg.text))
- X rsp.code = WR_FAIL ;
- X (void) close(f) ;
- X }
- X }
- X /* send status report to the sender */
- X cc = sendto(s, (char *)&rsp, sizeof(rsp),
- X 0, (struct sockaddr *) &from, sizeof(from)) ;
- X return(cc == sizeof(rsp) ? 0 : -1) ;
- X}
- X
- X#ifdef INET_D
- Xvoid
- Xtimeout()
- X{
- X long now ;
- X
- X (void) time(&now) ;
- X if (now - lastmsgtime >= MAXIDLE)
- X exit(0) ;
- X (void) alarm(TIMEOUT) ;
- X}
- X#endif
- X
- X#ifndef DEBUG
- Xvoid
- Xreaper() /* takes care of getting rid of zombie-children */
- X{
- X union wait status ;
- X
- X while (wait3(&status, WNOHANG, (struct rusage *) 0) > 0) ;
- X}
- X
- Xvoid
- Xchaser() /* chase down children that refuse to die */
- X{
- X (void) kill(pid, SIGKILL) ;
- X}
- X#endif
- + END-OF-FILE rsendd.c
- chmod 'u=r,g=r,o=r' 'rsendd.c'
- echo ' -r--r--r-- 1 zap 7552 Dec 30 22:56 rsendd.c (as sent)'
- echo -n ' '
- /bin/ls -l rsendd.c
- echo 'Extracting rsend.c'
- sed 's/^X//' > rsend.c << '+ END-OF-FILE rsend.c'
- X#ifndef lint
- Xstatic char *RCSid = "$Header: rsend.c,v 1.7 85/12/30 22:54:02 zap Exp $";
- Xstatic char *Copyright = "rsend.c Copyright (C) 1985 Svante Lindahl.";
- X#endif
- X
- X/*
- X * $Log: rsend.c,v $
- X * Revision 1.7 85/12/30 22:54:02 zap
- X * Made lint happier. Fixed bug, replacing strcmp with strncmp.
- X *
- X * Revision 1.6 85/10/06 19:01:35 zap
- X * Bugfix; working directory was "wrong" when shellescape invoked, now
- X * does a chdir back after checking things in /dev & /usr/spool/rwho.
- X *
- X * Revision 1.5 85/08/21 17:37:12 zap
- X * Now chooses to send to writeable tty with least idletime if reciever
- X * is logged in more than once on the local host.
- X *
- X * Revision 1.4 85/08/19 23:08:56 zap
- X * Small change.
- X *
- X * Revision 1.3 85/08/19 21:27:51 zap
- X * When no host is specified and the reciever isn't logged in on the local
- X * host the rwho database is searched to find reciever on an other machine
- X * in the local area network. If logged in several times on other hosts the
- X * tty (pty) with the least idletime is selected.
- X *
- X * Revision 1.2 85/08/17 01:40:41 zap
- X * Now checks if reciever is logged in and tty is writeable before entering
- X * interactive mode.
- X *
- X * Revision 1.1 85/08/16 21:41:09 zap
- X * Initial revision
- X *
- X * rsend.c 1.0 zap@bogart 1985-07-23 21:29:27
- X *
- X */
- X
- X/*
- X** rsend - send a message to a local or remote user
- X**
- X** This program, and any documentation for it, is copyrighted by Svante
- X** Lindahl. It may be copied for non-commercial use only, provided that
- X** any and all copyright notices are preserved.
- X**
- X** Please report any bugs and/or fixes to:
- X**
- X** UUCP: {seismo,mcvax,cernvax,diku,ircam,prlb2,tut,ukc,unido}!enea!ttds!zap
- X** ARPA: enea!ttds!zap@seismo.ARPA
- X** or Svante_Lindahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA
- X**
- X*/
- X
- X#include "rsend.h"
- X
- X#define TIMEOUT 2 /* seconds */
- X
- Xint Argc, remotesend, interactive = FALSE ;
- Xchar **Argv, *my_name, *my_tty ;
- Xchar my_cpu[HOST_NAME_SIZE] ;
- Xchar rcv_cpu[HOST_NAME_SIZE] ;
- Xstruct sockaddr_in sin;
- X
- Xchar *getlogin(), *ttyname(), *rindex() ;
- Xstruct hostent *gethostbyname() ;
- Xstruct servent *getservbyname() ;
- X
- Xextern void err_check () ;
- Xextern void who_am_i () ;
- Xextern void who_is_rcvr () ;
- Xextern void set_up_msg() ;
- Xextern void set_up_tty() ;
- Xextern int where_is_rcvr () ;
- Xextern void where_to () ;
- Xextern void check_it () ;
- Xextern void be_interactive () ;
- Xextern void do_shell ();
- Xextern void build_msg () ;
- Xextern int build_header () ;
- Xextern void send_it () ;
- Xextern void timeout() ;
- Xextern void error_handle() ;
- X
- Xmain (argc, argv)
- X int argc ;
- X char **argv ;
- X{
- X Argc = argc ;
- X Argv = argv ;
- X err_check () ;
- X who_am_i () ;
- X who_is_rcvr () ;
- X where_to () ;
- X if (interactive) {
- X check_it () ;
- X be_interactive() ;
- X } else {
- X build_msg () ;
- X send_it () ;
- X }
- X}
- X
- Xvoid
- Xerr_check ()
- X{
- X if (Argc < 2 ) {
- X fprintf(stderr,
- X "Usage: rsend user[@host] [-tty] [message...]\n") ;
- X exit(1) ;
- X }
- X if (!isatty(0)) {
- X fprintf(stderr,
- X "rsend: Sorry, standard input must be a tty!\n") ;
- X exit(1) ;
- X }
- X}
- X
- Xvoid
- Xwho_am_i ()
- X{
- X struct passwd *pwp ;
- X
- X my_name = getlogin() ;
- X if (*my_name == NULL)
- X if ((pwp = getpwuid(getuid())) == NULL) {
- X fprintf(stderr, "You are not for real!.\n") ;
- X exit(1) ;
- X }
- X else
- X my_name = (char *)pwp->pw_name ;
- X my_tty = rindex(ttyname(0), '/') + 1 ;
- X (void) gethostname(my_cpu, sizeof(my_cpu)) ;
- X}
- X
- Xvoid
- Xwho_is_rcvr ()
- X{
- X char *ptr ;
- X int code ;
- X
- X Argc-- ; Argv++ ;
- X *msg.rcv_tty = '\0' ;
- X *msg.rcv_name = '\0' ;
- X for (ptr = *Argv ; *ptr != '\0' && *ptr != '@' && *ptr != ':'
- X && *ptr != '!' && *ptr != '.' ; ptr++)
- X ;
- X if (*ptr == '\0') { /* no host specified */
- X set_up_msg(*Argv, my_cpu) ;
- X if (*msg.rcv_tty == '\0') {
- X if ((code = where_is_rcvr()) != SUCCESS)
- X error_handle(code) ;
- X }
- X } else {
- X if (*ptr == '@') { /* user@host || -tty@host */
- X *ptr++ = '\0' ;
- X set_up_msg(*Argv, ptr) ;
- X } else { /* host[.!:]user || host[.!:]-tty */
- X *ptr++ = '\0' ;
- X set_up_msg(ptr, *Argv) ;
- X }
- X }
- X remotesend = strcmp(rcv_cpu, my_cpu) ;
- X Argc-- ; Argv++ ;
- X if (Argc == 0) /* anything left on the commandline? */
- X interactive = TRUE ;
- X else if (**Argv == '-') { /* tty-specification? */
- X set_up_tty(&Argv[0][1]) ;
- X Argc-- ; Argv++ ;
- X if (Argc == 0) /* still more? */
- X interactive = TRUE ;
- X }
- X}
- X
- Xvoid
- Xset_up_msg(ptr, cpu)
- X char *ptr, *cpu;
- X{
- X if (*ptr != '-') /* reciever's username or tty? */
- X (void) strcpy(msg.rcv_name, ptr) ;
- X else
- X set_up_tty(++ptr) ;
- X (void) strcpy(rcv_cpu, cpu) ;
- X}
- X
- Xvoid
- Xset_up_tty(ptr)
- X char *ptr ;
- X{
- X if (!strcmp("console", ptr))
- X (void) strcpy(msg.rcv_tty, ptr) ;
- X else {
- X if (strncmp("tty", ptr, 3))
- X (void) strcpy(msg.rcv_tty, "tty") ;
- X (void) strcat(msg.rcv_tty, ptr) ;
- X }
- X msg.rcv_tty[TTY_SIZE-1] = '\0' ;
- X}
- X
- Xint
- Xwhere_is_rcvr()
- X{
- X int code, f, i, idle = -1, nowd = 0 ;
- X char path[1024], *getwd() ;
- X struct stat st ;
- X struct utmp ut ;
- X long now ;
- X
- X if (getwd(path) == '\0')
- X nowd++ ;
- X if (getpwnam(msg.rcv_name) == NULL)
- X code = NO_USER ;
- X else if ((f = open ("/etc/utmp", 0)) < 0)
- X code = OP_UTMP ;
- X else if (chdir("/dev") < 0)
- X code = CHDIR ;
- X else {
- X code = NOT_IN ; /* search for reciver in /etc/utmp */
- X (void) time(&now) ;
- X while (read(f, (char *)&ut, sizeof(ut)) > 0) {
- X if (strncmp (msg.rcv_name, ut.ut_name, 8) == 0) {
- X if ((stat(ut.ut_line, &st) >= 0) && (st.st_mode & 2)
- X && (((i = now - st.st_mtime) < idle) || (idle = -1))) {
- X (void) strcpy(msg.rcv_tty, ut.ut_line) ;
- X code = SUCCESS ;
- X idle = i ;
- X } else if (code != SUCCESS) {
- X (void) strcpy(msg.rcv_tty, ut.ut_line) ;
- X code = DENIED ;
- X }
- X }
- X }
- X (void) close(f) ;
- X }
- X#ifdef UNIQUE
- X {
- X int cc, n ;
- X DIR *dirp ;
- X struct direct *dp ;
- X struct whoent *we ;
- X struct whod wd ;
- X register struct whod *wp = &wd ;
- X
- X if ( ((code == NO_USER) || (code == NOT_IN) || (code == CHDIR))
- X && (chdir("/usr/spool/rwho") >= 0)
- X && ((dirp = opendir(".")) != NULL)) {
- X /* check other machines in local network (use rwho database) */
- X (void) time(&now) ;
- X while (dp = readdir (dirp)) {
- X if ((dp->d_ino == 0) || (strncmp(dp->d_name, "whod.", 5)))
- X continue ;
- X if ((f = open(dp->d_name, 0)) < 0)
- X continue ;
- X cc = read(f, (char *)&wd, sizeof(struct whod)) ;
- X if ((cc < WHDRSIZE) || (now - wp->wd_recvtime > 5 * 60)
- X || (!strcmp (my_cpu, wp->wd_hostname))) {
- X (void) close (f) ;
- X continue ;
- X }
- X for(we = wp->wd_we,
- X n = (cc - WHDRSIZE) / sizeof(struct whoent);
- X n > 0; n--, we++) {
- X if (strncmp(msg.rcv_name, we->we_utmp.out_name, 8))
- X continue ;
- X if ((i = we->we_idle) < idle || idle == -1) {
- X code = SUCCESS ;
- X idle = i ;
- X (void) strcpy(rcv_cpu, wp->wd_hostname) ;
- X (void) strcpy(msg.rcv_tty, we->we_utmp.out_line) ;
- X }
- X }
- X (void) close (f) ;
- X }
- X if (code == SUCCESS)
- X fprintf(stderr, "%s not logged in on %s, sending to %s@%s\n",
- X msg.rcv_name, my_cpu, msg.rcv_name, rcv_cpu) ;
- X }
- X }
- X#endif
- X if (!nowd)
- X (void) chdir(path) ;
- X return(code) ;
- X}
- X
- Xvoid
- Xwhere_to()
- X{
- X struct hostent *hp ;
- X struct servent *sp ;
- X
- X hp = gethostbyname(rcv_cpu) ; /* get address of reciever's machine */
- X if (hp == (struct hostent *) 0 ) {
- X fprintf(stderr, "rsend: I don't know a machine named %s\n", rcv_cpu) ;
- X exit(1) ;
- X }
- X bzero(&sin, sizeof (sin)) ;
- X bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length) ;
- X sin.sin_family = hp->h_addrtype ;
- X#ifndef TEST
- X sp = getservbyname("rsend", "udp") ; /* find daemon's port */
- X if (sp == NULL) {
- X fprintf(stderr, "rsend isn't supported by this machine\n") ;
- X exit(1) ;
- X }
- X sin.sin_port = sp->s_port ;
- X#else
- X if (remotesend) { /* remote sends not supported when testing */
- X fprintf(stderr,
- X "Sorry, only local sends are supported at this time\n") ;
- X exit(1) ;
- X }
- X sin.sin_port = htons(RENDEZ_VOUS) ; /* find daemon's port */
- X#endif
- X}
- X
- Xvoid
- Xcheck_it()
- X{
- X msg.rqst_type = CHECK ;
- X send_it() ;
- X msg.rqst_type = SEND ;
- X}
- X
- Xvoid
- Xbe_interactive()
- X{
- X int hdr_siz, i ;
- X char buf[BUF_SIZE] ;
- X
- X hdr_siz = build_header () ; /* standard header for first message */
- X msg.text[hdr_siz++] = ' ' ;
- X msg.text[hdr_siz] = '\0' ;
- X for(ever) {
- X printf("rsend>") ; /* prompt for input */
- X (void) fflush(stdout) ;
- X if (fgets(buf, sizeof(buf), stdin) != NULL) {
- X if ((i = strlen(buf)) > 1) {
- X buf[--i] = '\0' ; /* nullify the \n from fgets */
- X if (i == 1 && *buf == '.') /* '.' to exit pgm */
- X break ;
- X else if (*buf == '!')
- X do_shell(i, buf) ;
- X else {
- X if (hdr_siz + i > LINE_LENGTH) /* separate header if .. */
- X (void) strcat(msg.text, "\r\n") ; /* .. long message */
- X if (hdr_siz + i + 8 > BUF_SIZE) { /* too much... */
- X (void) strncat(msg.text, buf, BUF_SIZE-hdr_siz-i-8) ;
- X (void) strcat(msg.text, "...\r\n") ;
- X fprintf(stderr,
- X "rsend: long message, %d word(s) truncated\n",
- X Argc + 1) ;
- X } else {
- X (void) strcat(msg.text, buf) ;
- X (void) strcat(msg.text, ">\r\n") ;
- X }
- X msg.text[BUF_SIZE-1] = '\0' ;
- X send_it() ;
- X (void) sprintf(msg.text, "\r\n<%s: ", my_name) ;
- X hdr_siz = strlen(msg.text) ;
- X }
- X }
- X } else {
- X printf("\r\n") ;
- X break ;
- X }
- X }
- X}
- X
- Xvoid
- Xdo_shell (i, cmd)
- X int i ;
- X char *cmd ;
- X{
- X int pid, w ;
- X union wait status ;
- X char *sh, *getenv() ;
- X int (*saveintr)(), (*savequit)() ;
- X
- X if ((sh = getenv("SHELL")) == NULL)
- X sh = "/bin/sh" ;
- X if (i == 1) { /* interactive shell */
- X if ((pid = vfork()) == 0)
- X execl(sh, sh, (char *) 0) ;
- X }
- X else if ((pid = vfork ()) == 0) /* do one commandline */
- X execl(sh, sh, "-c", ++cmd, (char *) 0) ;
- X saveintr = signal(SIGINT, SIG_IGN) ;
- X savequit = signal(SIGQUIT, SIG_IGN) ;
- X while ((w = wait(&status)) != pid && w != -1)
- X ;
- X if (i == 1)
- X printf("\n") ;
- X (void) signal(SIGINT, saveintr) ;
- X (void) signal(SIGQUIT, savequit) ;
- X}
- X
- Xvoid
- Xbuild_msg ()
- X{
- X int hdr_siz, too_much = FALSE ;
- X char buf[BUF_SIZE] ;
- X
- X msg.rqst_type = SEND ;
- X hdr_siz = build_header() ;
- X while (Argc--) { /* copy everything from the commandline */
- X (void) strcat(buf, " ") ;
- X if (hdr_siz + strlen(buf) + 8 + strlen(*Argv) > BUF_SIZE ) {
- X too_much = TRUE ;
- X break ;
- X }
- X (void) strcat(buf, *Argv++) ;
- X }
- X if (hdr_siz + strlen(buf) > LINE_LENGTH) /* separate heading from .. */
- X (void) strcat(msg.text, "\r\n") ; /* ..message if it's long */
- X (void) strcat(msg.text, buf) ;
- X if (too_much) {
- X (void) strcat(msg.text, "...\r\n") ;
- X fprintf(stderr,
- X "rsend: long message, %d word(s) truncated\n", Argc + 1) ;
- X }
- X else
- X (void) strcat(msg.text, ">\r\n") ;
- X msg.text[BUF_SIZE-1] = '\0' ; /* just to make sure...*/
- X}
- X
- Xint
- Xbuild_header ()
- X{
- X long clock ;
- X struct tm *tp, *localtime() ;
- X
- X (void) time(&clock) ; /* message header: "<11:47 From foo@bar (ttyxx):" */
- X tp = localtime(&clock) ;
- X (void) sprintf(msg.text,"\r\n\007<%d:%02d From %s@%s (%s):",
- X tp->tm_hour, tp->tm_min, my_name, my_cpu, my_tty) ;
- X return(strlen(msg.text)) ;
- X}
- X
- Xvoid
- Xsend_it ()
- X{
- X struct sockaddr from ;
- X int s, cc, fromlen = sizeof(from) ;
- X
- X s = socket(AF_INET, SOCK_DGRAM, 0) ; /* get a socket */
- X if (s < 0) {
- X perror("rsend: socket") ;
- X exit(1) ;
- X }
- X /* send to address in 'sin' through socket to (possibly remote) daemon */
- X cc = sendto(s, (char *)&msg, sizeof(msg),
- X 0, (struct sockaddr *)&sin, sizeof (sin)) ;
- X if (cc != sizeof(msg)) {
- X perror("sendto") ;
- X exit(1) ;
- X }
- X rsp.code = NO_ANSW ;
- X (void) signal(SIGALRM, timeout) ;/* will not wait forever for a response */
- X (void) alarm(TIMEOUT) ;
- X (void) recvfrom(s, (char *)&rsp, sizeof(rsp), 0, &from, &fromlen) ;
- X (void) close(s) ;
- X (void) alarm(0) ; /* don't time out on an interactive user */
- X if (*msg.rcv_name == '\0')
- X (void) strcpy(msg.rcv_name, rsp.rcv_name) ;
- X if (*msg.rcv_tty == '\0')
- X (void) strcpy(msg.rcv_tty, rsp.rcv_tty) ;
- X if (rsp.code != SUCCESS)
- X error_handle(rsp.code) ;
- X}
- X
- Xvoid
- Xtimeout ()
- X{
- X fprintf(stderr, "rsend: timeout before acknowledged by rsend-daemon@%s\n",
- X rcv_cpu) ;
- X exit(0) ;
- X}
- X
- Xvoid
- Xerror_handle (errcod)
- X int errcod ;
- X{
- X char errmsg[BUF_SIZE] ;
- X char recvr[NAME_SIZE + HOST_NAME_SIZE + 1] ;
- X char daemon_at[HOST_NAME_SIZE + 15] ;
- X
- X if (remotesend) {
- X (void) sprintf(recvr, "%s@%s", msg.rcv_name, rcv_cpu) ;
- X (void) sprintf(daemon_at, "rsend-daemon@%s", rcv_cpu) ;
- X (void) strcat(rcv_cpu, ":") ;
- X } else {
- X (void) strcpy(recvr, msg.rcv_name) ;
- X (void) strcpy(daemon_at, "rsend-daemon") ;
- X *rcv_cpu = '\0' ;
- X }
- X
- X switch (errcod) {
- X case NO_USER :
- X (void) sprintf(errmsg, "%s: no such user", recvr) ;
- X break ;
- X case NOT_IN :
- X (void) sprintf(errmsg, "%s not logged in", recvr) ;
- X break ;
- X case NOT_TTY :
- X (void) sprintf(errmsg, "%s/dev/%s no such device",
- X rcv_cpu, msg.rcv_tty) ;
- X break ;
- X case WRNG_TTY :
- X (void) sprintf(errmsg, "%s is not on %s", recvr, msg.rcv_tty) ;
- X break ;
- X case NOT_USED :
- X (void) sprintf(errmsg, "%s/dev/%s is not in use",
- X rcv_cpu, msg.rcv_tty) ;
- X break ;
- X case DENIED :
- X (void) sprintf(errmsg,
- X "%s/dev/%s: permission denied, try mail instead",
- X rcv_cpu, msg.rcv_tty) ;
- X break ;
- X case OP_UTMP :
- X (void) sprintf(errmsg, "cannot open %s/etc/utmp", rcv_cpu) ;
- X break ;
- X case OP_TTY :
- X (void) sprintf(errmsg, "cannot open %s/dev/%s", rcv_cpu, msg.rcv_tty) ;
- X break ;
- X case WR_FAIL :
- X (void) sprintf(errmsg, "couldn't write on %s/dev/%s",
- X rcv_cpu, msg.rcv_tty) ;
- X break ;
- X case CONFUSED :
- X (void) sprintf(errmsg, "%s is confused", daemon_at) ;
- X break ;
- X case NO_ANSW :
- X (void) sprintf(errmsg, "no answer from %s", daemon_at) ;
- X break ;
- X case CHDIR :
- X (void) sprintf(errmsg, "couldn't chdir to /dev") ;
- X break ;
- X default :
- X (void) sprintf(errmsg,
- X "this cannot happen! (unknown error, no:%d)", errcod) ;
- X }
- X fprintf(stderr, "rsend: %s\n", errmsg) ;
- X exit(1) ;
- X}
- + END-OF-FILE rsend.c
- chmod 'u=r,g=r,o=r' 'rsend.c'
- echo ' -r--r--r-- 1 zap 15648 Dec 30 22:55 rsend.c (as sent)'
- echo -n ' '
- /bin/ls -l rsend.c
- exit 0
-
- --
- Svante Lindahl, NADA, KTH Numerical Analysis & Computer Science
- Phone: +46-8-787-7146 Royal Institute of Technology
- UUCP: {seismo,mcvax}!enea!ttds!zap ARPA: enea!ttds!zap@seismo.CSS.GOV
-
-