home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / misc-utils / write.c < prev   
Encoding:
C/C++ Source or Header  |  1995-02-22  |  8.8 KB  |  348 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.  * Modified for Linux, Mon Mar  8 18:16:24 1993, faith@cs.unc.edu
  37.  * Wed Jun 22 21:41:56 1994, faith@cs.unc.edu:
  38.  *      Added fix from Mike Grupenhoff (kashmir@umiacs.umd.edu)
  39.  *
  40.  */
  41.  
  42. #ifndef lint
  43. char copyright[] =
  44. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  45.  All rights reserved.\n";
  46. #endif /* not lint */
  47.  
  48. #ifndef lint
  49. static char sccsid[] = "@(#)write.c    4.22 (Berkeley) 6/1/90";
  50. #endif /* not lint */
  51.  
  52. #include <sys/param.h>
  53. #include <sys/signal.h>
  54. #include <sys/stat.h>
  55. #include <sys/file.h>
  56. #include <sys/time.h>
  57. #include <utmp.h>
  58. #include <ctype.h>
  59. #include <pwd.h>
  60. #include <stdio.h>
  61. #include <string.h>
  62. #ifdef __linux__
  63. #include <paths.h>
  64. #endif
  65.  
  66. extern int errno;
  67.  
  68. main(argc, argv)
  69.     int argc;
  70.     char **argv;
  71. {
  72.     register char *cp;
  73.     time_t atime;
  74.     uid_t myuid;
  75.     int msgsok, myttyfd;
  76.     char tty[MAXPATHLEN], *mytty, *ttyname();
  77.     void done();
  78.  
  79.     /* check that sender has write enabled */
  80.     if (isatty(fileno(stdin)))
  81.         myttyfd = fileno(stdin);
  82.     else if (isatty(fileno(stdout)))
  83.         myttyfd = fileno(stdout);
  84.     else if (isatty(fileno(stderr)))
  85.         myttyfd = fileno(stderr);
  86.     else {
  87.         (void)fprintf(stderr, "write: can't find your tty\n");
  88.         exit(1);
  89.     }
  90.     if (!(mytty = ttyname(myttyfd))) {
  91.         (void)fprintf(stderr, "write: can't find your tty's name\n");
  92.         exit(1);
  93.     }
  94.     if (cp = rindex(mytty, '/'))
  95.         mytty = cp + 1;
  96.     if (term_chk(mytty, &msgsok, &atime, 1))
  97.         exit(1);
  98.     if (!msgsok) {
  99.         (void)fprintf(stderr,
  100.             "write: you have write permission turned off.\n");
  101.         exit(1);
  102.     }
  103.  
  104.     myuid = getuid();
  105.  
  106.     /* check args */
  107.     switch (argc) {
  108.     case 2:
  109.         search_utmp(argv[1], tty, mytty, myuid);
  110.         do_write(tty, mytty, myuid);
  111.         break;
  112.     case 3:
  113.         if (!strncmp(argv[2], "/dev/", 5))
  114.             argv[2] += 5;
  115.         if (utmp_chk(argv[1], argv[2])) {
  116.             (void)fprintf(stderr,
  117.                 "write: %s is not logged in on %s.\n",
  118.                 argv[1], argv[2]);
  119.             exit(1);
  120.         }
  121.         if (term_chk(argv[2], &msgsok, &atime, 1))
  122.             exit(1);
  123.         if (myuid && !msgsok) {
  124.             (void)fprintf(stderr,
  125.                 "write: %s has messages disabled on %s\n",
  126.                 argv[1], argv[2]);
  127.             exit(1);
  128.         }
  129.         do_write(argv[2], mytty, myuid);
  130.         break;
  131.     default:
  132.         (void)fprintf(stderr, "usage: write user [tty]\n");
  133.         exit(1);
  134.     }
  135.     done();
  136.     /* NOTREACHED */
  137. }
  138.  
  139. /*
  140.  * utmp_chk - checks that the given user is actually logged in on
  141.  *     the given tty
  142.  */
  143. utmp_chk(user, tty)
  144.     char *user, *tty;
  145. {
  146.     struct utmp u;
  147.     int ufd;
  148.  
  149.     if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
  150.         return(0);    /* ignore error, shouldn't happen anyway */
  151.  
  152.     while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
  153.         if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 &&
  154.             strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) {
  155.             (void)close(ufd);
  156.             return(0);
  157.         }
  158.  
  159.     (void)close(ufd);
  160.     return(1);
  161. }
  162.  
  163. /*
  164.  * search_utmp - search utmp for the "best" terminal to write to
  165.  *
  166.  * Ignores terminals with messages disabled, and of the rest, returns
  167.  * the one with the most recent access time.  Returns as value the number
  168.  * of the user's terminals with messages enabled, or -1 if the user is
  169.  * not logged in at all.
  170.  *
  171.  * Special case for writing to yourself - ignore the terminal you're
  172.  * writing from, unless that's the only terminal with messages enabled.
  173.  */
  174. search_utmp(user, tty, mytty, myuid)
  175.     char *user, *tty, *mytty;
  176.     uid_t myuid;
  177. {
  178.     struct utmp u;
  179.     time_t bestatime, atime;
  180.     int ufd, nloggedttys, nttys, msgsok, user_is_me;
  181. #ifdef __linux__
  182.     char atty[sizeof(u.ut_line) + 1];
  183. #else
  184.     char atty[UT_LINESIZE + 1];
  185. #endif
  186.  
  187.     if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
  188.         perror("utmp");
  189.         exit(1);
  190.     }
  191.  
  192.     nloggedttys = nttys = 0;
  193.     bestatime = 0;
  194.     user_is_me = 0;
  195.     while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
  196.         if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
  197.             ++nloggedttys;
  198. #ifdef __linux__
  199.             (void)strncpy(atty, u.ut_line, sizeof(u.ut_line));
  200.             atty[sizeof(u.ut_line)] = '\0';
  201. #else
  202.             (void)strncpy(atty, u.ut_line, UT_LINESIZE);
  203.             atty[UT_LINESIZE] = '\0';
  204. #endif
  205.             if (term_chk(atty, &msgsok, &atime, 0))
  206.                 continue;    /* bad term? skip */
  207.             if (myuid && !msgsok)
  208.                 continue;    /* skip ttys with msgs off */
  209.             if (strcmp(atty, mytty) == 0) {
  210.                 user_is_me = 1;
  211.                 continue;    /* don't write to yourself */
  212.             }
  213. #ifdef __linux__
  214.                         if (u.ut_type != USER_PROCESS)
  215.                     continue;       /* it's not a valid entry */
  216. #endif
  217.             ++nttys;
  218.             if (atime > bestatime) {
  219.                 bestatime = atime;
  220.                 (void)strcpy(tty, atty);
  221.             }
  222.         }
  223.  
  224.     (void)close(ufd);
  225.     if (nloggedttys == 0) {
  226.         (void)fprintf(stderr, "write: %s is not logged in\n", user);
  227.         exit(1);
  228.     }
  229.     if (nttys == 0) {
  230.         if (user_is_me) {        /* ok, so write to yourself! */
  231.             (void)strcpy(tty, mytty);
  232.             return;
  233.         }
  234.         (void)fprintf(stderr,
  235.             "write: %s has messages disabled\n", user);
  236.         exit(1);
  237.     } else if (nttys > 1) {
  238.         (void)fprintf(stderr,
  239.             "write: %s is logged in more than once; writing to %s\n",
  240.             user, tty);
  241.     }
  242. }
  243.  
  244. /*
  245.  * term_chk - check that a terminal exists, and get the message bit
  246.  *     and the access time
  247.  */
  248. term_chk(tty, msgsokP, atimeP, showerror)
  249.     char *tty;
  250.     int *msgsokP, showerror;
  251.     time_t *atimeP;
  252. {
  253.     struct stat s;
  254.     char path[MAXPATHLEN];
  255.  
  256.     (void)sprintf(path, "/dev/%s", tty);
  257.     if (stat(path, &s) < 0) {
  258.         if (showerror)
  259.             (void)fprintf(stderr,
  260.                 "write: %s: %s\n", path, strerror(errno));
  261.         return(1);
  262.     }
  263.     *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0;    /* group write bit */
  264.     *atimeP = s.st_atime;
  265.     return(0);
  266. }
  267.  
  268. /*
  269.  * do_write - actually make the connection
  270.  */
  271. do_write(tty, mytty, myuid)
  272.     char *tty, *mytty;
  273.     uid_t myuid;
  274. {
  275.     register char *login, *nows;
  276.     register struct passwd *pwd;
  277.     time_t now, time();
  278.     char *getlogin(), path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512];
  279.     void done();
  280.  
  281.     /* Determine our login name before the we reopen() stdout */
  282.     if ((login = getlogin()) == NULL)
  283.         if (pwd = getpwuid(myuid))
  284.             login = pwd->pw_name;
  285.         else
  286.             login = "???";
  287.  
  288.     (void)sprintf(path, "/dev/%s", tty);
  289.     if ((freopen(path, "w", stdout)) == NULL) {
  290.         (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
  291.         exit(1);
  292.     }
  293.  
  294.     (void)signal(SIGINT, done);
  295.     (void)signal(SIGHUP, done);
  296.  
  297.     /* print greeting */
  298.     if (gethostname(host, sizeof(host)) < 0)
  299.         (void)strcpy(host, "???");
  300.     now = time((time_t *)NULL);
  301.     nows = ctime(&now);
  302.     nows[16] = '\0';
  303.     (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n",
  304.         login, host, mytty, nows + 11);
  305.  
  306.     while (fgets(line, sizeof(line), stdin) != NULL)
  307.         wr_fputs(line);
  308. }
  309.  
  310. /*
  311.  * done - cleanup and exit
  312.  */
  313. void
  314. done()
  315. {
  316.     (void)printf("EOF\r\n");
  317.     exit(0);
  318. }
  319.  
  320. /*
  321.  * wr_fputs - like fputs(), but makes control characters visible and
  322.  *     turns \n into \r\n
  323.  */
  324. wr_fputs(s)
  325.     register char *s;
  326. {
  327.     register char c;
  328.  
  329. #define    PUTC(c)    if (putchar(c) == EOF) goto err;
  330.  
  331.     for (; *s != '\0'; ++s) {
  332.         c = toascii(*s);
  333.         if (c == '\n') {
  334.             PUTC('\r');
  335.             PUTC('\n');
  336.         } else if (!isprint(c) && !isspace(c) && c != '\007') {
  337.             PUTC('^');
  338.             PUTC(c^0x40);    /* DEL to ?, others to alpha */
  339.         } else
  340.             PUTC(c);
  341.     }
  342.     return;
  343.  
  344. err:    (void)fprintf(stderr, "write: %s\n", strerror(errno));
  345.     exit(1);
  346. #undef PUTC
  347. }
  348.