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>
 | 
						|
 | 
						|
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("/etc/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);
 | 
						|
}
 |