2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
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 * Mon Jul 1 17:01:39 MET DST 1996, janl@math.uio.no:
40 * - Added fix from David.Chapell@mail.trincoll.edu enabeling daemons
42 * - ANSIed it since I was working on it anyway.
43 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
44 * - added Native Language Support
57 #include <sys/param.h>
60 #include <asm/param.h>
64 #include "carefulputc.h"
65 #include "closestream.h"
68 static void __attribute__ ((__noreturn__
)) usage(FILE * out
);
69 void search_utmp(char *, char *, char *, uid_t
);
70 void do_write(char *, char *, uid_t
);
71 void wr_fputs(char *);
72 static void __attribute__ ((__noreturn__
)) done(int);
73 int term_chk(char *, int *, time_t *, int);
74 int utmp_chk(char *, char *);
78 static void __attribute__ ((__noreturn__
)) usage(FILE * out
)
80 fputs(_("\nUsage:\n"), out
);
82 _(" %s [options] <user> [<ttyname>]\n"),
83 program_invocation_short_name
);
85 fputs(_("\nOptions:\n"), out
);
86 fputs(_(" -V, --version output version information and exit\n"
87 " -h, --help display this help and exit\n\n"), out
);
89 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
92 int main(int argc
, char **argv
)
96 int msgsok
, myttyfd
, c
;
97 char tty
[MAXPATHLEN
], *mytty
;
99 static const struct option longopts
[] = {
100 {"version", no_argument
, NULL
, 'V'},
101 {"help", no_argument
, NULL
, 'h'},
105 setlocale(LC_ALL
, "");
106 bindtextdomain(PACKAGE
, LOCALEDIR
);
108 atexit(close_stdout
);
110 while ((c
= getopt_long(argc
, argv
, "Vh", longopts
, NULL
)) != -1)
113 printf(_("%s from %s\n"),
114 program_invocation_short_name
,
125 /* check that sender has write enabled */
126 if (isatty(fileno(stdin
)))
127 myttyfd
= fileno(stdin
);
128 else if (isatty(fileno(stdout
)))
129 myttyfd
= fileno(stdout
);
130 else if (isatty(fileno(stderr
)))
131 myttyfd
= fileno(stderr
);
136 if (!(mytty
= ttyname(myttyfd
)))
138 _("can't find your tty's name"));
141 * We may have /dev/ttyN but also /dev/pts/xx. Below,
142 * term_chk() will put "/dev/" in front, so remove that
145 if (!strncmp(mytty
, "/dev/", 5))
147 if (term_chk(mytty
, &msgsok
, &atime
, 1))
151 _("you have write permission turned off"));
161 search_utmp(argv
[1], tty
, mytty
, myuid
);
162 do_write(tty
, mytty
, myuid
);
165 if (!strncmp(argv
[2], "/dev/", 5))
167 if (utmp_chk(argv
[1], argv
[2]))
169 _("%s is not logged in on %s"),
171 if (term_chk(argv
[2], &msgsok
, &atime
, 1))
173 if (myuid
&& !msgsok
)
175 _("%s has messages disabled on %s"),
177 do_write(argv
[2], mytty
, myuid
);
190 * utmp_chk - checks that the given user is actually logged in on
193 int utmp_chk(char *user
, char *tty
)
199 utmpname(_PATH_UTMP
);
202 while ((uptr
= getutent())) {
203 memcpy(&u
, uptr
, sizeof(u
));
204 if (strncmp(user
, u
.ut_name
, sizeof(u
.ut_name
)) == 0 &&
205 strncmp(tty
, u
.ut_line
, sizeof(u
.ut_line
)) == 0) {
216 * search_utmp - search utmp for the "best" terminal to write to
218 * Ignores terminals with messages disabled, and of the rest, returns
219 * the one with the most recent access time. Returns as value the number
220 * of the user's terminals with messages enabled, or -1 if the user is
221 * not logged in at all.
223 * Special case for writing to yourself - ignore the terminal you're
224 * writing from, unless that's the only terminal with messages enabled.
226 void search_utmp(char *user
, char *tty
, char *mytty
, uid_t myuid
)
230 time_t bestatime
, atime
;
231 int nloggedttys
, nttys
, msgsok
, user_is_me
;
232 char atty
[sizeof(u
.ut_line
) + 1];
234 utmpname(_PATH_UTMP
);
237 nloggedttys
= nttys
= 0;
240 while ((uptr
= getutent())) {
241 memcpy(&u
, uptr
, sizeof(u
));
242 if (strncmp(user
, u
.ut_name
, sizeof(u
.ut_name
)) == 0) {
244 strncpy(atty
, u
.ut_line
, sizeof(u
.ut_line
));
245 atty
[sizeof(u
.ut_line
)] = '\0';
246 if (term_chk(atty
, &msgsok
, &atime
, 0))
249 if (myuid
&& !msgsok
)
250 /* skip ttys with msgs off */
252 if (strcmp(atty
, mytty
) == 0) {
254 /* don't write to yourself */
257 if (u
.ut_type
!= USER_PROCESS
)
258 /* it's not a valid entry */
261 if (atime
> bestatime
) {
269 if (nloggedttys
== 0)
270 errx(EXIT_FAILURE
, _("%s is not logged in"), user
);
273 /* ok, so write to yourself! */
277 errx(EXIT_FAILURE
, _("%s has messages disabled"), user
);
278 } else if (nttys
> 1) {
279 warnx(_("%s is logged in more than once; writing to %s"),
285 * term_chk - check that a terminal exists, and get the message bit
286 * and the access time
288 int term_chk(char *tty
, int *msgsokP
, time_t * atimeP
, int showerror
)
291 char path
[MAXPATHLEN
];
293 if (strlen(tty
) + 6 > sizeof(path
))
295 sprintf(path
, "/dev/%s", tty
);
296 if (stat(path
, &s
) < 0) {
302 /* group write bit and group ownership */
303 *msgsokP
= (s
.st_mode
& (S_IWRITE
>> 3)) && myegid
== s
.st_gid
;
304 *atimeP
= s
.st_atime
;
309 * do_write - actually make the connection
311 void do_write(char *tty
, char *mytty
, uid_t myuid
)
313 char *login
, *pwuid
, *nows
;
316 char path
[MAXPATHLEN
], host
[MAXHOSTNAMELEN
], line
[512];
318 /* Determine our login name(s) before the we reopen() stdout */
319 if ((pwd
= getpwuid(myuid
)) != NULL
)
320 pwuid
= pwd
->pw_name
;
323 if ((login
= getlogin()) == NULL
)
326 if (strlen(tty
) + 6 > sizeof(path
))
327 errx(EXIT_FAILURE
, _("tty path %s too long"), tty
);
328 snprintf(path
, sizeof(path
), "/dev/%s", tty
);
329 if ((freopen(path
, "w", stdout
)) == NULL
)
330 err(EXIT_FAILURE
, "%s", path
);
332 signal(SIGINT
, done
);
333 signal(SIGHUP
, done
);
336 if (gethostname(host
, sizeof(host
)) < 0)
338 now
= time((time_t *) NULL
);
341 printf("\r\n\007\007\007");
342 if (strcmp(login
, pwuid
))
343 printf(_("Message from %s@%s (as %s) on %s at %s ..."),
344 login
, host
, pwuid
, mytty
, nows
+ 11);
346 printf(_("Message from %s@%s on %s at %s ..."),
347 login
, host
, mytty
, nows
+ 11);
350 while (fgets(line
, sizeof(line
), stdin
) != NULL
)
355 * done - cleanup and exit
357 static void __attribute__ ((__noreturn__
))
358 done(int dummy
__attribute__ ((__unused__
)))
365 * wr_fputs - like fputs(), but makes control characters visible and
366 * turns \n into \r\n.
368 void wr_fputs(char *s
)
372 #define PUTC(c) if (carefulputc(c, stdout) == EOF) \
373 err(EXIT_FAILURE, _("carefulputc failed"));