1
0
Files
irix-657m-src/eoe/cmd/write/write.c
2022-09-29 17:59:04 +03:00

499 lines
12 KiB
C

/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
/* UNIX System Laboratories, Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/* Portions Copyright (c) 1988, Sun Microsystems, Inc. */
/* All Rights Reserved. */
/* #ident "@(#)write:write.c 1.10" */
#ident "$Header: /proj/irix6.5.7m/isms/eoe/cmd/write/RCS/write.c,v 1.5 1992/05/06 15:27:22 wtk Exp $"
/* Program to communicate with other users of the system. */
/* Usage: write user [line] */
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <utmp.h>
#include <pwd.h>
#include <fcntl.h>
#include <locale.h>
#include <sys/euc.h>
#include <getwidth.h>
#include <pfmt.h>
#include <errno.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define FAILURE -1
#define DATE_FMT "%a %b %e %H:%M:%S"
#define DATE_FMTID ":541"
/*
* DATE-TIME format
* %a abbreviated weekday name
* %b abbreviated month name
* %e day of month
* %H hour - 24 hour clock
* %M minute
* %S second
*
*/
struct utsname utsn;
FILE *fp ; /* File pointer for receipient's terminal */
char *rterm,*receipient ; /* Pointer to receipient's terminal and name */
char *thissys;
eucwidth_t eucwidth;
static const char multilog[] =
":553:%s is logged on more than one place.\nYou are connected to \"%s\".\nOther locations are:\n";
static const char badperm[] = ":64:Permission denied\n";
/*
* Procedure: main
*/
main(argc,argv)
int argc ;
char **argv ;
{
register int i ;
register struct utmp *ubuf ;
static struct utmp self ;
char ownname[sizeof(self.ut_user) + 1] ;
static char rterminal[] = "/dev/\0 2345678901";
extern char *rterm,*receipient ;
char *terminal,*ownterminal, *oterminal;
short count ;
extern FILE *fp ;
extern void openfail(),eof() ;
char input[134] ;
register char *ptr ;
long tod ;
char time_buf[40];
struct passwd *passptr ;
#ifdef ALREADY_DECLARED /* in include files pwd.h & utmp.h */
extern struct utmp *getutent() ;
extern struct passwd *getpwuid() ;
#endif
char badterm[20][20];
register int bad = 0;
uid_t myuid;
register char *bp;
int ibp;
(void)setlocale(LC_ALL, "");
(void)setcat("uxcore");
(void)setlabel("UX:write");
getwidth(&eucwidth);
myuid = geteuid();
uname(&utsn);
thissys = utsn.nodename;
/* Set "rterm" to location where receipient's terminal will go. */
rterm = &rterminal[sizeof("/dev/") - 1] ;
terminal = NULL ;
if (--argc <= 0)
usage();
else
{
receipient = *++argv ;
}
/* Was a terminal name supplied? If so, save it. */
if (--argc > 1)
usage();
else terminal = *++argv ;
/* One of the standard file descriptors must be attached to a */
/* terminal in "/dev". */
if ((ownterminal = ttyname(fileno(stdin))) == NULL &&
(ownterminal = ttyname(fileno(stdout))) == NULL &&
(ownterminal = ttyname(fileno(stderr))) == NULL)
{
pfmt(stderr, MM_WARNING,
":554:I cannot determine your terminal name. No reply possible.\n") ;
ownterminal = "/dev/???" ;
}
/* Set "ownterminal" past the "/dev/" at the beginning of */
/* the device name. */
oterminal = ownterminal + sizeof("/dev/")-1 ;
/* Scan through the "utmp" file for your own entry and the */
/* entry for the person we want to send to. */
for (self.ut_pid=0,count=0;(ubuf = getutent()) != NULL;)
{
/* Is this a USER_PROCESS entry? */
if (ubuf->ut_type == USER_PROCESS)
{
/* Is it our entry? (ie. The line matches ours?) */
if (strncmp(&ubuf->ut_line[0],oterminal,
sizeof(ubuf->ut_line)) == 0) self = *ubuf ;
/* Is this the person we want to send to? */
if (strncmp(receipient,&ubuf->ut_user[0],
sizeof(ubuf->ut_user)) == 0)
{
/* If a terminal name was supplied, is this login at the correct */
/* terminal? If not, ignore. If it is right place, copy over the */
/* name. */
if (terminal != NULL)
{
if (strncmp(terminal,&ubuf->ut_line[0],
sizeof(ubuf->ut_line)) == 0)
{
strncpy(rterm,&ubuf->ut_line[0],
sizeof(ubuf->ut_line)+1) ;
if (myuid && !permit(rterminal)) {
bad++;
rterm[0] = '\0';
}
}
}
/* If no terminal was supplied, then take this terminal if no */
/* other terminal has been encountered already. */
else
{
/* If this is the first encounter, copy the string into */
/* "rterminal". */
if (*rterm == '\0')
{
strncpy(rterm,
&ubuf->ut_line[0],sizeof(ubuf->ut_line)+1) ;
if (myuid && !permit(rterminal)) {
strcpy(badterm[bad++],rterm);
rterm[0] = '\0';
}
else if (bad > 0)
{
pfmt(stderr, MM_INFO, multilog,
receipient,rterm) ;
for (i = 0 ; i < bad ; i++)
fprintf(stderr,"\t%s\n",badterm[i]) ;
}
}
/* If this is the second terminal, print out the first. In all */
/* cases of multiple terminals, list out all the other terminals */
/* so the user can restart knowing what her/his choices are. */
else if (terminal == NULL)
{
if (count == 1 && bad == 0)
{
pfmt(stderr, MM_INFO, multilog,
receipient,rterm) ;
}
putc('\t', stderr);
fwrite(&ubuf->ut_line[0],sizeof(ubuf->ut_line),
1,stderr) ;
fprintf(stderr,"\n") ;
}
count++ ;
} /* End of "else" */
} /* End of "else if (strncmp" */
} /* End of "if (USER_PROCESS" */
} /* End of "for(count=0" */
/* Did we find a place to talk to? If we were looking for a */
/* specific spot and didn't find it, complain and quit. */
if (terminal != NULL && *rterm == '\0')
{
if (bad > 0)
pfmt(stderr, MM_ERROR, badperm);
else
pfmt(stderr, MM_ERROR,
":555:%s is not at \"%s\".\n",receipient,terminal) ;
exit(1) ;
}
/* If we were just looking for anyplace to talk and didn't find */
/* one, complain and quit. */
/* If permissions prevent us from sending to this person - exit */
else if (*rterm == '\0')
{
if (bad > 0)
pfmt(stderr, MM_ERROR, badperm);
else
pfmt(stderr, MM_ERROR, ":556:%s is not logged on.\n",
receipient) ;
exit(1) ;
}
/* Did we find our own entry? */
else if (self.ut_pid == 0)
{
/* Use the user id instead of utmp name if the entry in the */
/* utmp file couldn't be found. */
if ((passptr = getpwuid(getuid())) == (struct passwd *)NULL)
{
pfmt (stderr, MM_ERROR, ":557:Cannot determine who you are.\n") ;
exit(1) ;
}
strncpy(&ownname[0],&passptr->pw_name[0],sizeof(ownname)) ;
}
else
{
strncpy(&ownname[0],self.ut_user,sizeof(self.ut_user)) ;
}
ownname[sizeof(ownname)-1] = '\0' ;
if (!permit1(1))
pfmt(stderr, MM_WARNING,
":558:You have your terminal set to \"mesg -n\". No reply possible.\n") ;
/* Try to open up the line to the receipient's terminal. */
signal(SIGALRM,openfail) ;
alarm(5) ;
if ((fp = fopen(&rterminal[0],"w")) == NULL) {
pfmt(stderr, MM_ERROR, badperm);
exit(1);
}
alarm(0) ;
/* Catch signals SIGHUP, SIGINT, SIGQUIT, and SIGTERM, and send */
/* <EOT> message to receipient before dying away. */
setsignals(eof) ;
/* Get the time of day, convert it to a string and throw away the */
/* year information at the end of the string. */
time(&tod) ;
cftime(time_buf, gettxt(DATE_FMTID, DATE_FMT), &tod);
pfmt(fp, MM_NOSTD, ":559:\n\007\007\007\tMessage from %s on %s (%s) [ %s ] ...\n",
&ownname[0],thissys,oterminal,time_buf) ;
fflush(fp) ;
fprintf(stderr,"\007\007") ;
/* Get input from user and send to receipient unless it begins */
/* with a !, when it is to be a shell command. */
while ((ptr = fgets(&input[0],sizeof(input),stdin)) != NULL)
{
/* Is this a shell command? */
if (*ptr == '!')
{
shellcmd(++ptr) ;
}
/* Send line to the receipient. */
else
{
if (myuid && !permit1(fileno(fp))) {
pfmt(stderr, MM_ERROR,
":560:Can no longer write to %s\n",rterminal);
break;
}
/*
All non-printable characters are displayed using a special notation:
Control characters shall be displayed using the two character
sequence of ^ (carat) and the ASCII character (decimal) 64 greater
that the character being encoded (e.g., a \003 is displayed ^C).
Characters with the eighth bit set shall be displayed using
the three or four character meta notation( e.g., \372 is
displayed M-z and \203 is displayed M-^C). */
i = strlen(input);
for (bp = &input[0]; --i >= 0; bp++) {
ibp = (unsigned int) *bp;
if (*bp == '\n')
putc('\r', fp);
if (ISPRINT(ibp, eucwidth) || *bp == ' ' ||
*bp == '\t' || *bp == '\n' ||
*bp == '\r' || *bp == '\013' || *bp == '\007') {
putc(*bp, fp);
} else {
if (!isascii(*bp)) {
fputs("M-", fp);
*bp = toascii(*bp);
}
if (iscntrl(*bp)) {
putc('^',fp);
/* add decimal 64 to the control character */
putc(*bp + 0100, fp);
}
else
putc(*bp, fp);
}
if (*bp == '\n')
fflush(fp) ;
if (ferror(fp) || feof(fp)) {
pfmt(stdout, MM_ERROR,
":561:\n\007Write failed (%s logged out?): %s\n",
receipient, strerror(errno));
exit(1);
}
}
fflush(fp) ;
}
}
/* Since "end of file" received, send <EOT> message to receipient. */
eof() ;
}
/*
* Procedure: setsignals
*/
setsignals(catch)
void (*catch)() ;
{
signal(SIGHUP,catch) ;
signal(SIGINT,catch) ;
signal(SIGQUIT,catch) ;
signal(SIGTERM,catch) ;
}
/*
* Procedure: shellcmd
*/
shellcmd(command)
char *command ;
{
register pid_t child ;
extern void eof() ;
if ((child = fork()) == (pid_t)FAILURE) {
pfmt(stderr, MM_ERROR, ":43:fork() failed: %s\n", strerror(errno));
pfmt(stderr, MM_ACTION, ":562:Try again later.\n") ;
return ;
}
else if (child == (pid_t)0) {
/* Reset the signals to the default actions and exec a shell. */
if (setgid(getgid()) < 0)
exit(1);
execl("/sbin/sh","sh","-c",command,0) ;
exit(0) ;
}
else {
/* Allow user to type <del> and <quit> without dying during */
/* commands. */
signal(SIGINT,SIG_IGN) ;
signal(SIGQUIT,SIG_IGN) ;
/* As parent wait around for user to finish spunoff command. */
while(wait(NULL) != child) ;
/* Reset the signals to their normal state. */
setsignals(eof) ;
}
fprintf(stdout,"!\n") ;
}
/*
* Procedure: openfail
*/
void
openfail()
{
extern char *rterm,*receipient ;
pfmt(stderr, MM_ERROR, ":563:Timeout trying to open %s's line(%s).\n",
receipient,rterm) ;
exit(1) ;
}
void
eof()
{
extern FILE *fp ;
fprintf(fp,"<EOT>\n") ;
exit(0) ;
}
/*
* permit: check mode of terminal - if not writable by all disallow writing
* to (even the user him/herself cannot therefore write to their own tty)
*/
/*
* Procedure: permit
*/
permit (term)
char *term;
{
struct stat buf;
int fildes;
if ((fildes = open(term,O_WRONLY)) < 0)
return(0);
fstat(fildes,&buf);
close(fildes);
return(buf.st_mode & (S_IWGRP|S_IWOTH));
}
/* permit1: check mode of terminal - if not writable by all disallow writing to
(even the user him/herself cannot therefore write to their own tty) */
/* this is used with fstat (which is faster than stat) where possible */
/*
* Procedure: permit1
*/
permit1 (fildes)
int fildes;
{
struct stat buf;
fstat(fildes,&buf);
return(buf.st_mode & (S_IWGRP|S_IWOTH));
}
/*
* Procedure: usage
*/
usage()
{
pfmt(stderr, MM_ERROR, ":1:Incorrect usage\n");
pfmt(stderr, MM_ACTION, ":564:Usage: write user [terminal]\n") ;
exit(1) ;
}