*** empty log message ***
[dana/urxvt.git] / src / logging.C
1 /*--------------------------------*-C-*---------------------------------*
2  * File:        logging.C
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 1992      John Bovey <jdb@ukc.ac.uk>
7  *                              - original version
8  * Copyright (c) 1993      lipka
9  * Copyright (c) 1993      Brian Stempien <stempien@cs.wmich.edu>
10  * Copyright (c) 1995      Raul Garcia Garcia <rgg@tid.es>
11  * Copyright (c) 1995      Piet W. Plomp <piet@idefix.icce.rug.nl>
12  * Copyright (c) 1997      Raul Garcia Garcia <rgg@tid.es>
13  * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
14  *                              - extensive modifications
15  * Copyright (c) 1999      D J Hawkey Jr <hawkeyd@visi.com>
16  *                              - lastlog support
17  * Copyright (c) 2004      Marc Lehmann <pcg@goof.com>
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 2 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32  *----------------------------------------------------------------------*/
33 /*----------------------------------------------------------------------*
34  * Public:
35  *      extern void cleanutent (void);
36  *      extern void makeutent (const char * pty, const char * hostname);
37  *
38  * Private:
39  *      rxvt_update_wtmp ();
40  *----------------------------------------------------------------------*/
41
42 #include "../config.h"          /* NECESSARY */
43 #include "rxvt.h"               /* NECESSARY */
44 #include "logging.h"
45 #ifdef UTMP_SUPPORT
46
47 #if HAVE_STRUCT_UTMP
48 int              rxvt_write_bsd_utmp              (int utmp_pos, struct utmp *wu);
49 void             rxvt_update_wtmp                 (const char *fname, const struct utmp *putmp);
50 #endif
51
52 void             rxvt_update_lastlog              (const char *fname, const char *pty, const char *host);
53
54 /*
55  * BSD style utmp entry
56  *      ut_line, ut_name, ut_host, ut_time
57  * SYSV style utmp (and utmpx) entry
58  *      ut_user, ut_id, ut_line, ut_pid, ut_type, ut_exit, ut_time
59  */
60
61 /* ------------------------------------------------------------------------- */
62
63 /*
64  * make and write utmp and wtmp entries
65  */
66 void
67 rxvt_term::makeutent (const char *pty, const char *hostname)
68 {
69 #ifdef HAVE_STRUCT_UTMP
70   struct utmp *ut = &this->ut;
71 #endif
72 #ifdef HAVE_STRUCT_UTMPX
73   struct utmpx *utx = &this->utx;
74 #endif
75 #ifdef HAVE_UTMP_PID
76   int i;
77 #endif
78   struct passwd *pwent = getpwuid (getuid ());
79
80   if (!strncmp (pty, "/dev/", 5))
81     pty += 5;           /* skip /dev/ prefix */
82
83 #ifdef HAVE_UTMP_PID
84   if (!strncmp (pty, "pty", 3) || !strncmp (pty, "tty", 3))
85     strncpy (ut_id, pty + 3, sizeof (ut_id));
86   else if (sscanf (pty, "pts/%d", &i) == 1)
87     sprintf (ut_id, "vt%02x", (i & 0xff));      /* sysv naming */
88   else if (strncmp (pty, "pty", 3) && strncmp (pty, "tty", 3))
89     {
90       rxvt_warn ("can't parse tty name \"%s\", not adding utmp entry.\n", pty);
91       return;
92     }
93 #endif
94
95 #ifdef HAVE_STRUCT_UTMP
96   memset (ut, 0, sizeof (struct utmp));
97 # ifdef HAVE_UTMP_PID
98   setutent ();
99   strncpy (ut->ut_id, ut_id, sizeof (ut->ut_id));
100   ut->ut_type = DEAD_PROCESS;
101   getutid (ut);         /* position to entry in utmp file */
102   strncpy (ut_id, ut_id, sizeof (ut_id));
103 # endif
104 #endif
105
106 #ifdef HAVE_STRUCT_UTMPX
107   memset (utx, 0, sizeof (struct utmpx));
108   setutxent ();
109   strncpy (utx->ut_id, ut_id, sizeof (utx->ut_id));
110   utx->ut_type = DEAD_PROCESS;
111   getutxid (utx);               /* position to entry in utmp file */
112   strncpy (ut_id, ut_id, sizeof (ut_id));
113 #endif
114
115 #ifdef HAVE_STRUCT_UTMP
116   strncpy (ut->ut_line, pty, sizeof (ut->ut_line));
117   ut->ut_time = time (NULL);
118 # ifdef HAVE_UTMP_PID
119   strncpy (ut->ut_user, (pwent && pwent->pw_name) ? pwent->pw_name : "?",
120           sizeof (ut->ut_user));
121   strncpy (ut->ut_id, ut_id, sizeof (ut->ut_id));
122   ut->ut_time = time (NULL);
123   ut->ut_pid = cmd_pid;
124 #  ifdef HAVE_UTMP_HOST
125   strncpy (ut->ut_host, hostname, sizeof (ut->ut_host));
126 #  endif
127   ut->ut_type = USER_PROCESS;
128   pututline (ut);
129   endutent ();                  /* close the file */
130   utmp_pos = 0;
131 # else
132   strncpy (ut->ut_name, (pwent && pwent->pw_name) ? pwent->pw_name : "?",
133           sizeof (ut->ut_name));
134 #  ifdef HAVE_UTMP_HOST
135   strncpy (ut->ut_host, hostname, sizeof (ut->ut_host));
136 #  endif
137 # endif
138 #endif
139
140 #ifdef HAVE_STRUCT_UTMPX
141   strncpy (utx->ut_line, pty, sizeof (utx->ut_line));
142   strncpy (utx->ut_user, (pwent && pwent->pw_name) ? pwent->pw_name : "?",
143           sizeof (utx->ut_user));
144   strncpy (utx->ut_id, ut_id, sizeof (utx->ut_id));
145 # if HAVE_UTMPX_SESSION
146   utx->ut_session = getsid (0);
147 # endif
148   utx->ut_tv.tv_sec = time (NULL);
149   utx->ut_tv.tv_usec = 0;
150   utx->ut_pid = cmd_pid;
151 # ifdef HAVE_UTMPX_HOST
152   strncpy (utx->ut_host, hostname, sizeof (utx->ut_host));
153 #  if 0
154   {
155     char           *colon;
156
157     if ((colon = strrchr (ut->ut_host, ':')) != NULL)
158       *colon = '\0';
159   }
160 #  endif
161 # endif
162   utx->ut_type = USER_PROCESS;
163   pututxline (utx);
164   endutxent ();         /* close the file */
165   utmp_pos = 0;
166 #endif
167
168 #if defined(HAVE_STRUCT_UTMP) && !defined(HAVE_UTMP_PID)
169
170   {
171     int             i;
172 # ifdef HAVE_TTYSLOT
173     i = ttyslot ();
174     if (rxvt_write_bsd_utmp (i, ut))
175       utmp_pos = i;
176 # else
177     FILE           *fd0;
178
179     if ((fd0 = fopen (TTYTAB_FILENAME, "r")) != NULL)
180       {
181         char            buf[256], name[256];
182
183         buf[sizeof (buf) - 1] = '\0';
184         for (i = 1; (fgets (buf, sizeof (buf) - 1, fd0) != NULL);)
185           {
186             if (*buf == '#' || sscanf (buf, "%s", name) != 1)
187               continue;
188             if (!strcmp (ut->ut_line, name))
189               {
190                 if (!rxvt_write_bsd_utmp (i, ut))
191                   i = 0;
192                 utmp_pos = i;
193                 fclose (fd0);
194                 break;
195               }
196             i++;
197           }
198         fclose (fd0);
199       }
200 # endif
201
202   }
203 #endif
204
205 #ifdef WTMP_SUPPORT
206 # ifdef WTMP_ONLY_ON_LOGIN
207   if (options & Opt_loginShell)
208 # endif
209     {
210 # ifdef HAVE_STRUCT_UTMP
211 #  ifdef HAVE_UPDWTMP
212       updwtmp (RXVT_WTMP_FILE, ut);
213 #  else
214       rxvt_update_wtmp (RXVT_WTMP_FILE, ut);
215 #  endif
216 # endif
217 # ifdef HAVE_STRUCT_UTMPX
218 #  if HAVE_UPDWTMPX
219       updwtmpx (RXVT_WTMPX_FILE, utx);
220 #  else
221       pututxline (utx);
222 #  endif
223 # endif
224     }
225 #endif
226 #if defined(LASTLOG_SUPPORT) && defined(RXVT_LASTLOG_FILE)
227   if (options & Opt_loginShell)
228     rxvt_update_lastlog (RXVT_LASTLOG_FILE, pty, hostname);
229 #endif
230 }
231
232 /* ------------------------------------------------------------------------- */
233 /*
234  * remove utmp and wtmp entries
235  */
236 void
237 rxvt_term::cleanutent ()
238 {
239 #ifdef HAVE_STRUCT_UTMP
240   struct utmp *ut = &this->ut;
241 #endif
242 #ifdef HAVE_STRUCT_UTMPX
243   struct utmpx *tmputx, *utx = &this->utx;
244 #endif
245
246 #ifdef HAVE_STRUCT_UTMP
247 # ifdef HAVE_UTMP_PID
248   memset (ut, 0, sizeof (struct utmp));
249   setutent ();
250   strncpy (ut->ut_id, ut_id, sizeof (ut->ut_id));
251   ut->ut_type = USER_PROCESS;
252   {
253     struct utmp    *tmput = getutid (ut);
254
255     if (tmput)          /* position to entry in utmp file */
256       ut = tmput;
257   }
258   ut->ut_type = DEAD_PROCESS;
259 # else
260   memset (ut->ut_name, 0, sizeof (ut->ut_name));
261 #  ifdef HAVE_UTMP_HOST
262   memset (ut->ut_host, 0, sizeof (ut->ut_host));
263 #  endif
264 # endif
265   ut->ut_time = time (NULL);
266 #endif
267
268 #ifdef HAVE_STRUCT_UTMPX
269   memset (utx, 0, sizeof (struct utmpx));
270   setutxent ();
271   strncpy (utx->ut_id, ut_id, sizeof (utx->ut_id));
272   utx->ut_type = USER_PROCESS;
273   if ((tmputx = getutxid (utx)))        /* position to entry in utmp file */
274     utx = tmputx;
275   utx->ut_type = DEAD_PROCESS;
276 # if HAVE_UTMPX_SESSION
277   utx->ut_session = getsid (0);
278 # endif
279   utx->ut_tv.tv_sec = time (NULL);
280   utx->ut_tv.tv_usec = 0;
281 #endif
282
283   /*
284    * Write ending wtmp entry
285    */
286 #ifdef WTMP_SUPPORT
287 # ifdef WTMP_ONLY_ON_LOGIN
288   if (options & Opt_loginShell)
289 # endif
290     {
291 # ifdef HAVE_STRUCT_UTMP
292 #  ifdef HAVE_UPDWTMP
293       updwtmp (RXVT_WTMP_FILE, ut);
294 #  else
295       rxvt_update_wtmp (RXVT_WTMP_FILE, ut);
296 #  endif
297 # endif
298 # ifdef HAVE_STRUCT_UTMPX
299 #  if HAVE_UPDWTMPX
300       updwtmpx (RXVT_WTMPX_FILE, utx);
301 #  else
302       pututxline (utx);
303 #  endif
304 # endif
305     }
306 #endif
307
308   /*
309    * Write utmp entry
310    */
311 #ifdef HAVE_STRUCT_UTMP
312 # ifdef HAVE_UTMP_PID
313   if (ut->ut_pid == cmd_pid)
314     pututline (ut);
315   endutent ();
316 # else
317   memset (ut, 0, sizeof (struct utmp));
318   rxvt_write_bsd_utmp (utmp_pos, ut);
319 # endif
320 #endif
321 #ifdef HAVE_STRUCT_UTMPX
322   if (utx->ut_pid == cmd_pid)
323     pututxline (utx);
324   endutxent ();
325 #endif
326 }
327
328 /* ------------------------------------------------------------------------- */
329 /*
330  * Write a BSD style utmp entry
331  */
332 #ifdef HAVE_UTMP_H
333 int
334 rxvt_write_bsd_utmp (int utmp_pos, struct utmp *wu)
335 {
336   int             fd;
337
338   if (utmp_pos <= 0 || (fd = open (RXVT_UTMP_FILE, O_WRONLY)) == -1)
339     return 0;
340
341   if (lseek (fd, (off_t) (utmp_pos * sizeof (struct utmp)), SEEK_SET) != -1)
342     write (fd, wu, sizeof (struct utmp));
343   close (fd);
344   return 1;
345 }
346 #endif
347
348 /* ------------------------------------------------------------------------- */
349 /*
350  * Update a BSD style wtmp entry
351  */
352 #if defined(WTMP_SUPPORT) && !defined(HAVE_UPDWTMP) && defined(HAVE_STRUCT_UTMP)
353 void
354 rxvt_update_wtmp (const char *fname, const struct utmp *putmp)
355 {
356   int             fd, gotlock, retry;
357   struct flock    lck;  /* fcntl locking scheme */
358   struct stat     sbuf;
359
360   if ((fd = open (fname, O_WRONLY | O_APPEND, 0)) < 0)
361     return;
362
363   lck.l_whence = SEEK_END;      /* start lock at current eof */
364   lck.l_len = 0;                /* end at ``largest possible eof'' */
365   lck.l_start = 0;
366   lck.l_type = F_WRLCK; /* we want a write lock */
367
368   /* attempt lock with F_SETLK; F_SETLKW would cause a deadlock! */
369   for (retry = 10, gotlock = 0; retry--;)
370     if (fcntl (fd, F_SETLK, &lck) != -1)
371       {
372         gotlock = 1;
373         break;
374       }
375     else if (errno != EAGAIN && errno != EACCES)
376       break;
377   if (!gotlock)
378     {           /* give it up */
379       close (fd);
380       return;
381     }
382   if (fstat (fd, &sbuf) == 0)
383     if (write (fd, putmp, sizeof (struct utmp)) != sizeof (struct utmp))
384       ftruncate (fd, sbuf.st_size);     /* remove bad writes */
385
386   lck.l_type = F_UNLCK; /* unlocking the file */
387   fcntl (fd, F_SETLK, &lck);
388   close (fd);
389 }
390 #endif
391
392 /* ------------------------------------------------------------------------- */
393 #ifdef LASTLOG_SUPPORT
394 void
395 rxvt_update_lastlog (const char *fname, const char *pty, const char *host)
396 {
397 # ifdef HAVE_STRUCT_LASTLOGX
398   struct lastlogx llx;
399 # endif
400 # ifdef HAVE_STRUCT_LASTLOG
401   int             fd;
402   struct lastlog  ll;
403 #  ifdef LASTLOG_IS_DIR
404   char            lastlogfile[256];
405 #  endif
406   struct passwd  *pwent;
407 # endif
408
409 # ifdef HAVE_STRUCT_LASTLOGX
410   memset (&llx, 0, sizeof (llx));
411   llx.ll_tv.tv_sec = time (NULL);
412   llx.ll_tv.tv_usec = 0;
413   strncpy (llx.ll_line, pty, sizeof (llx.ll_line));
414   strncpy (llx.ll_host, host, sizeof (llx.ll_host));
415   updlastlogx (RXVT_LASTLOGX_FILE, getuid (), &llx);
416 # endif
417
418 # ifdef HAVE_STRUCT_LASTLOG
419   pwent = getpwuid (getuid ());
420   if (!pwent)
421     {
422       rxvt_warn ("no entry in password file, not updating lastlog.\n");
423       return;
424     }
425
426   memset (&ll, 0, sizeof (ll));
427   ll.ll_time = time (NULL);
428   strncpy (ll.ll_line, pty, sizeof (ll.ll_line));
429   strncpy (ll.ll_host, host, sizeof (ll.ll_host));
430 #  ifdef LASTLOG_IS_DIR
431   sprintf (lastlogfile, "%.*s/%.*s",
432           sizeof (lastlogfile) - sizeof (pwent->pw_name) - 2, fname,
433           sizeof (pwent->pw_name),
434           (!pwent->pw_name || pwent->pw_name[0] == '\0') ? "unknown"
435           : pwent->pw_name);
436   if ((fd = open (lastlogfile, O_WRONLY | O_CREAT, 0644)) >= 0)
437     {
438       write (fd, &ll, sizeof (ll));
439       close (fd);
440     }
441 #  else
442   if ((fd = open (fname, O_RDWR)) != -1)
443     {
444       if (lseek (fd, (off_t) ((long)pwent->pw_uid * sizeof (ll)),
445                 SEEK_SET) != -1)
446         write (fd, &ll, sizeof (ll));
447       close (fd);
448     }
449 #  endif                        /* LASTLOG_IS_DIR */
450 # endif                         /* HAVE_STRUCT_LASTLOG */
451 }
452 #endif                          /* LASTLOG_SUPPORT */
453 /* ------------------------------------------------------------------------- */
454
455 #endif                          /* UTMP_SUPPORT */