nick@nswitgould.OZ (Nick Andrew) (03/30/89)
Although Minix is not very sophisticated multi-user wise, I thought it needed a Write command. Someday somebody will realise Minix is a nice way to run a fairly inexpensive Unix-based BBS - and they may find write(1) handy. Please send any suggestions for improvement to nick@nswitgould.oz. ------------------------------- hack here ------------------------------- echo x - write.1 sed '/^X/s///' > write.1 << '/' XCommand: write - send messages to a logged-in user XSyntax: write [flags] user [tty] XFlags: -c to use cbreak mode X -v verbose mode X X Write lets a user send messages to another logged-in user. Lines typed by Xthe user appear on the other user's screen a line at a time (a character at Xa time in the case of cbreak mode). The file /usr/adm/wtmp is searched to Xdetermine which tty to send to. If the user is logged onto more than one Xterminal, the 'tty' argument (eg. tty1) specifies which terminal to write Xon. Type EOF (control D) to terminate the write command. A typed line Xwith '!' as the first character of the line is a shell escape. The rest of Xthe line is executed by the system() call, using /bin/sh as the shell. X XBUGS: Shell escape does not function in cbreak mode X Verbose mode is ineffectual. / echo x - write.c sed '/^X/s///' > write.c << '/' X/* write(1) - write to a logged-in user X * Author: Nick Andrew (nick@nswitgould.oz) - Public Domain X * Minix version: 1.4a, 30 March 1989 X * X * Usage: write [flags] user [tty] X * flags: -c Read & write one character at a time (cbreak mode) X * -v Verbose X * X * NOTES: X * Write requires 1.4a (or higher) libraries, for getopt(), strchr(). X * X * BUGS: X * Shell escape is not supported when in cbreak mode. X * Verbose mode is ineffectual. X */ X X#include <stdio.h> X#include <pwd.h> X#include <sgtty.h> X#include <signal.h> X Xextern long time(); Xextern char *ttyname(); Xextern struct passwd *getpwnam(); Xextern int optind; X Xlong now; X Xint otty, i, wtmpfd; X Xchar *user = NULL, *tty = NULL, wtmptty[8], optstring[]="cv"; Xchar *ourtty, othertty[16], c, line[80], ourname[9]; Xchar *wtmpfile = "/usr/adm/wtmp"; X Xshort cbreak = 0, verbose = 0, writing = 0; X Xstruct passwd *userptr; Xstruct sgttyb ttyold, ttynew; X Xstruct wtmprec { X char wt_line[8]; X char wt_name[8]; X long wt_time; X} wtmp; X X#define show(var,true,false) \ X fprintf(stderr,"var:\t%s\n", var ? true : false) X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X setbuf(stdout,NULL); X X /* parse options */ X while ((c=getopt(argc,argv,optstring)) != EOF) switch(c) { X case 'c': X cbreak = 1; X break; X case 'v': X verbose = 1; X break; X default: X usage(); X } X X /* parse user and tty arguments */ X if (optind < argc) { X user = argv[optind++]; X if (strlen(user) > 8) X err("username must be 1 to 8 characters long\n"); X if (optind<argc) { X tty = argv[optind++]; X if (optind<argc) usage(); X } X } X else usage(); X X finduser(); /* find which tty to write onto */ X settty(); /* setup our terminal */ X sayhello(); /* print the initial message */ X writetty(); /* the write loop */ X X stty(0,&ttyold); X exit(0); X} X Xusage() { X fprintf(stderr,"usage: write [flags] user [tty]\n"); X fprintf(stderr,"flags: -c == cbreak mode, -v == verbose\n"); X exit(255); X} X X/* search the accumulated who file for the user we want */ X Xfinduser() { X ourtty = ttyname(); X if (ourtty == NULL) ourtty = "/dev/tty0"; X X if (user == NULL) exit(1); X if ((userptr=getpwnam(user))==NULL) { X fprintf(stderr,"No such user: %s\n",user); X exit(1); X } X X fprintf(stderr,"Trying to write to %s\n",userptr->pw_gecos); X X if ((wtmpfd = open(wtmpfile,0))<0) X err("Cannot open wtmp file\n"); X X wtmptty[0] = '\0'; X while (read(wtmpfd, &wtmp, sizeof(wtmp)) == sizeof(wtmp)) { X X /* we want to find if steve is logged on, and return in X wtmptty[] steve's terminal, and if steve is logged onto the X tty the user specified, return that tty name X */ X X /* reboot, nobody's logged on */ X if (!strcmp(wtmp.wt_line, "~")) { X wtmptty[0] = '\0'; X continue; X } X X /* we found a tty that steve used, but this is a logoff */ X if (!strcmp(wtmp.wt_line,wtmptty) && wtmp.wt_name[0]==0) { X wtmptty[0] = '\0'; X continue; X } X X /* is this steve logging on? */ X if (strcmp(wtmp.wt_name,user)) continue; X X /* is he on the terminal we want to write to? */ X if (tty==NULL || strcmp(wtmptty,tty)) /* not yet apparently */ X strcpy(wtmptty,wtmp.wt_line); /* on somewhere */ X } X X if (wtmptty[0] == 0) { X fprintf(stderr,"%s is not logged on\n",user); X exit(1); X } X X if (strcmp(wtmptty,tty) && tty!=NULL) { X fprintf(stderr,"%s is logged onto %s not %s\n", X user,wtmptty,tty); X exit(1); X } X X fprintf(stderr,"Writing to %s on %s\n",user,wtmptty); X} X Xerr(s) Xchar *s; X{ X fputs(s,stderr); X exit(255); X} X X/* the interrupt key has been hit. exit cleanly */ X Xintr() { X signal(SIGINT,SIG_IGN); X fprintf(stderr,"\nInterrupt. Exiting write\n"); X stty(0,&ttyold); X if (writing) write(otty,"\nEOT\n",5); X exit(0); X} X X/* open other person's terminal and setup our own terminal */ X Xsettty() { X sprintf(othertty,"/dev/%s",wtmptty); X if ((otty = open(othertty,1)) < 0) { X fprintf(stderr,"Cannot open %s to write to %s\n",wtmptty,user); X fprintf(stderr,"It may have write permission turned off\n"); X exit(1); X } X gtty(0,&ttyold); X ttynew = ttyold; X ttynew.sg_flags |= CBREAK; X signal(SIGINT,intr); X if (cbreak) stty(0,&ttynew); X} X Xsayhello() { X now = time(0); X printf("Message from %s on %s at %s\n", X getenv("USER"),ourtty,ctime(&now)); X} X X/* the write loop */ X Xwritetty() { X int n; X X writing = 1; X while ((n=read(0,line,79)) > 0) { X if (line[0]=='!' && !cbreak) X escape(); X else write(otty,line,n); X } X write(1,"\nEOT\n",5); X write(otty,"\nEOT\n",5); X} X X/* shell escape */ X Xescape() { X char *x; X X write(1,"!\n",2); X for (x=line;*x;++x) if (*x == '\n') *x = 0; X system(&line[1]); X write(1,"!\n",2); X} / exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@nswitgould.oz UUCP: ...uunet!munnari!nswitgould.oz!nick Fidonet: Nick Andrew on 713/602 (Zeta), nick@nswitgould on 713/603 (ACSgate)