Use accessors for setting adjustment
[vte.git] / gnome-pty-helper / gnome-utmp.c
1 /*
2  * utmp/wtmp file updating
3  *
4  * Authors:
5  *    Miguel de Icaza (miguel@gnu.org).
6  *    Timur I. Bakeyev (timur@gnu.org).
7  *
8  * FIXME: Do we want to register the PID of the process running *under* the
9  * subshell or the PID of the parent process? (we are doing the latter now).
10  *
11  * FIXME: Solaris (utmpx) stuff need to be checked.
12  */
13
14 #include <config.h>
15 #include <sys/types.h>
16 #include <sys/file.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <errno.h>
24
25 #if defined(TIME_WITH_SYS_TIME)
26 #    include <sys/time.h>
27 #include <time.h>
28 #else
29 #  if defined(HAVE_SYS_TIME_H)
30 #    include <sys/time.h>
31 #  else
32 #    include <time.h>
33 #  endif
34 #endif
35
36 #if defined(HAVE_LASTLOG_H)
37 #    include <lastlog.h>
38 #endif
39
40 #if defined(HAVE_PATHS_H)
41 #    include <paths.h>
42 #endif
43
44 #if defined(HAVE_UTMP_H)
45 #    include <utmp.h>
46 #endif
47
48 #if defined(HAVE_UTMPX_H)
49 #    include <utmpx.h>
50 #endif
51
52 #if defined(HAVE_TTYENT_H)
53 #    include <ttyent.h>
54 #endif
55
56 #include "gnome-pty.h"
57 #include "gnome-login-support.h"
58
59
60
61 #if !defined(UTMP_OUTPUT_FILENAME)
62 #    if defined(UTMP_FILE)
63 #        define UTMP_OUTPUT_FILENAME UTMP_FILE
64 #    elif defined(_PATH_UTMP) /* BSD systems */
65 #        define UTMP_OUTPUT_FILENAME _PATH_UTMP
66 #    else
67 #        define UTMP_OUTPUT_FILENAME "/etc/utmp"
68 #    endif
69 #endif
70
71 #if !defined(WTMP_OUTPUT_FILENAME)
72 #    if defined(WTMPX_FILE)
73 #        define WTMP_OUTPUT_FILENAME WTMPX_FILE
74 #    elif defined(_PATH_WTMPX)
75 #        define WTMP_OUTPUT_FILENAME _PATH_WTMPX
76 #    elif defined(WTMPX_FILENAME)
77 #        define WTMP_OUTPUT_FILENAME WTMPX_FILENAME
78 #    elif defined(WTMP_FILE)
79 #        define WTMP_OUTPUT_FILENAME WTMP_FILE
80 #    elif defined(_PATH_WTMP) /* BSD systems */
81 #        define WTMP_OUTPUT_FILENAME _PATH_WTMP
82 #    else
83 #        define WTMP_OUTPUT_FILENAME "/etc/wtmp"
84 #    endif
85 #endif
86
87 #if defined(_PATH_LASTLOG) /* BSD systems */
88 #    define LASTLOG_OUTPUT_FILE _PATH_LASTLOG
89 #else
90 #    define LASTLOG_OUTPUT_FILE "/var/log/lastlog"
91 #endif
92
93 #if defined(HAVE_UPDWTMPX)
94 #include <utmpx.h>
95 #define update_wtmp updwtmpx
96 #elif defined(HAVE_UPDWTMP)
97 #define update_wtmp updwtmp
98 #else /* !HAVE_UPDWTMPX && !HAVE_UPDWTMP */
99 static void
100 update_wtmp (char *file, UTMP *putmp)
101 {
102         int fd, times = 3;
103 #if defined(HAVE_FCNTL)
104         struct flock lck;
105
106         lck.l_whence = SEEK_END;
107         lck.l_len    = 0;
108         lck.l_start  = 0;
109         lck.l_type   = F_WRLCK;
110 #endif
111
112         if ((fd = open (file, O_WRONLY|O_APPEND, 0)) < 0)
113                 return;
114
115 #if defined (HAVE_FCNTL)
116         while (times--)
117           if ((fcntl (fd, F_SETLK, &lck) < 0))
118             {
119               if (errno != EAGAIN && errno != EACCES) {
120                 close (fd);
121                 return;
122               }
123               sleep (1); /*?!*/
124             } else
125               break;
126 #elif defined(HAVE_FLOCK)
127         while (times--)
128           if (flock (fd, LOCK_EX | LOCK_NB) < 0)
129             {
130               if (errno != EWOULDBLOCK)
131                 {
132                   close (fd);
133                   return;
134                 }
135               sleep (1); /*?!*/
136             } else
137               break;
138 #endif /* HAVE_FLOCK */
139
140         lseek (fd, 0, SEEK_END);
141         write (fd, putmp, sizeof(UTMP));
142
143         /* unlock the file */
144 #if defined(HAVE_FCNTL)
145         lck.l_type = F_UNLCK;
146         fcntl (fd, F_SETLK, &lck);
147 #elif defined(HAVE_FLOCK)
148         flock (fd, LOCK_UN);
149 #endif
150         close (fd);
151 }
152 #endif /* !HAVE_GETUTMPX */
153
154
155 #if defined(HAVE_GETUTMPX)
156 static void
157 update_utmp (UTMP *ut)
158 {
159         setutxent();
160         pututxline (ut);
161         endutxent();
162 }
163 #elif defined(HAVE_GETUTENT)
164 static void
165 update_utmp (UTMP *ut)
166 {
167         setutent();
168         pututline (ut);
169         endutent();
170 }
171 #elif defined(HAVE_GETTTYENT)
172 /* This variant is sutable for most BSD */
173 static void
174 update_utmp (UTMP *ut)
175 {
176         struct ttyent *ty;
177         int fd, pos = 0;
178
179         if ((fd = open (UTMP_OUTPUT_FILENAME, O_RDWR|O_CREAT, 0644)) < 0)
180                 return;
181
182         setttyent ();
183         while ((ty = getttyent ()) != NULL)
184         {
185                 ++pos;
186                 if (strncmp (ty->ty_name, ut->ut_line, sizeof (ut->ut_line)) == 0)
187                 {
188                         lseek (fd, (off_t)(pos * sizeof(UTMP)), SEEK_SET);
189                         write(fd, ut, sizeof(UTMP));
190                 }
191         }
192         endttyent ();
193
194         close(fd);
195 }
196 #else
197 #define update_utmp(ut)
198 #endif
199
200 #if !defined(HAVE_LASTLOG)
201 #define update_lastlog(login_name, ut)
202 #else
203 static void
204 update_lastlog(char* login_name, UTMP *ut)
205 {
206     struct passwd *pwd;
207     struct lastlog ll;
208     int fd;
209
210     if ((fd = open(LASTLOG_OUTPUT_FILE, O_WRONLY, 0)) < 0)
211         return;
212
213     if ((pwd=getpwnam(login_name)) == NULL)
214         return;
215
216     memset (&ll, 0, sizeof(ll));
217
218     lseek (fd, (off_t)pwd->pw_uid * sizeof (ll), SEEK_SET);
219
220     time (&ll.ll_time);
221
222     strncpy (ll.ll_line, ut->ut_line, sizeof (ll.ll_line));
223
224 #if defined(HAVE_UT_UT_HOST)
225     if (ut->ut_host)
226         strncpy (ll.ll_host, ut->ut_host, sizeof (ll.ll_host));
227 #endif
228
229     write (fd, (void *)&ll, sizeof (ll));
230     close (fd);
231 }
232 #endif /* HAVE_LASTLOG */
233
234 void
235 write_logout_record (char *login_name, void *data, int utmp, int wtmp)
236 {
237         UTMP put, *ut = data;
238         struct timeval tv;
239
240         memset (&put, 0, sizeof(UTMP));
241
242 #if defined(HAVE_UT_UT_TYPE)
243         put.ut_type = DEAD_PROCESS;
244 #endif
245 #if defined(HAVE_UT_UT_ID)
246         strncpy (put.ut_id, ut->ut_id, sizeof (put.ut_id));
247 #endif
248
249         strncpy (put.ut_line, ut->ut_line, sizeof (put.ut_line));
250
251 #if defined(HAVE_UT_UT_TV)
252         gettimeofday(&tv, NULL);
253         put.ut_tv.tv_sec = tv.tv_sec;
254         put.ut_tv.tv_usec = tv.tv_usec;
255 #elif defined(HAVE_UT_UT_TIME)
256         time (&put.ut_time);
257 #endif
258
259 #if defined(HAVE_UT_UT_NAME)
260         strncpy (put.ut_name, login_name, sizeof (put.ut_name));
261 #elif defined(HAVE_UT_UT_USER)
262         strncpy (put.ut_user, login_name, sizeof (put.ut_user));
263 #endif
264
265         if (utmp)
266                 update_utmp (&put);
267
268         if (wtmp)
269                 update_wtmp (WTMP_OUTPUT_FILENAME, &put);
270
271         free (ut);
272 }
273
274 void *
275 write_login_record (char *login_name, char *display_name,
276                     char *term_name, int utmp, int wtmp, int lastlog)
277 {
278         UTMP *ut;
279         char *pty = term_name;
280         struct timeval tv;
281
282         if ((ut=(UTMP *) malloc (sizeof (UTMP))) == NULL)
283                 return NULL;
284
285         memset (ut, 0, sizeof (UTMP));
286
287 #if defined(HAVE_UT_UT_NAME)
288         strncpy (ut->ut_name, login_name, sizeof (ut->ut_name));
289 #elif defined(HAVE_UT_UT_USER)
290         strncpy (ut->ut_user, login_name, sizeof (ut->ut_user));
291 #endif
292
293         /* This shouldn't happen */
294         if (strncmp (pty, "/dev/", 5) == 0)
295             pty += 5;
296
297 #if defined(HAVE_STRRCHR)
298         {
299                 char *p;
300
301                 if (strncmp (pty, "pts", 3) &&
302                     (p = strrchr (pty, '/')) != NULL)
303                         pty = p + 1;
304         }
305 #endif
306
307 #if defined(HAVE_UT_UT_ID)
308         /* Just a safe-guard */
309         ut->ut_id [0] = '\0';
310
311         /* BSD-like terminal name */
312         if (strncmp (pty, "pts", 3) == 0 ||
313             strncmp (pty, "pty", 3) == 0 ||
314             strncmp (pty, "tty", 3) == 0) {
315                 strncpy (ut->ut_id, pty+3, sizeof (ut->ut_id));
316         } else {
317                 unsigned int num;
318                 char buf[10];
319                 /* Try to get device number and convert it to gnome-terminal # */
320                 if (sscanf (pty, "%*[^0-9a-f]%x", &num) == 1) {
321                         sprintf (buf, "gt%2.2x", num);
322                         strncpy (ut->ut_id, buf, sizeof (ut->ut_id));
323                 }
324         }
325 #endif
326
327         /* For utmpx ut_line should be null terminated */
328         /* We do that for both cases to be sure */
329         strncpy (ut->ut_line, pty, sizeof (ut->ut_line));
330         ut->ut_line[sizeof (ut->ut_line)-1] = '\0';
331
332         /* We want parent's pid, not our own */
333 #if defined(HAVE_UT_UT_PID)
334         ut->ut_pid  = getppid ();
335 #endif
336
337 #if defined(HAVE_UT_UT_TYPE)
338         ut->ut_type = USER_PROCESS;
339 #endif
340         /* If structure has ut_tv it doesn't need ut_time */
341 #if defined(HAVE_UT_UT_TV)
342         gettimeofday(&tv, NULL);
343         ut->ut_tv.tv_sec = tv.tv_sec;
344         ut->ut_tv.tv_usec = tv.tv_usec;
345 #elif defined(HAVE_UT_UT_TIME)
346         time (&ut->ut_time);
347 #endif
348         /* ut_ host supposed to be null terminated or len should */
349         /* be specifid in additional field. We do both :)  */
350 #if defined(HAVE_UT_UT_HOST)
351         strncpy (ut->ut_host, display_name, sizeof (ut->ut_host));
352         ut->ut_host [sizeof (ut->ut_host)-1] = '\0';
353 #    if defined(HAVE_UT_UT_SYSLEN)
354         ut->ut_syslen = strlen (ut->ut_host);
355 #    endif
356 #endif
357         if (utmp)
358                 update_utmp (ut);
359
360         if (wtmp)
361                 update_wtmp (WTMP_OUTPUT_FILENAME, ut);
362
363         if (lastlog)
364                 update_lastlog(login_name, ut);
365
366         return ut;
367 }
368
369 void *
370 update_dbs (int utmp, int wtmp, int lastlog, char *login_name, char *display_name, char *term_name)
371 {
372         return write_login_record (login_name, display_name,
373                                    term_name, utmp, wtmp, lastlog);
374 }