/* @(#)wall.c 1.6 */ #define FAILURE (-1) #define TRUE 1 #define FALSE 0 #include <signal.h> char mesg[3000]; #include <sys/types.h> #include <utmp.h> #include <grp.h> #include <sys/stat.h> #include <sys/dir.h> #include <pwd.h> #include <stdio.h> #include <fcntl.h> #include <time.h> #include <errno.h> unsigned int usize; int entries; struct utmp *utmp; char *line = "???"; char who[9] = "???"; char *infile; int group; struct group *pgrp; extern struct group *getgrname(); extern char *ttyname(); char *grpname; char *timstr; long tloc, time(); extern int errno; #define equal(a,b) (!strcmp( (a), (b) )) main(argc, argv) int argc; char *argv[]; { int i, fd; register struct utmp *p,*pmax; FILE *f; struct utmp *getutent(); struct stat statbuf; struct direct direntry; int devfd; register char *ptr; struct passwd *pwd; extern struct passwd *getpwuid(); char *malloc(); if(stat(UTMP_FILE, &statbuf) < 0) { fprintf(stderr, "stat failed on %s\n", UTMP_FILE); exit(1); } /* get usize (an unsigned int) for malloc call * and check that there is no truncation (for those 16 bit CPUs) */ usize = statbuf.st_size; if(usize != statbuf.st_size) { fprintf(stderr, "'%s' too big.\n", UTMP_FILE); exit(1); } entries = usize / sizeof(struct utmp); if((utmp=(struct utmp *)malloc(usize)) == NULL) { fprintf(stderr, "cannot allocate memory for '%s'.\n", UTMP_FILE); exit(1); } if((fd=open(UTMP_FILE, O_RDONLY)) < 0) { fprintf(stderr,"cannot open '%s'\n", UTMP_FILE); exit(1); } if(read(fd, utmp, usize) != usize) { fprintf(stderr, "cannot read '%s'\n", UTMP_FILE); exit(1); } close(fd); readargs(argc, argv); /* Get the name of the terminal wall is running from. */ if (isatty(fileno(stderr)) && fstat(fileno(stderr),&statbuf) != FAILURE && (devfd = open("/dev",0)) != FAILURE) { while (who[0] == '?') { /* Read in directory entries for /dev and look for ones with */ /* an inode number equal to the inode number of our standard */ /* error output. */ for (direntry.d_ino=0; direntry.d_ino != statbuf.st_ino;) { direntry.d_ino = 0; if (read(devfd,&direntry,sizeof(direntry)) != sizeof(direntry)) { direntry.d_ino = 0; break; } } /* If we've reached the end of the dev directory and can't find */ /* another name for this terminal, finally give up. */ if (direntry.d_ino != statbuf.st_ino) break; else line = &direntry.d_name[0]; /* Search for self so that we can identify ourselves when we send. */ for(i=0;i<entries;i++) { p = &utmp[i]; if(p->ut_type != USER_PROCESS) continue; if (strncmp(line,&p->ut_line[0], sizeof(p->ut_line)) == 0) { strncpy(&who[0],&p->ut_user[0], sizeof(p->ut_user)); who[sizeof(p->ut_user)] = '\0'; break; } } /* If we didn't find the utmp entry, reset line to "???" and */ /* continue looking. */ if (p == pmax) { strcpy(&who[0],"???"); line = "???"; } } } else { if (pwd = getpwuid(getuid())) strncpy(&who[0],pwd->pw_name,sizeof(who)); } if (devfd != FAILURE) close(devfd); f = stdin; if(infile) { f = fopen(infile, "r"); if(f == NULL) { printf("%s??\n", infile); exit(1); } } for(ptr= &mesg[0]; fgets(ptr,&mesg[sizeof(mesg)]-ptr, f) != NULL ; ptr += strlen(ptr)); fclose(f); time(&tloc); timstr = ctime(&tloc); for(i=0;i<entries;i++) { if((p=(&utmp[i]))->ut_type != USER_PROCESS) continue; sendmes(p); } alarm(60); do { i = wait((int *)0); } while(i != -1 || errno != ECHILD); exit(0); } sendmes(p) struct utmp *p; { register i; register char *s; static char device[] = "/dev/123456789012"; FILE *f; if(group) if(!chkgrp(p->ut_user)) return; while((i=fork()) == -1) { alarm(60); wait((int *)0); alarm(0); } if(i) return; signal(SIGHUP, SIG_IGN); alarm(60); s = &device[0]; sprintf(s,"/dev/%s",&p->ut_line[0]); #ifdef DEBUG f = fopen("wall.debug", "a"); #else f = fopen(s, "w"); #endif if(f == NULL) { printf("Cannot send to %.-8s\n", &p->ut_user[0]); perror("open"); exit(1); } fprintf(f, "\07\07\07Broadcast Message from %s (%s) %19.19s", who, line, timstr); if(group) fprintf(f, " to group %s", grpname); fprintf(f, "...\n"); #ifdef DEBUG fprintf(f,"DEBUG: To %.8s on %s\n", p->ut_user, s); #endif fprintf(f, "%s\n", mesg); fclose(f); exit(0); } readargs(ac, av) int ac; char **av; { register int i, j; for(i = 1; i < ac; i++) { if(equal(av[i], "-g")) { if(group) { fprintf(stderr, "Only one group allowed\n"); exit(1); } i++; if((pgrp=getgrname(grpname= av[i])) == NULL) { fprintf(stderr, "Unknown group %s\n", grpname); exit(1); } endgrent(); group++; } else infile = av[i]; } } #define BLANK ' ' chkgrp(name) register char *name; { register int i; register char *p; for(i = 0; pgrp->gr_mem[i] && pgrp->gr_mem[i][0]; i++) { for(p=name; *p && *p != BLANK; p++); *p = 0; if(equal(name, pgrp->gr_mem[i])) return(1); } return(0); }