home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xwall / bin.wall / wall.c < prev   
Encoding:
C/C++ Source or Header  |  1995-06-20  |  12.4 KB  |  515 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. char copyright[] =
  20. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  21.  All rights reserved.\n";
  22. #endif not lint
  23.  
  24. #ifndef lint
  25. static char sccsid[] = "@(#)wall.c    5.3 (Berkeley) 4/20/86";
  26. #endif not lint
  27.  
  28. /*
  29.  * wall.c - Broadcast a message to all users.
  30.  *
  31.  * This program is not related to David Wall, whose Stanford Ph.D. thesis
  32.  * is entitled "Mechanisms for Broadcast and Selective Broadcast".
  33.  */
  34. #ifdef UW
  35. /*
  36.  * Modified Monday 19 November 10:52:26 CST 1990 by Dean Luick
  37.  *   Added a check to see if an xwall message failed.  If so, then it will
  38.  *   try a tty ring on the least idle tty for that display.
  39.  *
  40.  * Modified Wed April 5 14:24:19 CST 1989 by Lexie Panter, The
  41.  *   University of Wisconsin-Madison.  Checks utmp entries for
  42.  *   X display names in host part.  If someone is running X, send
  43.  *   the message via xwall instead of sending the message to all of 
  44.  *   their existing windows.
  45.  *
  46.  * bolo@cat (Joe Burger) on Thu Aug 10 12:27:17 CDT 1989
  47.  *   Fixed "bug" with X windows code.  A non-terminated string was
  48.  *   causing problems.
  49.  *   Security enhanced: only writes message to character devices.
  50.  *
  51.  * Modified Thu Jan 14 12:57:17 CST 1988 by Dave Cohrs
  52.  *   Added a "-u username" option to broadcast only to tty's logged
  53.  *   in as the given username.  A compromise between wall and write.
  54.  */
  55. #endif UW
  56.  
  57. #include <stdio.h>
  58. #include <errno.h>
  59. #include <signal.h>
  60. #if defined(UW) && defined(CRAY)
  61. #include <time.h>
  62. #include <sys/sysmacros.h>
  63. #else
  64. #include <sys/time.h>
  65. #endif
  66. #include <fcntl.h>
  67. #include <sys/types.h>
  68. #include <sys/stat.h>
  69. #include <utmp.h>
  70. #ifdef UW
  71. #include <pwd.h>
  72. #include <strings.h>
  73. #endif UW
  74.  
  75. #if defined(UW) && defined(CRAY)
  76. extern char *index();
  77. extern char *rindex();
  78. #endif
  79.  
  80. /*
  81.  *  Systems derived from SysVr3 (like UNICOS) define the
  82.  *  fcntl flags differently so pick up the dropped ball here.
  83.  */
  84. #ifndef FNDELAY
  85. #define FNDELAY O_NDELAY
  86. #endif
  87.  
  88. #if defined(UW) && !defined(XWALL)
  89. #define XWALL "/usr/misc/X11/bin/xwall"
  90. #endif
  91.  
  92. #define IGNOREUSER    "sleeper"
  93.  
  94. char    hostname[32];
  95. char    mesg[3000];
  96. int    msize,sline;
  97. struct    utmp *utmp;
  98. char    *strcpy();
  99. char    *strcat();
  100. char    *malloc();
  101. char    who[9] = "???";
  102. #ifdef UW
  103. long    now;    /* time() is defined in sys/time.h */
  104. #else
  105. long    now, time();
  106. #endif
  107. struct tm *localtime();
  108. struct tm *localclock;
  109. #ifdef UW
  110. void    _exit();
  111. char    xmesg[3000];
  112. int    xmsize;
  113. int    xdisplay();
  114. char    *exmalloc();
  115. struct xlist {                    /* keeps a list of displays */
  116.     char display[sizeof(utmp->ut_host)+2];    /* to send an xwall message.*/
  117.     char user[sizeof(utmp->ut_name)+1];    
  118.     char tty[sizeof(utmp->ut_line)+1];
  119.     long idle;
  120.     struct xlist *next;
  121. } *xlist;
  122. #endif UW
  123.  
  124. extern    errno;
  125.  
  126. main(argc, argv)
  127. char *argv[];
  128. {
  129.     register int i, c;
  130.     register struct utmp *p;
  131.     int f;
  132.     struct stat statb;
  133. #ifdef UW
  134.     struct passwd *pw;
  135.     register char *onlyuser = 0;
  136. #endif UW
  137.  
  138.     (void) gethostname(hostname, sizeof (hostname));
  139.     if ((f = open("/etc/utmp", O_RDONLY, 0)) < 0) {
  140.         fprintf(stderr, "Cannot open /etc/utmp\n");
  141.         exit(1);
  142.     }
  143. #ifdef UW
  144.     if(argc >= 2 && argv[1][0] == '-') {
  145.         i = strlen(argv[1]);
  146.  
  147.         if(strncmp(argv[1], "-u", 2) == 0 && (i > 2 || argc >= 3)) {
  148.             if(i == 2) {
  149.                 onlyuser = argv[2];
  150.                 argv++;
  151.                 argc--;
  152.             } else
  153.                 onlyuser = &argv[1][2];
  154.             argv++;
  155.             argc--;
  156.         } else {
  157.             fprintf(stderr, "Usage: wall [ -u username ] [ file ]\n");
  158.             exit(1);
  159.         }
  160.     }
  161. #endif UW
  162.     now = time( 0 );
  163.     localclock = localtime( &now );
  164.     sline = ttyslot();    /* 'utmp' slot no. of sender */
  165.     (void) fstat(f, &statb);
  166. #ifdef UW
  167.     utmp = (struct utmp *)exmalloc(statb.st_size);
  168. #else
  169.     utmp = (struct utmp *)malloc(statb.st_size);
  170. #endif
  171.     c = read(f, (char *)utmp, statb.st_size);
  172.     (void) close(f);
  173.     c /= sizeof(struct utmp);
  174.     if (sline)
  175.         strncpy(who, utmp[sline].ut_name, sizeof(utmp[sline].ut_name));
  176. #ifdef UW
  177.     else if((pw = getpwuid(getuid())) != NULL)
  178.         (void) strncpy(who,pw->pw_name,8);
  179.     if (sline == 0)
  180.         (void) sprintf(mesg,
  181.             "\r\n\07\07\07Broadcast Message from %s@%s at %d:%02d ...\r\n\n"
  182.             , who
  183.             , hostname
  184.             , localclock -> tm_hour
  185.             , localclock -> tm_min
  186.         );
  187.     else
  188. #endif UW
  189.     sprintf(mesg,
  190.         "\r\n\007\007Broadcast Message from %s@%s (%.*s) at %d:%02d ...\r\n\n"
  191.         , who
  192.         , hostname
  193.         , sizeof(utmp[sline].ut_line)
  194.         , utmp[sline].ut_line
  195.         , localclock -> tm_hour
  196.         , localclock -> tm_min
  197.     );
  198.     msize = strlen(mesg);
  199.     if (argc >= 2) {
  200.         /* take message from unix file instead of standard input */
  201.         if (freopen(argv[1], "r", stdin) == NULL) {
  202.             perror(argv[1]);
  203.             exit(1);
  204.         }
  205.     }
  206.     while ((i = getchar()) != EOF) {
  207.         if (i == '\n')
  208.             mesg[msize++] = '\r';
  209.         if (msize >= sizeof mesg) {
  210.             fprintf(stderr, "Message too long\n");
  211.             exit(1);
  212.         }
  213.         mesg[msize++] = i;
  214. #ifdef UW
  215.         xmesg[xmsize++] = i;
  216. #endif UW
  217.     }
  218.     fclose(stdin);
  219.     for (i=0; i<c; i++) {
  220.         p = &utmp[i];
  221.         if (p->ut_name[0] == 0 ||
  222. #ifdef UW
  223.             (onlyuser != 0 &&
  224.                 strncmp(p->ut_name, onlyuser, sizeof(p->ut_name)) != 0) ||
  225. #ifdef nonuser
  226.             /* support for the Sun nonuser macro */
  227.             nonuser(*p) ||
  228. #endif nonuser
  229. #endif UW
  230.             strncmp(p->ut_name, IGNOREUSER, sizeof(p->ut_name)) == 0)
  231.             continue;
  232. #ifdef UW
  233.         /* Only send wall message to ttys not using X */
  234.         if (!xdisplay(p))
  235. #endif UW
  236.         sendmes(p->ut_line);
  237.     }
  238. #ifdef UW
  239.     sendwindows();
  240. #endif UW
  241.     exit(0);
  242. }
  243.  
  244. sendmes(tty)
  245. char *tty;
  246. {
  247.     register f, flags;
  248.     static char t[50] = "/dev/";
  249.     int e, i;
  250. #ifdef UW 
  251.     struct stat st;
  252. #endif
  253.  
  254.     strcpy(t + 5, tty);
  255.  
  256. #ifdef UW
  257.     /* make sure the file is a tty ! */
  258.     if (stat(t, &st) == -1  ||  (st.st_mode&S_IFMT) != S_IFCHR)
  259.         return;
  260. #endif
  261.     if ((f = open(t, O_WRONLY|O_NDELAY)) < 0) {
  262.         if (errno != EWOULDBLOCK)
  263.             perror(t);
  264.         return;
  265.     }
  266.     if ((flags = fcntl(f, F_GETFL, 0)) == -1) {
  267.         perror(t);
  268.         return;
  269.     }
  270.     if (fcntl(f, F_SETFL, flags | FNDELAY) == -1)
  271.         goto oldway;
  272.     i = write(f, mesg, msize);
  273.     e = errno;
  274.     (void) fcntl(f, F_SETFL, flags);
  275.     if (i == msize) {
  276.         (void) close(f);
  277.         return;
  278.     }
  279. #ifdef UW
  280.     /*
  281.      * The write can succeed, but not write all characters 
  282.      * may be written. We should retry, but are too lazy
  283.      * -- see write(2) about non-blocking IO.
  284.      * bolo
  285.      */
  286.     if (i < 0  && e != EWOULDBLOCK) {
  287. #else
  288.     if (e != EWOULDBLOCK) {
  289. #endif
  290.         errno = e;
  291.         perror(t);
  292.         (void) close(f);
  293.         return;
  294.     }
  295. oldway:
  296.     while ((i = fork()) == -1)
  297.         if (wait((int *)0) == -1) {
  298.             fprintf(stderr, "Try again\n");
  299.             return;
  300.         }
  301.     if (i) {
  302.         (void) close(f);
  303.         return;
  304.     }
  305.  
  306.     (void) write(f, mesg, msize);
  307.     exit(0);
  308. }
  309.  
  310. #ifdef UW
  311.  
  312. /* Add display entry to the xlist.  */
  313. static int
  314. xdisplay(p)
  315.     struct utmp *p;
  316. {
  317.     struct xlist *xptr;
  318.     struct stat  ttystat, p0stat;
  319.     char display[sizeof(p->ut_host)+2];    /* may need to add '0' and '\0'. */
  320.     char xpty[64];            /* name of the pty */
  321.     char *colonp, *dotp, *displayp;
  322.     int  n;
  323.     long idle;
  324.  
  325.     static int get_major = 1;    /* get the major number of a pty */
  326.     static int have_major;    /* we have the major number of a pty */
  327.     static int pty_major;    /* pty major number */
  328.  
  329.  
  330.     /* If the host field contains the char ':', the person is using X.  */
  331.     strncpy(display, p->ut_host, sizeof(p->ut_host));
  332.     if ((colonp = index(display, ':')) != NULL) {
  333.     /* display string may be truncated at bad place.
  334.      * If ends with ':', assume display 0.
  335.      * If ends with '.', remove the '.'. */
  336.     n = strlen(display)-1;
  337.     if (display[n] == ':') {
  338.         display[n+1] = '0';
  339.         display[n+2] = '\0';
  340.     } else if (display[n] == '.') display[n] = '\0';
  341.  
  342.     /* We are interested in the display, screen is irrelevant */
  343.     if (dotp = index(colonp, '.')) *dotp = '\0';
  344.     /* Recognize that hostname:0 is equivalent to :0 */
  345.     if (strncmp(display, hostname, strlen(hostname)) == 0)
  346.         displayp = colonp;
  347.     else
  348.         displayp = display;
  349.  
  350.     /*
  351.      *  Since this is an X window, we are either running on a pty or are
  352.      *  the X device.  Make sure we pick the least idle pty in case
  353.      *  the X operation fails.
  354.      */
  355.     sprintf(xpty,"/dev/%s", p->ut_line);
  356.     if (stat(xpty,&ttystat) == 0) {
  357.         /*
  358.          *  If we can't write to the xpty or it is not a character special,
  359.          *  then our idle time is infinite (-2).
  360.          */
  361.         if (! ((ttystat.st_mode & 020) &&
  362.                     ((ttystat.st_mode & S_IFMT) == S_IFCHR)))
  363.         idle = -2;
  364.         else {
  365.         /*
  366.          *  Get a major number of a known pty.
  367.          */
  368.         if (get_major) {
  369.             get_major = 0;    /* only try to get major once */
  370.  
  371. #ifndef CRAY
  372.             if (stat("/dev/ttyp0",&p0stat) == 0) {
  373. #else  !CRAY
  374.             if (stat("/dev/ttyp000",&p0stat) == 0) {
  375. #endif  CRAY
  376.             have_major = 1;
  377.             pty_major = major(p0stat.st_rdev);
  378.             } else
  379.             perror("ttyp0 stat:");
  380.         }
  381.  
  382.         /*
  383.          *  If we have a pty major number and it matches this
  384.          *  tty, then we know we have a pty.
  385.          */
  386.         if (have_major && pty_major == major(ttystat.st_rdev)) {
  387.             /* Get idle time */
  388.             idle = (long) now - (long) ttystat.st_atime;
  389.             if (idle < 0L) idle = 0L;
  390.         } else
  391.             idle = -1;    /* pick another if we can */
  392.         }
  393.     } else {
  394.         perror("stat:");
  395.         idle = -2;
  396.     }
  397.  
  398.     /* Search the X list for a matching display. */
  399.     for (xptr = xlist; xptr != NULL; xptr = xptr->next) {
  400.         if (strcmp(xptr->display, displayp) == 0) {
  401.         /*
  402.          *  We have matched displays.  We always want to take the
  403.          *  least idle tty.  If the chosen tty (xptr) is unknown
  404.          *  (-2) then use the new one.  If we couldn't get the chosen
  405.          *  tty's major number or it didn't match a pty (-1) and
  406.          *  the new one has a valid idle itme, then use the new one
  407.          *  as if it is known (!= -2).  If the chosen tty has an idle
  408.          *  time and the new one is less, use the new tty.
  409.          */
  410.         if ( xptr->idle == -2                    ||
  411.             (xptr->idle == -1 && idle != -2 )            ||
  412.             (xptr->idle >=  0 && idle >= 0 && idle < xptr->idle) ) {
  413. #ifdef DEBUG
  414.             fprintf(stderr,
  415.                 "%s@%s:  switching from %s to %s, idle %d\n",
  416.                 xptr->user, xptr->display,
  417.                 xptr->tty, p->ut_line, (int) idle);
  418. #endif
  419.             goto new_tty;    /* an evil goto */
  420.             }
  421.  
  422.         break;
  423.         }
  424.     }
  425.     if (xptr == NULL) {
  426.         xptr = (struct xlist *) exmalloc(sizeof(struct xlist));
  427.         xptr->next = xlist;
  428.         xlist = xptr;
  429.         strcpy(xptr->display,  displayp);
  430.         strncpy(xptr->user, p->ut_name, sizeof(p->ut_name));
  431. #ifdef DEBUG
  432.         fprintf(stderr, "%s@%s:  new entry on %s, idle %d\n",
  433.                 xptr->user, xptr->display,
  434.                 p->ut_line, (int) idle);
  435. #endif
  436. new_tty:
  437.         strncpy(xptr->tty, p->ut_line, sizeof(p->ut_line));
  438.         xptr->idle = idle;
  439.     }
  440.     return 1;
  441.     }
  442.  
  443.     return 0;
  444. }
  445.  
  446. sendwindows()
  447. {
  448.     struct xlist *xptr;
  449.     FILE     *xfp;        /* file pointer for xwall command */
  450.     char     xcomm[128];    /* xwall command */
  451.     int         status;    /* pclose() status */
  452.     int         fs;        /* fork status */
  453.  
  454. #ifdef DEBUG
  455.     fprintf(stderr,"\n");
  456. #endif
  457.  
  458.     for (xptr = xlist; xptr != NULL; xptr = xptr->next) {
  459. #ifdef DEBUG
  460.     fprintf(stderr,"Trying %s@%s on %s\n",
  461.         xptr->user, xptr->display ,xptr->tty);
  462. #endif
  463.     sprintf(xcomm,"%s -user %s -display %s",XWALL,
  464.         xptr->user, xptr->display);
  465.  
  466.     if ((fs = fork()) == 0) {
  467.         /*
  468.          *  We want to fork because xwall will wait 15 seconds
  469.          *  before deciding that it can't connect to the remote
  470.          *  xwalld.
  471.          */
  472.         if (xfp = popen(xcomm,"w")) {
  473.         if ((int) fwrite(xmesg,1,xmsize,xfp) != xmsize) {
  474.             fprintf(stderr, "wall: fwrite to pipe of '%s' failed\n",
  475.             xcomm);
  476.             goto tty_wall;
  477.         }
  478.         /* pclose() returns the result of a wait() */
  479.         status = (pclose(xfp) >> 8) & 0xff;    /* get return status */
  480.         if (status) {
  481.             fprintf(stderr, "wall: '%s' failed, return code %d\n",
  482.             xcomm, status);
  483.             goto tty_wall;
  484.         }
  485.         } else {
  486.         fprintf(stderr, "wall:  popen failed on '%s'\n", xcomm);
  487. tty_wall:
  488.         sendmes(xptr->tty);
  489.  
  490.         }
  491.         _exit(0);
  492.     } else if (fs < 0)
  493.         perror("fork");
  494.     }
  495.  
  496.     /*
  497.      *  Wait for all children to finish.
  498.      */
  499.     while ((int) wait((union wait *)0) != -1) ;
  500. }
  501.  
  502. char *
  503. exmalloc(size)
  504.     int size;
  505. {
  506.     char *ret;
  507.  
  508.     if ((ret = malloc(size)) == 0) {
  509.     fprintf(stderr, "Out of memory\n");
  510.     exit(1);
  511.     }
  512.     return (ret);
  513. }
  514. #endif UW
  515.