269 lines
5.8 KiB
C
Executable file
269 lines
5.8 KiB
C
Executable file
/* write - write to a logged in user Authors: N. Andrew and F. van Kempen */
|
|
|
|
/*
|
|
* Usage: write [-c] [-v] user [tty]
|
|
* -c Read & write one character at a time (cbreak mode)
|
|
* -v Verbose
|
|
*
|
|
* Version: 1.6 10/24/92
|
|
*
|
|
* NOTES: Write requires 1.4a (or higher) libraries,
|
|
* for getopt(), strchr().
|
|
*
|
|
* Authors: Nick Andrew (nick@nswitgould.oz) - Public Domain
|
|
* Fred van Kempen (minixug!waltje@kyber.uucp)
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <termios.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <utmp.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <minix/paths.h>
|
|
|
|
static char *Version = "@(#) WRITE 1.6 (10/24/92)";
|
|
|
|
int otty; /* file desc of callee's terminal */
|
|
short int cbreak = 0; /* are we in CBREAK (-c) mode? */
|
|
short int verbose = 0; /* are we in VERBOSE (-v) mode? */
|
|
short int writing = 0; /* is there a connection? */
|
|
char *user = NULL; /* callee's user name */
|
|
char *tty = NULL; /* callee's terminal if given */
|
|
char *ourtty = NULL; /* our terminal name */
|
|
struct termios ttyold, ttynew; /* our tty controlling structs */
|
|
|
|
extern int optind;
|
|
|
|
_PROTOTYPE(int main, (int argc, char **argv));
|
|
_PROTOTYPE(char *finduser, (void));
|
|
_PROTOTYPE(void settty, (char *utty));
|
|
_PROTOTYPE(void sayhello, (void));
|
|
_PROTOTYPE(void escape, (char *cmd));
|
|
_PROTOTYPE(void writetty, (void));
|
|
_PROTOTYPE(void usage, (void));
|
|
_PROTOTYPE(void intr, (int dummy));
|
|
|
|
char *finduser()
|
|
{
|
|
/* Search the UTMP database for the user we want. */
|
|
|
|
static char utmptty[16];
|
|
struct utmp utmp;
|
|
struct passwd *userptr;
|
|
int utmpfd;
|
|
|
|
ourtty = ttyname(0);
|
|
if (ourtty == NULL) ourtty = "/dev/console";
|
|
|
|
if (user == NULL) exit(-1);
|
|
if ((userptr = getpwnam(user)) == NULL) {
|
|
fprintf(stderr, "No such user: %s\n", user);
|
|
return(NULL);
|
|
}
|
|
if (verbose) fprintf(stderr, "Trying to write to %s\n",
|
|
userptr->pw_gecos);
|
|
|
|
if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) {
|
|
fprintf(stderr, "Cannot open utmp file\n");
|
|
return(NULL);
|
|
}
|
|
utmptty[0] = '\0';
|
|
|
|
/* We want to find if 'user' is logged on, and return in utmptty[]
|
|
* 'user' `s terminal, and if 'user' is logged onto the tty the
|
|
* caller specified, return that tty name. */
|
|
while (read(utmpfd, (char *) &utmp, sizeof(utmp)) == sizeof(utmp)) {
|
|
/* is this the user we are looking for? */
|
|
if (strncmp(utmp.ut_name, user, sizeof(utmp.ut_name))) continue;
|
|
|
|
strcpy(utmptty, utmp.ut_line);
|
|
/* is he on the terminal we want to write to? */
|
|
if (tty == NULL || !strcmp(utmptty, tty)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (utmptty[0] == '\0') {
|
|
fprintf(stderr, "%s is not logged on\n", user);
|
|
return( NULL);
|
|
}
|
|
if (tty != NULL && strcmp(utmptty, tty)) {
|
|
fprintf(stderr, "%s is logged onto %s, not %s\n", user, utmptty, tty);
|
|
return( NULL);
|
|
}
|
|
close(utmpfd);
|
|
|
|
if (verbose) fprintf(stderr, "Writing to %s on %s\n", user, utmptty);
|
|
return(utmptty);
|
|
}
|
|
|
|
|
|
void settty(utty)
|
|
char *utty; /* name of terminal found in utmp */
|
|
{
|
|
/* Open other person's terminal and setup our own terminal. */
|
|
|
|
char buff[48];
|
|
|
|
sprintf(buff, "/dev/%s", utty);
|
|
if ((otty = open(buff, O_WRONLY)) < 0) {
|
|
fprintf(stderr, "Cannot open %s to write to %s\n", utty, user);
|
|
fprintf(stderr, "It may have write permission turned off\n");
|
|
exit(-1);
|
|
}
|
|
tcgetattr(0, &ttyold);
|
|
tcgetattr(0, &ttynew);
|
|
ttynew.c_lflag &= ~(ICANON|ECHO);
|
|
signal(SIGINT, intr);
|
|
if (cbreak) tcsetattr(0, TCSANOW, &ttynew);
|
|
}
|
|
|
|
|
|
void sayhello()
|
|
{
|
|
struct passwd *pw;
|
|
char buff[128];
|
|
long now;
|
|
char *sp;
|
|
|
|
time(&now);
|
|
|
|
pw = getpwuid(getuid());
|
|
if (pw == NULL) {
|
|
fprintf(stderr, "unknown user\n");
|
|
exit(-1);
|
|
}
|
|
if ((sp = strrchr(ourtty, '/')) != NULL)
|
|
++sp;
|
|
else
|
|
sp = ourtty;
|
|
|
|
sprintf(buff, "\nMessage from %s (%s) %-24.24s...\n",
|
|
pw->pw_name, sp, ctime(&now));
|
|
|
|
write(otty, buff, strlen(buff));
|
|
printf("\007\007");
|
|
fflush(stdout);
|
|
}
|
|
|
|
|
|
void escape(cmd)
|
|
char *cmd;
|
|
{
|
|
/* Shell escape. */
|
|
|
|
register char *x;
|
|
|
|
write(1, "!\n", 2);
|
|
for (x = cmd; *x; ++x)
|
|
if (*x == '\n') *x = '\0';
|
|
|
|
system(cmd);
|
|
write(1, "!\n", 2);
|
|
}
|
|
|
|
|
|
void writetty()
|
|
{
|
|
/* The write loop. */
|
|
|
|
char line[80];
|
|
int n, cb_esc;
|
|
|
|
writing = 1;
|
|
cb_esc = 0;
|
|
|
|
while ((n = read(0, line, 79)) > 0) {
|
|
if (line[0] == '\004') break; /* EOT */
|
|
|
|
if (cbreak && line[0] == '\n') cb_esc = 1;
|
|
|
|
if (cbreak) write(1, line, n);
|
|
|
|
if (line[0] == '!') {
|
|
if (cbreak && cb_esc) {
|
|
cb_esc = 0;
|
|
tcsetattr(0, TCSANOW, &ttyold);
|
|
read(0, line, 79);
|
|
escape(line);
|
|
tcsetattr(0, TCSANOW, &ttynew);
|
|
} else if (cbreak)
|
|
write(otty, line, n);
|
|
else
|
|
escape(&line[1]);
|
|
continue;
|
|
}
|
|
write(otty, line, n);
|
|
}
|
|
write(1, "\nEOT\n", 5);
|
|
write(otty, "\nEOT\n", 5);
|
|
}
|
|
|
|
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "usage: write [-c] [-v] user [tty]\n");
|
|
fprintf(stderr, "\t-c : cbreak mode\n\t-v : verbose\n");
|
|
exit(-1);
|
|
}
|
|
|
|
|
|
int main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
register int c;
|
|
char *sp;
|
|
|
|
setbuf(stdout, (char *) NULL);
|
|
|
|
/* Parse options. */
|
|
while ((c = getopt(argc, argv, "cv")) != EOF) switch (c) {
|
|
case 'c': cbreak = 1; break;
|
|
case 'v': verbose = 1; break;
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
/* Parse user and tty arguments */
|
|
if (optind < argc) {
|
|
user = argv[optind++];
|
|
|
|
/* WTMP usernames are 1-8 chars */
|
|
if (strlen(user) > 8) *(user + 8) = '\0';
|
|
|
|
if (optind < argc) {
|
|
tty = argv[optind++];
|
|
if (optind < argc) usage();
|
|
}
|
|
} else
|
|
usage();
|
|
|
|
sp = finduser(); /* find which tty to write onto */
|
|
if (sp != NULL) { /* did we find one? */
|
|
settty(sp); /* setup our terminal */
|
|
sayhello(); /* print the initial message */
|
|
writetty(); /* the write loop */
|
|
tcsetattr(0, TCSANOW, &ttyold);
|
|
exit(0);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
void intr(dummy)
|
|
int dummy; /* to satisfy the prototype */
|
|
{
|
|
/* The interrupt key has been hit. exit cleanly. */
|
|
|
|
signal(SIGINT, SIG_IGN);
|
|
fprintf(stderr, "\nInterrupt. Exiting write\n");
|
|
tcsetattr(0, TCSANOW, &ttyold);
|
|
if (writing) write(otty, "\nEOT\n", 5);
|
|
exit(0);
|
|
}
|