home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / write / write.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  8.3 KB  |  327 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)write.c    4.22 (Berkeley) 6/1/90";
  45. #endif /* not lint */
  46.  
  47. #include <sys/param.h>
  48. #include <sys/signal.h>
  49. #include <sys/stat.h>
  50. #include <sys/file.h>
  51. #include <sys/time.h>
  52. #include <utmp.h>
  53. #include <ctype.h>
  54. #include <pwd.h>
  55. #include <stdio.h>
  56. #include <string.h>
  57.  
  58. extern int errno;
  59.  
  60. main(argc, argv)
  61.     int argc;
  62.     char **argv;
  63. {
  64.     register char *cp;
  65.     time_t atime;
  66.     uid_t myuid;
  67.     int msgsok, myttyfd;
  68.     char tty[MAXPATHLEN], *mytty, *ttyname();
  69.     void done();
  70.  
  71.     /* check that sender has write enabled */
  72.     if (isatty(fileno(stdin)))
  73.         myttyfd = fileno(stdin);
  74.     else if (isatty(fileno(stdout)))
  75.         myttyfd = fileno(stdout);
  76.     else if (isatty(fileno(stderr)))
  77.         myttyfd = fileno(stderr);
  78.     else {
  79.         (void)fprintf(stderr, "write: can't find your tty\n");
  80.         exit(1);
  81.     }
  82.     if (!(mytty = ttyname(myttyfd))) {
  83.         (void)fprintf(stderr, "write: can't find your tty's name\n");
  84.         exit(1);
  85.     }
  86.     if (cp = rindex(mytty, '/'))
  87.         mytty = cp + 1;
  88.     if (term_chk(mytty, &msgsok, &atime, 1))
  89.         exit(1);
  90.     if (!msgsok) {
  91.         (void)fprintf(stderr,
  92.             "write: you have write permission turned off.\n");
  93.         exit(1);
  94.     }
  95.  
  96.     myuid = getuid();
  97.  
  98.     /* check args */
  99.     switch (argc) {
  100.     case 2:
  101.         search_utmp(argv[1], tty, mytty, myuid);
  102.         do_write(tty, mytty, myuid);
  103.         break;
  104.     case 3:
  105.         if (!strncmp(argv[2], "/dev/", 5))
  106.             argv[2] += 5;
  107.         if (utmp_chk(argv[1], argv[2])) {
  108.             (void)fprintf(stderr,
  109.                 "write: %s is not logged in on %s.\n",
  110.                 argv[1], argv[2]);
  111.             exit(1);
  112.         }
  113.         if (term_chk(argv[2], &msgsok, &atime, 1))
  114.             exit(1);
  115.         if (myuid && !msgsok) {
  116.             (void)fprintf(stderr,
  117.                 "write: %s has messages disabled on %s\n",
  118.                 argv[1], argv[2]);
  119.             exit(1);
  120.         }
  121.         do_write(argv[2], mytty, myuid);
  122.         break;
  123.     default:
  124.         (void)fprintf(stderr, "usage: write user [tty]\n");
  125.         exit(1);
  126.     }
  127.     done();
  128.     /* NOTREACHED */
  129. }
  130.  
  131. /*
  132.  * utmp_chk - checks that the given user is actually logged in on
  133.  *     the given tty
  134.  */
  135. utmp_chk(user, tty)
  136.     char *user, *tty;
  137. {
  138.     struct utmp u;
  139.     int ufd;
  140.  
  141.     if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
  142.         return(0);    /* ignore error, shouldn't happen anyway */
  143.  
  144.     while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
  145.         if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 &&
  146.             strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) {
  147.             (void)close(ufd);
  148.             return(0);
  149.         }
  150.  
  151.     (void)close(ufd);
  152.     return(1);
  153. }
  154.  
  155. /*
  156.  * search_utmp - search utmp for the "best" terminal to write to
  157.  *
  158.  * Ignores terminals with messages disabled, and of the rest, returns
  159.  * the one with the most recent access time.  Returns as value the number
  160.  * of the user's terminals with messages enabled, or -1 if the user is
  161.  * not logged in at all.
  162.  *
  163.  * Special case for writing to yourself - ignore the terminal you're
  164.  * writing from, unless that's the only terminal with messages enabled.
  165.  */
  166. search_utmp(user, tty, mytty, myuid)
  167.     char *user, *tty, *mytty;
  168.     uid_t myuid;
  169. {
  170.     struct utmp u;
  171.     time_t bestatime, atime;
  172.     int ufd, nloggedttys, nttys, msgsok, user_is_me;
  173.     char atty[UT_LINESIZE + 1];
  174.  
  175.     if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
  176.         perror("utmp");
  177.         exit(1);
  178.     }
  179.  
  180.     nloggedttys = nttys = 0;
  181.     bestatime = 0;
  182.     user_is_me = 0;
  183.     while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
  184.         if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
  185.             ++nloggedttys;
  186.             (void)strncpy(atty, u.ut_line, UT_LINESIZE);
  187.             atty[UT_LINESIZE] = '\0';
  188.             if (term_chk(atty, &msgsok, &atime, 0))
  189.                 continue;    /* bad term? skip */
  190.             if (myuid && !msgsok)
  191.                 continue;    /* skip ttys with msgs off */
  192.             if (strcmp(atty, mytty) == 0) {
  193.                 user_is_me = 1;
  194.                 continue;    /* don't write to yourself */
  195.             }
  196.             ++nttys;
  197.             if (atime > bestatime) {
  198.                 bestatime = atime;
  199.                 (void)strcpy(tty, atty);
  200.             }
  201.         }
  202.  
  203.     (void)close(ufd);
  204.     if (nloggedttys == 0) {
  205.         (void)fprintf(stderr, "write: %s is not logged in\n", user);
  206.         exit(1);
  207.     }
  208.     if (nttys == 0) {
  209.         if (user_is_me) {        /* ok, so write to yourself! */
  210.             (void)strcpy(tty, mytty);
  211.             return;
  212.         }
  213.         (void)fprintf(stderr,
  214.             "write: %s has messages disabled\n", user);
  215.         exit(1);
  216.     } else if (nttys > 1) {
  217.         (void)fprintf(stderr,
  218.             "write: %s is logged in more than once; writing to %s\n",
  219.             user, tty);
  220.     }
  221. }
  222.  
  223. /*
  224.  * term_chk - check that a terminal exists, and get the message bit
  225.  *     and the access time
  226.  */
  227. term_chk(tty, msgsokP, atimeP, showerror)
  228.     char *tty;
  229.     int *msgsokP, showerror;
  230.     time_t *atimeP;
  231. {
  232.     struct stat s;
  233.     char path[MAXPATHLEN];
  234.  
  235.     (void)sprintf(path, "/dev/%s", tty);
  236.     if (stat(path, &s) < 0) {
  237.         if (showerror)
  238.             (void)fprintf(stderr,
  239.                 "write: %s: %s\n", path, strerror(errno));
  240.         return(1);
  241.     }
  242.     *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0;    /* group write bit */
  243.     *atimeP = s.st_atime;
  244.     return(0);
  245. }
  246.  
  247. /*
  248.  * do_write - actually make the connection
  249.  */
  250. do_write(tty, mytty, myuid)
  251.     char *tty, *mytty;
  252.     uid_t myuid;
  253. {
  254.     register char *login, *nows;
  255.     register struct passwd *pwd;
  256.     time_t now, time();
  257.     char *getlogin(), path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512];
  258.     void done();
  259.  
  260.     /* Determine our login name before the we reopen() stdout */
  261.     if ((login = getlogin()) == NULL)
  262.         if (pwd = getpwuid(myuid))
  263.             login = pwd->pw_name;
  264.         else
  265.             login = "???";
  266.  
  267.     (void)sprintf(path, "/dev/%s", tty);
  268.     if ((freopen(path, "w", stdout)) == NULL) {
  269.         (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
  270.         exit(1);
  271.     }
  272.  
  273.     (void)signal(SIGINT, done);
  274.     (void)signal(SIGHUP, done);
  275.  
  276.     /* print greeting */
  277.     if (gethostname(host, sizeof(host)) < 0)
  278.         (void)strcpy(host, "???");
  279.     now = time((time_t *)NULL);
  280.     nows = ctime(&now);
  281.     nows[16] = '\0';
  282.     (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n",
  283.         login, host, mytty, nows + 11);
  284.  
  285.     while (fgets(line, sizeof(line), stdin) != NULL)
  286.         wr_fputs(line);
  287. }
  288.  
  289. /*
  290.  * done - cleanup and exit
  291.  */
  292. void
  293. done()
  294. {
  295.     (void)printf("EOF\r\n");
  296.     exit(0);
  297. }
  298.  
  299. /*
  300.  * wr_fputs - like fputs(), but makes control characters visible and
  301.  *     turns \n into \r\n
  302.  */
  303. wr_fputs(s)
  304.     register char *s;
  305. {
  306.     register char c;
  307.  
  308. #define    PUTC(c)    if (putchar(c) == EOF) goto err;
  309.  
  310.     for (; *s != '\0'; ++s) {
  311.         c = toascii(*s);
  312.         if (c == '\n') {
  313.             PUTC('\r');
  314.             PUTC('\n');
  315.         } else if (!isprint(c) && !isspace(c) && c != '\007') {
  316.             PUTC('^');
  317.             PUTC(c^0x40);    /* DEL to ?, others to alpha */
  318.         } else
  319.             PUTC(c);
  320.     }
  321.     return;
  322.  
  323. err:    (void)fprintf(stderr, "write: %s\n", strerror(errno));
  324.     exit(1);
  325. #undef PUTC
  326. }
  327.