From: gak@gakbox.Sun.COM (Richard Stueven) Subject: Re: /bin/write on the 3b1 Date: 16 Apr 90 15:15:03 GMT Reply-To: gak@gakbox.EBay.Sun.COM (Richard Stueven) Organization: Sun Microsystems, Inc. Mt. View, Ca. Lines: 461 In article <285@iczer-1.UUCP> emm@iczer-1.UUCP (Edward M. Markowski) writes: > >Does anybody have a version of write that does not use /dev/error >for writing to the console? > >It is a pain to keep using that little icon to carry on a >conversation(sp?). Offerred as-is...with thanks to Kent Landfield somewhere in Omaha for the original hack several years ago... have fun gak ======================================================================= /* * write to another user * (modified for char by char transmission) */ #include #include #include #include #include #include #include #define NMAX sizeof(ubuf.ut_name) #define LMAX sizeof(ubuf.ut_line) #define EOFC '\004' #define BEL '\007' #define IOBUFSIZ 256 #define myfildes 1 int errno; char *strcat(); char *strcpy(); struct utmp ubuf; int signum[] = { SIGHUP, SIGINT, SIGQUIT, 0}; int onstop(); char me[10] = "???"; char *him; char *mytty; char histty[32]; char *histtya; int hisfildes; int modeset; char *ttyname(); void exit(); void perror(); unsigned alarm(); char *rindex(); int logcnt; int find; int die(); int timout(); FILE *tf; char *getenv(); struct termio new_term, old_term; #ifdef BSD4.1 struct ltchars o_ltchars; struct ltchars ltchars; #endif char erase, werase, lkill; char erase, werase, lkill; char iobuf[IOBUFSIZ]; char *ptr = iobuf; main(argc, argv) char *argv[]; { struct stat stbuf; register i; int c1, c2; char c; register FILE *uf; long time(); long clock; struct tm *localtime(); struct tm *localclock; clock = time( 0 ); localclock = localtime( &clock ); if (argc < 2) { printf("usage: %s user [ttyname]\n", argv[0]); exit(1); } him = argv[1]; if (argc > 2) histtya = argv[2]; if ((uf = fopen("/etc/utmp", "r")) == NULL) { printf("cannot open /etc/utmp\n"); goto cont; } mytty = ttyname(2); if (mytty == NULL) { printf("Can't find your tty\n"); exit(1); } mytty = rindex(mytty, '/') + 1; while (fread((char *) & ubuf, sizeof(ubuf), 1, uf) == 1) { if (ubuf.ut_name[0] == '\0') continue; if (strcmp(ubuf.ut_line, mytty) == 0) { for (i = 0; i < NMAX; i++) { c1 = ubuf.ut_name[i]; if (c1 == ' ') c1 = 0; me[i] = c1; if (c1 == 0) break; } } if (him[0] != '-' || him[1] != 0 || !histtya[0]) for (i = 0; i < NMAX; i++) { c1 = him[i]; c2 = ubuf.ut_name[i]; if (c1 == 0) if (c2 == 0 || c2 == ' ') break; if (c1 != c2) goto nomat; } logcnt++; if (histtya) if (strcmp(histtya, ubuf.ut_line)) goto nomat; find++; if (histty[0] == 0) { strcpy(histty, "/dev/"); strcat(histty, ubuf.ut_line); } nomat: ; } cont: if (logcnt == 0) { printf("%s not logged in.\n", him); exit(1); } fclose(uf); if (histtya == 0 && logcnt > 1) { printf("%s logged more than once\nwriting to %s\n", him, histty + 5); } if (!find) { printf("%s not on that tty\n", him); exit(1); } if (access(histty, 0) < 0) { printf("No such tty\n"); exit(1); } signal(SIGALRM, timout); alarm(5); if ((tf = fopen(histty, "w")) == NULL) goto perm; alarm(0); hisfildes = fileno(tf); if (fstat(hisfildes, &stbuf) < 0) goto perm; if ((stbuf.st_mode & 02) == 0) goto perm; sigs(die); #ifdef BSD4.1 sigset(SIGTSTP, onstop); #endif setmode(myfildes); fprintf(tf, "\r\nMessage from "); #ifdef interdata fprintf(tf, "(Interdata) " ); #endif fprintf(tf, "%s on %s at %d:%02d ...\r\n" , me, mytty , localclock ->tm_hour , localclock ->tm_min ); fflush(tf); printf("Writing, type control/d to exit.\n"); while (0 <= read(0, &c, 1) && c != EOFC) { if (c == erase) erase_char(); else if (c == lkill) kill_line(); else if (c == werase) erase_word(); else if (c == '\n') { putch('\n', hisfildes); putch('\n', myfildes); if (iobuf[0] == '!') { *ptr++ = 0; ex(iobuf); iobuf[0] = 0; } ptr = iobuf; } else if (ptr != iobuf + IOBUFSIZ) { putch(c, hisfildes); putch(c, myfildes); *ptr++ = c; } else { putch(BEL, myfildes); putch(BEL, hisfildes); } } die(); perm: printf("Permission denied\n"); perror("write"); exit(1); } timout() { printf("Timeout opening their tty\n"); exit(1); } die() { fprintf(tf, "EOF\r\n"); if (modeset) resetmode(myfildes); exit(0); } #ifdef BSD4.1 onstop() { register char *p; if (modeset) resetmode(myfildes); sigset(SIGTSTP, SIG_DFL); kill(getpid(), SIGTSTP); sigrelse(SIGTSTP); /* resume here */ sighold(SIGTSTP); sigset(SIGTSTP, onstop); setmode(myfildes); /* put the line out again */ putch('\n', myfildes); for ( p = iobuf; p < ptr; ) putch(*p++, myfildes); } #endif ex(bp) char *bp; { register i; holdsigs(); resetmode(myfildes); i = fork(); if (i < 0) { printf("Try again\n"); goto out; } if (i == 0) { sigs(SIG_DFL); #ifdef BSD sigset(SIGTSTP, SIG_DFL); #endif execl(getenv("SHELL") ? getenv("SHELL") : "/bin/sh", "sh", "-c", bp + 1, 0); exit(0); } while (wait((int *)NULL) != i) ; printf("!\n"); out: relsigs(); setmode(myfildes); } sigs(sig) int (*sig)(); { register i; for (i = 0; signum[i]; i++) #ifdef BSD sigset(signum[i], sig); #else signal(signum[i], sig); #endif } holdsigs() { #ifdef BSD4.1 register i; for (i = 0; signum[i]; i++) sighold(signum[i]); sighold(SIGTSTP); #endif } relsigs() { #ifdef BSD4.1 register i; for (i = 0; signum[i]; i++) sigrelse(signum[i]); sigrelse(SIGTSTP); #endif } #define seterror printf("write: unable to alter terminal state\n"), \ exit(1) int setmode (filedes) int filedes; { if (modeset) return; /* if modes already set */ #ifdef BSD4.1 holdsigs(SIGTSTP); #endif if (ioctl (filedes, TCGETA, &old_term)) /* get current terminal state */ seterror; new_term = old_term; /* copy current terminal state */ new_term.c_lflag &= ~(ICANON | ECHO | ECHOE); new_term.c_cc[VMIN] = 1; new_term.c_cc[VTIME] = 0; erase = new_term.c_cc[VERASE]; lkill = new_term.c_cc[VKILL]; #ifdef BSD4.1 if (ioctl (filede, TIOCGLTC, &o_ltchars)) seterror; ltchars = o_ltchars; werase = ltchars.t_werasc; #else werase = '\027'; #endif if (ioctl(filedes, TCSETA, &new_term)) seterror; modeset++; relsigs (); } resetmode (filedes) int filedes; { if (!modeset) return; holdsigs (); if (ioctl(filedes, TCSETA, &old_term)) { printf("write : error resetting tty\n"); exit (1); } modeset = 0; relsigs (); } erase_char() { if (ptr > iobuf) { putch('\b', myfildes); putch(' ', myfildes); putch('\b', myfildes); putch('\b', hisfildes); putch(' ' , hisfildes); putch('\b', hisfildes); ptr--; } } erase_word() { while (ptr > iobuf && ptr[-1] == ' ') erase_char(); while (ptr > iobuf && ptr[-1] != ' ') erase_char(); } kill_line() { while (ptr > iobuf) erase_char(); } putch(c, f) char c; register int f; { if (0 >= write(f, &c, 1)) { perror("write"); die(); } } /* * Return the ptr in sp at which the character c last * appears; NULL if not found * * Identical to v7 rindex, included for portability. */ char * rindex(sp, c) register char *sp, c; { register char *r; r = NULL; do { if (*sp == c) r = sp; } while (*sp++); return(r); } Richard Stueven ...!att!attmail!gak gak@sun.com I like to know what I'm doing when I'm doing what I do when I'm doing it because I don't know what to do when I'm not doing it. - S.Ridgeway