/* @(#)write.c 1.4 */ /* Program to communicate with other users of the system. */ /* Usage: write user [line] */ #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <utmp.h> #include <pwd.h> #define TRUE 1 #define FALSE 0 #define FAILURE -1 FILE *fp ; /* File pointer for receipient's terminal */ char *rterm,*receipient ; /* Pointer to receipient's terminal and name */ 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,*ttyname() ; short count ; extern FILE *fp ; extern int openfail(),eof() ; char input[134] ; register char *ptr ; long tod ; char *time_of_day ; struct passwd *passptr ; extern struct utmp *getutent() ; extern struct passwd *getpwuid() ; extern char *ctime() ; /* Set "rterm" to location where receipient's terminal will go. */ rterm = &rterminal[sizeof("/dev/") - 1] ; terminal = NULL ; if (--argc <= 0) { fprintf(stderr,"Usage: write user [terminal]\n") ; exit(1) ; } else { receipient = *++argv ; } /* Was a terminal name supplied? If so, save it. */ if (--argc > 1) { fprintf(stderr,"Usage: write user [terminal]\n") ; exit(1) ; } 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) { fprintf(stderr,"I cannot determine your terminal name.\ No reply possible.\n") ; ownterminal = "/dev/???" ; } /* Set "ownterminal" past the "/dev/" at the beginning of */ /* the device name. */ 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],ownterminal, 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 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 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) { fprintf(stderr, "%s is logged on more than one\ place.\nYou are connected to \"%s\".\nOther locations are:\n", receipient,rterm) ; } 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') { fprintf(stderr,"%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. */ else if (*rterm == '\0') { fprintf(stderr,"%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) { fprintf(stderr,"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' ; /* Try to open up the line to the receipient's terminal. */ signal(SIGALRM,openfail) ; alarm(5) ; fp = fopen(&rterminal[0],"w") ; alarm(0) ; /* If open failed, then permissions must be preventing us from */ /* sending to this person. */ if (fp == NULL) { fprintf(stderr,"Permission denied.\n") ; exit(1) ; } /* 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) ; time_of_day = ctime(&tod) ; *(time_of_day + 19) = '\0' ; fprintf(fp,"\n\007\007\007\tMessage from %s (%s) [ %s ] ...\n", &ownname[0],ownterminal,time_of_day) ; 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 { fputs(ptr,fp) ; fflush(fp) ; } } /* Since "end of file" received, send <EOT> message to receipient. */ eof() ; } setsignals(catch) int (*catch)() ; { signal(SIGHUP,catch) ; signal(SIGINT,catch) ; signal(SIGQUIT,catch) ; signal(SIGTERM,catch) ; } shellcmd(command) char *command ; { register int child ; extern int eof() ; if ((child = fork()) == FAILURE) { fprintf(stderr,"Unable to fork. Try again later.\n") ; return ; } else if (child == 0) { /* Reset the signals to the default actions and exec a shell. */ execl("/bin/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") ; } openfail() { extern char *rterm,*receipient ; fprintf(stderr,"Timeout trying to open %s's line(%s).\n", receipient,rterm) ; exit(1) ; } eof() { extern FILE *fp ; fprintf(fp,"<EOT>\n") ; exit(0) ; }