add cpp
[unix-history] / usr / src / usr.bin / write / write.c
CommitLineData
cd784246 1/*
c213cedf
KB
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 *
32ce521f 8 * %sccs.include.redist.c%
cd784246
BJ
9 */
10
c213cedf
KB
11#ifndef lint
12char copyright[] =
13"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14 All rights reserved.\n";
15#endif /* not lint */
16
17#ifndef lint
32ce521f 18static char sccsid[] = "@(#)write.c 4.22 (Berkeley) %G%";
c213cedf
KB
19#endif /* not lint */
20
21#include <sys/param.h>
7abf8d65 22#include <sys/signal.h>
c213cedf
KB
23#include <sys/stat.h>
24#include <sys/file.h>
72cf2549 25#include <sys/time.h>
7abf8d65 26#include <utmp.h>
7abf8d65 27#include <ctype.h>
c213cedf
KB
28#include <pwd.h>
29#include <stdio.h>
38dde0cd 30#include <string.h>
c213cedf 31
d6178c05 32extern int errno;
cd784246
BJ
33
34main(argc, argv)
cf288731 35 int argc;
c213cedf 36 char **argv;
cd784246 37{
c213cedf 38 register char *cp;
c213cedf 39 time_t atime;
d6178c05
KB
40 uid_t myuid;
41 int msgsok, myttyfd;
f67b129a 42 char tty[MAXPATHLEN], *mytty, *ttyname();
c213cedf
KB
43 void done();
44
d6178c05 45 /* check that sender has write enabled */
c213cedf
KB
46 if (isatty(fileno(stdin)))
47 myttyfd = fileno(stdin);
48 else if (isatty(fileno(stdout)))
49 myttyfd = fileno(stdout);
50 else if (isatty(fileno(stderr)))
51 myttyfd = fileno(stderr);
52 else {
53 (void)fprintf(stderr, "write: can't find your tty\n");
cd784246
BJ
54 exit(1);
55 }
c213cedf
KB
56 if (!(mytty = ttyname(myttyfd))) {
57 (void)fprintf(stderr, "write: can't find your tty's name\n");
cd784246
BJ
58 exit(1);
59 }
c213cedf
KB
60 if (cp = rindex(mytty, '/'))
61 mytty = cp + 1;
62 if (term_chk(mytty, &msgsok, &atime, 1))
63 exit(1);
64 if (!msgsok) {
65 (void)fprintf(stderr,
66 "write: you have write permission turned off.\n");
cf288731 67 exit(1);
b40712b7 68 }
c213cedf 69
d6178c05 70 myuid = getuid();
c213cedf
KB
71
72 /* check args */
73 switch (argc) {
74 case 2:
d6178c05
KB
75 search_utmp(argv[1], tty, mytty, myuid);
76 do_write(tty, mytty, myuid);
c213cedf
KB
77 break;
78 case 3:
79 if (!strncmp(argv[2], "/dev/", 5))
80 argv[2] += 5;
81 if (utmp_chk(argv[1], argv[2])) {
82 (void)fprintf(stderr,
83 "write: %s is not logged in on %s.\n",
84 argv[1], argv[2]);
14c6ba7a 85 exit(1);
cd784246 86 }
c213cedf
KB
87 if (term_chk(argv[2], &msgsok, &atime, 1))
88 exit(1);
d6178c05 89 if (myuid && !msgsok) {
c213cedf
KB
90 (void)fprintf(stderr,
91 "write: %s has messages disabled on %s\n",
92 argv[1], argv[2]);
93 exit(1);
cd784246 94 }
d6178c05 95 do_write(argv[2], mytty, myuid);
c213cedf
KB
96 break;
97 default:
98 (void)fprintf(stderr, "usage: write user [tty]\n");
cd784246
BJ
99 exit(1);
100 }
c213cedf
KB
101 done();
102 /* NOTREACHED */
103}
104
105/*
106 * utmp_chk - checks that the given user is actually logged in on
107 * the given tty
108 */
109utmp_chk(user, tty)
110 char *user, *tty;
111{
112 struct utmp u;
113 int ufd;
114
115 if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
116 return(0); /* ignore error, shouldn't happen anyway */
117
118 while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
119 if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 &&
120 strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) {
121 (void)close(ufd);
122 return(0);
cd784246 123 }
31b42ab1 124
c213cedf
KB
125 (void)close(ufd);
126 return(1);
127}
31b42ab1 128
c213cedf
KB
129/*
130 * search_utmp - search utmp for the "best" terminal to write to
131 *
132 * Ignores terminals with messages disabled, and of the rest, returns
133 * the one with the most recent access time. Returns as value the number
134 * of the user's terminals with messages enabled, or -1 if the user is
135 * not logged in at all.
136 *
137 * Special case for writing to yourself - ignore the terminal you're
138 * writing from, unless that's the only terminal with messages enabled.
139 */
d6178c05 140search_utmp(user, tty, mytty, myuid)
c213cedf 141 char *user, *tty, *mytty;
d6178c05 142 uid_t myuid;
c213cedf
KB
143{
144 struct utmp u;
145 time_t bestatime, atime;
146 int ufd, nloggedttys, nttys, msgsok, user_is_me;
147 char atty[UT_LINESIZE + 1];
31b42ab1 148
c213cedf
KB
149 if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
150 perror("utmp");
151 exit(1);
152 }
153
154 nloggedttys = nttys = 0;
155 bestatime = 0;
156 user_is_me = 0;
157 while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
158 if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
159 ++nloggedttys;
d6178c05
KB
160 (void)strncpy(atty, u.ut_line, UT_LINESIZE);
161 atty[UT_LINESIZE] = '\0';
c213cedf
KB
162 if (term_chk(atty, &msgsok, &atime, 0))
163 continue; /* bad term? skip */
d6178c05 164 if (myuid && !msgsok)
c213cedf
KB
165 continue; /* skip ttys with msgs off */
166 if (strcmp(atty, mytty) == 0) {
167 user_is_me = 1;
168 continue; /* don't write to yourself */
169 }
170 ++nttys;
171 if (atime > bestatime) {
172 bestatime = atime;
173 (void)strcpy(tty, atty);
31b42ab1 174 }
93665ffd 175 }
c213cedf
KB
176
177 (void)close(ufd);
178 if (nloggedttys == 0) {
179 (void)fprintf(stderr, "write: %s is not logged in\n", user);
180 exit(1);
181 }
182 if (nttys == 0) {
183 if (user_is_me) { /* ok, so write to yourself! */
184 (void)strcpy(tty, mytty);
185 return;
186 }
187 (void)fprintf(stderr,
188 "write: %s has messages disabled\n", user);
189 exit(1);
190 } else if (nttys > 1) {
191 (void)fprintf(stderr,
192 "write: %s is logged in more than once; writing to %s\n",
193 user, tty);
cd784246 194 }
cd784246
BJ
195}
196
c213cedf
KB
197/*
198 * term_chk - check that a terminal exists, and get the message bit
199 * and the access time
200 */
201term_chk(tty, msgsokP, atimeP, showerror)
202 char *tty;
203 int *msgsokP, showerror;
204 time_t *atimeP;
cd784246 205{
c213cedf
KB
206 struct stat s;
207 char path[MAXPATHLEN];
cd784246 208
c213cedf
KB
209 (void)sprintf(path, "/dev/%s", tty);
210 if (stat(path, &s) < 0) {
211 if (showerror)
d6178c05
KB
212 (void)fprintf(stderr,
213 "write: %s: %s\n", path, strerror(errno));
c213cedf
KB
214 return(1);
215 }
216 *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
217 *atimeP = s.st_atime;
218 return(0);
cd784246
BJ
219}
220
c213cedf
KB
221/*
222 * do_write - actually make the connection
223 */
d6178c05 224do_write(tty, mytty, myuid)
c213cedf 225 char *tty, *mytty;
d6178c05 226 uid_t myuid;
cd784246 227{
c213cedf
KB
228 register char *login, *nows;
229 register struct passwd *pwd;
230 time_t now, time();
f67b129a 231 char *getlogin(), path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512];
c213cedf 232 void done();
cd784246 233
62488a93
CL
234 /* Determine our login name before the we reopen() stdout */
235 if ((login = getlogin()) == NULL)
236 if (pwd = getpwuid(myuid))
237 login = pwd->pw_name;
238 else
239 login = "???";
240
c213cedf
KB
241 (void)sprintf(path, "/dev/%s", tty);
242 if ((freopen(path, "w", stdout)) == NULL) {
62488a93 243 (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
c213cedf
KB
244 exit(1);
245 }
246
c213cedf 247 (void)signal(SIGINT, done);
d6178c05 248 (void)signal(SIGHUP, done);
c213cedf 249
d6178c05 250 /* print greeting */
c213cedf
KB
251 if (gethostname(host, sizeof(host)) < 0)
252 (void)strcpy(host, "???");
253 now = time((time_t *)NULL);
254 nows = ctime(&now);
255 nows[16] = '\0';
256 (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n",
d6178c05 257 login, host, mytty, nows + 11);
c213cedf
KB
258
259 while (fgets(line, sizeof(line), stdin) != NULL)
d6178c05 260 wr_fputs(line);
cd784246
BJ
261}
262
c213cedf
KB
263/*
264 * done - cleanup and exit
265 */
266void
267done()
cd784246 268{
c213cedf
KB
269 (void)printf("EOF\r\n");
270 exit(0);
cd784246
BJ
271}
272
c213cedf 273/*
d6178c05 274 * wr_fputs - like fputs(), but makes control characters visible and
c213cedf
KB
275 * turns \n into \r\n
276 */
d6178c05 277wr_fputs(s)
c213cedf 278 register char *s;
cd784246 279{
c213cedf 280 register char c;
cd784246 281
c213cedf
KB
282#define PUTC(c) if (putchar(c) == EOF) goto err;
283
284 for (; *s != '\0'; ++s) {
285 c = toascii(*s);
286 if (c == '\n') {
287 PUTC('\r');
288 PUTC('\n');
289 } else if (!isprint(c) && !isspace(c) && c != '\007') {
290 PUTC('^');
291 PUTC(c^0x40); /* DEL to ?, others to alpha */
292 } else
293 PUTC(c);
294 }
295 return;
296
297err: (void)fprintf(stderr, "write: %s\n", strerror(errno));
298 exit(1);
299#undef PUTC
cd784246 300}