Commit | Line | Data |
---|---|---|
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 |
12 | char 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 | 18 | static 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 | 32 | extern int errno; |
cd784246 BJ |
33 | |
34 | main(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 | */ | |
109 | utmp_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 | 140 | search_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 | */ | |
201 | term_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 | 224 | do_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 | */ | |
266 | void | |
267 | done() | |
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 | 277 | wr_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 | ||
297 | err: (void)fprintf(stderr, "write: %s\n", strerror(errno)); | |
298 | exit(1); | |
299 | #undef PUTC | |
cd784246 | 300 | } |