sessreg.c revision 1e5fa1c5
1a6d9b409Smrg/*
2a6d9b409Smrg * Copyright 1990, 1998  The Open Group
3a6d9b409Smrg *
4a6d9b409Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5a6d9b409Smrg * documentation for any purpose is hereby granted without fee, provided that
6a6d9b409Smrg * the above copyright notice appear in all copies and that both that
7a6d9b409Smrg * copyright notice and this permission notice appear in supporting
8a6d9b409Smrg * documentation.
9a6d9b409Smrg *
10a6d9b409Smrg * The above copyright notice and this permission notice shall be included
11a6d9b409Smrg * in all copies or substantial portions of the Software.
12a6d9b409Smrg *
13a6d9b409Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14a6d9b409Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15a6d9b409Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16a6d9b409Smrg * IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
17a6d9b409Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18a6d9b409Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19a6d9b409Smrg * OTHER DEALINGS IN THE SOFTWARE.
20a6d9b409Smrg *
21a6d9b409Smrg * Except as contained in this notice, the name of The Open Group shall
22a6d9b409Smrg * not be used in advertising or otherwise to promote the sale, use or
23a6d9b409Smrg * other dealings in this Software without prior written authorization
24a6d9b409Smrg * from The Open Group.
25a6d9b409Smrg *
26a6d9b409Smrg */
27a6d9b409Smrg
28a6d9b409Smrg/* Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
29a6d9b409Smrg *
30a6d9b409Smrg * Permission is hereby granted, free of charge, to any person obtaining a
311e5fa1c5Smrg * copy of this software and associated documentation files (the "Software"),
321e5fa1c5Smrg * to deal in the Software without restriction, including without limitation
331e5fa1c5Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
341e5fa1c5Smrg * and/or sell copies of the Software, and to permit persons to whom the
351e5fa1c5Smrg * Software is furnished to do so, subject to the following conditions:
361e5fa1c5Smrg *
371e5fa1c5Smrg * The above copyright notice and this permission notice (including the next
381e5fa1c5Smrg * paragraph) shall be included in all copies or substantial portions of the
391e5fa1c5Smrg * Software.
401e5fa1c5Smrg *
411e5fa1c5Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
421e5fa1c5Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
431e5fa1c5Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
441e5fa1c5Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
451e5fa1c5Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
461e5fa1c5Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
471e5fa1c5Smrg * DEALINGS IN THE SOFTWARE.
48a6d9b409Smrg */
49a6d9b409Smrg
50a6d9b409Smrg/*
51a6d9b409Smrg * Author:  Keith Packard, MIT X Consortium
52a6d9b409Smrg * Lastlog support and dynamic utmp entry allocation
53a6d9b409Smrg *   by Andreas Stolcke <stolcke@icsi.berkeley.edu>
54a6d9b409Smrg */
55a6d9b409Smrg
56a6d9b409Smrg/*
57a6d9b409Smrg * sessreg
58a6d9b409Smrg *
59a6d9b409Smrg * simple wtmp/utmp frobber
60a6d9b409Smrg *
61a6d9b409Smrg * usage: sessreg [ -w <wtmp-file> ] [ -u <utmp-file> ]
62a6d9b409Smrg *		  [ -l <line> ]
63efda2da8Smrg *		  [ -L <lastlog-file> ]		      / #ifndef NO_LASTLOG
64a6d9b409Smrg *		  [ -h <host-name> ]				/ BSD only
65a6d9b409Smrg *		  [ -s <slot-number> ] [ -x Xservers-file ]	/ BSD only
66a6d9b409Smrg *		  [ -t <ttys-file> ]				/ BSD only
67a6d9b409Smrg *	          [ -a ] [ -d ] user-name
68a6d9b409Smrg *
69a6d9b409Smrg * one of -a or -d must be specified
70a6d9b409Smrg */
71a6d9b409Smrg
72a6d9b409Smrg#include "sessreg.h"
73a6d9b409Smrg
74a6d9b409Smrg# include	<X11/Xos.h>
75a6d9b409Smrg# include	<X11/Xfuncs.h>
76a6d9b409Smrg# include	<stdio.h>
77a6d9b409Smrg# include	<stdlib.h>
78a6d9b409Smrg
79a6d9b409Smrg#if defined(__SVR4) || defined(SVR4) || defined(linux) || defined(__GLIBC__)
80a6d9b409Smrg# define SYSV
81a6d9b409Smrg#endif
82a6d9b409Smrg
83a6d9b409Smrg#include <time.h>
84a6d9b409Smrg#define Time_t time_t
85a6d9b409Smrg
861e5fa1c5Smrg#ifdef USE_UTMP
871e5fa1c5Smrgstatic void set_utmp (struct utmp *u, char *line, char *user, char *host,
881e5fa1c5Smrg		      Time_t date, int addp);
891e5fa1c5Smrg#endif
90a6d9b409Smrg
91a6d9b409Smrg#ifdef USE_UTMPX
92a6d9b409Smrgstatic void set_utmpx (struct utmpx *u, const char *line, const char *user,
93a6d9b409Smrg		       const char *host, Time_t date, int addp);
94a6d9b409Smrg#endif
95a6d9b409Smrg
96efda2da8Smrgstatic int wflag, uflag, lflag;
97efda2da8Smrgstatic char *wtmp_file, *utmp_file, *line;
98a6d9b409Smrg#ifdef USE_UTMPX
991e5fa1c5Smrg#ifdef HAVE_UPDWTMPX
1001e5fa1c5Smrgstatic char *wtmpx_file = NULL;
1011e5fa1c5Smrg#endif
1021e5fa1c5Smrg#ifdef HAVE_UTMPXNAME
1031e5fa1c5Smrgstatic char *utmpx_file = NULL;
1041e5fa1c5Smrg#endif
105a6d9b409Smrg#endif
106efda2da8Smrgstatic int utmp_none, wtmp_none;
107a6d9b409Smrg/*
108a6d9b409Smrg * BSD specific variables.  To make life much easier for Xstartup/Xreset
109a6d9b409Smrg * maintainers, these arguments are accepted but ignored for sysV
110a6d9b409Smrg */
111efda2da8Smrgstatic int hflag, sflag, xflag, tflag;
112efda2da8Smrgstatic char *host_name = NULL;
1131e5fa1c5Smrg#ifdef USE_UTMP
114efda2da8Smrgstatic int slot_number;
1151e5fa1c5Smrg#endif
116efda2da8Smrgstatic char *xservers_file, *ttys_file;
117efda2da8Smrgstatic char *user_name;
118efda2da8Smrgstatic int aflag, dflag;
119a6d9b409Smrg#ifndef NO_LASTLOG
120efda2da8Smrgstatic char *llog_file;
121efda2da8Smrgstatic int llog_none, Lflag;
122a6d9b409Smrg#endif
123a6d9b409Smrg
124efda2da8Smrgstatic char *program_name;
125a6d9b409Smrg
126a6d9b409Smrg#ifndef SYSV
127a6d9b409Smrgstatic int findslot (char *line_name, char *host_name, int addp, int slot);
128a6d9b409Smrgstatic int Xslot (char *ttys_file, char *servers_file, char *tty_line,
129a6d9b409Smrg		  char *host_name, int addp);
130a6d9b409Smrg#endif
131a6d9b409Smrg
132a6d9b409Smrgstatic int
133a6d9b409Smrgusage (int x)
134a6d9b409Smrg{
135a6d9b409Smrg	if (x) {
136a6d9b409Smrg		fprintf (stderr, "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]", program_name, program_name);
137a6d9b409Smrg#ifndef NO_LASTLOG
138a6d9b409Smrg		fprintf (stderr, " [-L lastlog-file]");
139a6d9b409Smrg#endif
140a6d9b409Smrg		fprintf (stderr, "\n");
141a6d9b409Smrg		fprintf (stderr, "             [-t ttys-file] [-l line-name] [-h host-name]\n");
142a6d9b409Smrg		fprintf (stderr, "             [-s slot-number] [-x servers-file] user-name\n");
143a6d9b409Smrg		exit (1);
144a6d9b409Smrg	}
145a6d9b409Smrg	return x;
146a6d9b409Smrg}
147a6d9b409Smrg
148a6d9b409Smrgstatic char *
149a6d9b409Smrggetstring (char ***avp, int *flagp)
150a6d9b409Smrg{
151a6d9b409Smrg	char	**a = *avp;
152a6d9b409Smrg
153a6d9b409Smrg	usage ((*flagp)++);
154a6d9b409Smrg	if (*++*a)
155a6d9b409Smrg		return *a;
156a6d9b409Smrg	++a;
157a6d9b409Smrg	usage (!*a);
158a6d9b409Smrg	*avp = a;
159a6d9b409Smrg	return *a;
160a6d9b409Smrg}
161a6d9b409Smrg
162a6d9b409Smrg#ifndef SYSV
163a6d9b409Smrgstatic int
164a6d9b409Smrgsyserr (int x, const char *s)
165a6d9b409Smrg{
166a6d9b409Smrg	if (x == -1) {
167a6d9b409Smrg		perror (s);
168a6d9b409Smrg		exit (1);
169a6d9b409Smrg	}
170a6d9b409Smrg	return x;
171a6d9b409Smrg}
172a6d9b409Smrg#endif
173a6d9b409Smrg
174a6d9b409Smrgstatic int
175a6d9b409Smrgsysnerr (int x, const char *s)
176a6d9b409Smrg{
177a6d9b409Smrg	if (x == 0) {
178a6d9b409Smrg		perror (s);
179a6d9b409Smrg		exit (1);
180a6d9b409Smrg	}
181a6d9b409Smrg	return x;
182a6d9b409Smrg}
183a6d9b409Smrg
184a6d9b409Smrgint
185a6d9b409Smrgmain (int argc, char **argv)
186a6d9b409Smrg{
1871e5fa1c5Smrg#if defined(USE_UTMP) && !defined(SYSV)
188a6d9b409Smrg	int		utmp;
189a6d9b409Smrg#endif
190a6d9b409Smrg	char		*line_tmp;
191a6d9b409Smrg#ifndef USE_UTMPX
192a6d9b409Smrg	int		wtmp;
193a6d9b409Smrg#endif
194a6d9b409Smrg	Time_t		current_time;
1951e5fa1c5Smrg#ifdef USE_UTMP
196a6d9b409Smrg	struct utmp	utmp_entry;
1971e5fa1c5Smrg#endif
198a6d9b409Smrg#ifdef USE_UTMPX
199a6d9b409Smrg	struct utmpx	utmpx_entry;
200a6d9b409Smrg#endif
201a6d9b409Smrg
202a6d9b409Smrg	program_name = argv[0];
203a6d9b409Smrg	while (*++argv && **argv == '-') {
204a6d9b409Smrg		switch (*++*argv) {
205a6d9b409Smrg		case 'w':
206a6d9b409Smrg			wtmp_file = getstring (&argv, &wflag);
207a6d9b409Smrg			if (!strcmp (wtmp_file, "none"))
208a6d9b409Smrg				wtmp_none = 1;
209a6d9b409Smrg			break;
210a6d9b409Smrg		case 'u':
211a6d9b409Smrg			utmp_file = getstring (&argv, &uflag);
212a6d9b409Smrg			if (!strcmp (utmp_file, "none"))
213a6d9b409Smrg				utmp_none = 1;
214a6d9b409Smrg			break;
215a6d9b409Smrg#ifndef NO_LASTLOG
216a6d9b409Smrg		case 'L':
217a6d9b409Smrg			llog_file = getstring (&argv, &Lflag);
218a6d9b409Smrg			if (!strcmp (llog_file, "none"))
219a6d9b409Smrg				llog_none = 1;
220a6d9b409Smrg			break;
221a6d9b409Smrg#endif
222a6d9b409Smrg		case 't':
223a6d9b409Smrg			ttys_file = getstring (&argv, &tflag);
224a6d9b409Smrg			break;
225a6d9b409Smrg		case 'l':
226a6d9b409Smrg			line = getstring (&argv, &lflag);
227a6d9b409Smrg			break;
228a6d9b409Smrg		case 'h':
229a6d9b409Smrg			host_name = getstring (&argv, &hflag);
230a6d9b409Smrg			break;
231a6d9b409Smrg		case 's':
2321e5fa1c5Smrg#ifdef USE_UTMP
233a6d9b409Smrg			slot_number = atoi (getstring (&argv, &sflag));
2341e5fa1c5Smrg#endif
235a6d9b409Smrg			break;
236a6d9b409Smrg		case 'x':
237a6d9b409Smrg			xservers_file = getstring (&argv, &xflag);
238a6d9b409Smrg			break;
239a6d9b409Smrg		case 'a':
240a6d9b409Smrg			aflag++;
241a6d9b409Smrg			break;
242a6d9b409Smrg		case 'd':
243a6d9b409Smrg			dflag++;
244a6d9b409Smrg			break;
245a6d9b409Smrg		default:
246a6d9b409Smrg			usage (1);
247a6d9b409Smrg		}
248a6d9b409Smrg	}
249a6d9b409Smrg	usage (!(user_name = *argv++));
250efda2da8Smrg	usage (*argv != NULL);
251a6d9b409Smrg	/*
252a6d9b409Smrg	 * complain if neither aflag nor dflag are set,
253a6d9b409Smrg	 * or if both are set.
254a6d9b409Smrg	 */
255a6d9b409Smrg	usage (!(aflag ^ dflag));
256a6d9b409Smrg	usage (xflag && !lflag);
257a6d9b409Smrg	/* set up default file names */
258a6d9b409Smrg	if (!wflag) {
259a6d9b409Smrg		wtmp_file = WTMP_FILE;
2601e5fa1c5Smrg#if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX)
261a6d9b409Smrg		wtmpx_file = WTMPX_FILE;
262a6d9b409Smrg#endif
263a6d9b409Smrg	}
264a6d9b409Smrg#ifndef NO_UTMP
265a6d9b409Smrg	if (!uflag) {
266a6d9b409Smrg		utmp_file = UTMP_FILE;
2671e5fa1c5Smrg#if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME)
268a6d9b409Smrg		utmpx_file = UTMPX_FILE;
269a6d9b409Smrg#endif
270a6d9b409Smrg	}
271a6d9b409Smrg#else
272a6d9b409Smrg	utmp_none = 1;
273a6d9b409Smrg#endif
274a6d9b409Smrg#ifndef NO_LASTLOG
275a6d9b409Smrg	if (!Lflag)
276a6d9b409Smrg		llog_file = LLOG_FILE;
277a6d9b409Smrg#endif
2781e5fa1c5Smrg#if defined(USE_UTMP) && !defined(SYSV) && !defined(linux) && !defined(__QNX__)
279a6d9b409Smrg	if (!tflag)
280a6d9b409Smrg		ttys_file = TTYS_FILE;
281a6d9b409Smrg	if (!sflag && !utmp_none) {
282a6d9b409Smrg		if (xflag)
283a6d9b409Smrg			sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot");
284a6d9b409Smrg		else
285a6d9b409Smrg			sysnerr (slot_number = ttyslot (), "ttyslot");
286a6d9b409Smrg	}
287a6d9b409Smrg#endif
288a6d9b409Smrg	if (!lflag) {
289a6d9b409Smrg		sysnerr ((line_tmp = ttyname (0)) != NULL, "ttyname");
290a6d9b409Smrg		line = strrchr(line_tmp, '/');
291a6d9b409Smrg		if (line)
292a6d9b409Smrg			line = line + 1;
293a6d9b409Smrg		else
294a6d9b409Smrg			line = line_tmp;
295a6d9b409Smrg	}
296a6d9b409Smrg	time (&current_time);
2971e5fa1c5Smrg#ifdef USE_UTMP
298a6d9b409Smrg	set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag);
2991e5fa1c5Smrg#endif
300a6d9b409Smrg
301a6d9b409Smrg#ifdef USE_UTMPX
302a6d9b409Smrg	/* need to set utmpxname() before calling set_utmpx() for
303a6d9b409Smrg	   UtmpxIdOpen to work */
3041e5fa1c5Smrg# ifdef HAVE_UTMPXNAME
305a6d9b409Smrg	if (utmpx_file != NULL) {
306a6d9b409Smrg	        utmpxname (utmpx_file);
307a6d9b409Smrg	}
3081e5fa1c5Smrg# endif
309a6d9b409Smrg	set_utmpx (&utmpx_entry, line, user_name,
310a6d9b409Smrg		   host_name, current_time, aflag);
311a6d9b409Smrg#endif
312a6d9b409Smrg
313a6d9b409Smrg	if (!utmp_none) {
314a6d9b409Smrg#ifdef USE_UTMPX
3151e5fa1c5Smrg# ifdef HAVE_UTMPX_NAME
3161e5fa1c5Smrg	    if (utmpx_file != NULL)
3171e5fa1c5Smrg# endif
3181e5fa1c5Smrg	    {
319a6d9b409Smrg		setutxent ();
320a6d9b409Smrg		(void) getutxid (&utmpx_entry);
321a6d9b409Smrg		pututxline (&utmpx_entry);
322a6d9b409Smrg		endutxent ();
323a6d9b409Smrg	    }
324a6d9b409Smrg#endif
3251e5fa1c5Smrg#ifdef USE_UTMP
3261e5fa1c5Smrg# ifdef SYSV
327a6d9b409Smrg		utmpname (utmp_file);
328a6d9b409Smrg		setutent ();
329a6d9b409Smrg		(void) getutid (&utmp_entry);
330a6d9b409Smrg		pututline (&utmp_entry);
331a6d9b409Smrg		endutent ();
3321e5fa1c5Smrg# else
333a6d9b409Smrg		utmp = open (utmp_file, O_RDWR);
334a6d9b409Smrg		if (utmp != -1) {
335a6d9b409Smrg			syserr ((int) lseek (utmp, (long) slot_number * sizeof (struct utmp), 0), "lseek");
336a6d9b409Smrg			sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry))
337a6d9b409Smrg				        == sizeof (utmp_entry), "write utmp entry");
338a6d9b409Smrg			close (utmp);
339a6d9b409Smrg		}
3401e5fa1c5Smrg# endif
3411e5fa1c5Smrg#endif /* USE_UTMP */
342a6d9b409Smrg	}
343a6d9b409Smrg	if (!wtmp_none) {
344a6d9b409Smrg#ifdef USE_UTMPX
3451e5fa1c5Smrg# ifdef HAVE_UPDWTMPX
346a6d9b409Smrg		if (wtmpx_file != NULL) {
347a6d9b409Smrg			updwtmpx(wtmpx_file, &utmpx_entry);
348a6d9b409Smrg		}
3491e5fa1c5Smrg# endif
350a6d9b409Smrg#else
351a6d9b409Smrg		wtmp = open (wtmp_file, O_WRONLY|O_APPEND);
352a6d9b409Smrg		if (wtmp != -1) {
353a6d9b409Smrg			sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry))
354a6d9b409Smrg				        == sizeof (utmp_entry), "write wtmp entry");
355a6d9b409Smrg			close (wtmp);
356a6d9b409Smrg		}
357a6d9b409Smrg#endif
358a6d9b409Smrg	}
359a6d9b409Smrg#ifndef NO_LASTLOG
360a6d9b409Smrg	if (aflag && !llog_none) {
361a6d9b409Smrg	        int llog;
362a6d9b409Smrg	        struct passwd *pwd = getpwnam(user_name);
363a6d9b409Smrg
364a6d9b409Smrg	        sysnerr( pwd != NULL, "get user id");
365a6d9b409Smrg	        llog = open (llog_file, O_RDWR);
366a6d9b409Smrg
367a6d9b409Smrg		if (llog != -1) {
368a6d9b409Smrg			struct lastlog ll;
369a6d9b409Smrg
370a6d9b409Smrg			sysnerr (lseek(llog, (long) pwd->pw_uid*sizeof(ll), 0)
371a6d9b409Smrg				        != -1, "seeking lastlog entry");
372a6d9b409Smrg			bzero((char *)&ll, sizeof(ll));
373a6d9b409Smrg			ll.ll_time = current_time;
374a6d9b409Smrg			if (line)
375a6d9b409Smrg			 (void) strncpy (ll.ll_line, line, sizeof (ll.ll_line));
376a6d9b409Smrg			if (host_name)
377a6d9b409Smrg			 (void) strncpy (ll.ll_host, host_name, sizeof (ll.ll_host));
378a6d9b409Smrg
379a6d9b409Smrg			sysnerr (write (llog, (char *) &ll, sizeof (ll))
380a6d9b409Smrg				        == sizeof (ll), "write lastlog entry");
381a6d9b409Smrg			close (llog);
382a6d9b409Smrg		}
383a6d9b409Smrg	}
384a6d9b409Smrg#endif
385a6d9b409Smrg	return 0;
386a6d9b409Smrg}
387a6d9b409Smrg
388a6d9b409Smrg/*
389a6d9b409Smrg * fill in the appropriate records of the utmp entry
390a6d9b409Smrg */
391a6d9b409Smrg
3921e5fa1c5Smrg#ifdef USE_UTMP
393a6d9b409Smrgstatic void
394a6d9b409Smrgset_utmp (struct utmp *u, char *line, char *user, char *host, Time_t date, int addp)
395a6d9b409Smrg{
396a6d9b409Smrg	bzero (u, sizeof (*u));
397a6d9b409Smrg	if (line)
398a6d9b409Smrg		(void) strncpy (u->ut_line, line, sizeof (u->ut_line));
399a6d9b409Smrg	else
400a6d9b409Smrg		bzero (u->ut_line, sizeof (u->ut_line));
401a6d9b409Smrg	if (addp && user)
402a6d9b409Smrg		(void) strncpy (u->ut_name, user, sizeof (u->ut_name));
403a6d9b409Smrg	else
404a6d9b409Smrg		bzero (u->ut_name, sizeof (u->ut_name));
405a6d9b409Smrg#ifdef SYSV
406a6d9b409Smrg	if (line) {
407a6d9b409Smrg		int	i;
408a6d9b409Smrg		/*
409a6d9b409Smrg		 * this is a bit crufty, but
410a6d9b409Smrg		 * follows the apparent conventions in
411a6d9b409Smrg		 * the ttys file.  ut_id is only 4 bytes
412a6d9b409Smrg		 * long, and the last 4 bytes of the line
413a6d9b409Smrg		 * name are written into it, left justified.
414a6d9b409Smrg		 */
415a6d9b409Smrg		i = strlen (line);
416a6d9b409Smrg		if (i >= sizeof (u->ut_id))
417a6d9b409Smrg			i -= sizeof (u->ut_id);
418a6d9b409Smrg		else
419a6d9b409Smrg			i = 0;
420a6d9b409Smrg		(void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
421a6d9b409Smrg	} else
422a6d9b409Smrg		bzero (u->ut_id, sizeof (u->ut_id));
423a6d9b409Smrg	if (addp) {
424a6d9b409Smrg		u->ut_pid = getppid ();
425a6d9b409Smrg		u->ut_type = USER_PROCESS;
426a6d9b409Smrg	} else {
427a6d9b409Smrg		u->ut_pid = 0;
428a6d9b409Smrg		u->ut_type = DEAD_PROCESS;
429a6d9b409Smrg	}
430a6d9b409Smrg#endif
431a6d9b409Smrg#if (!defined(SYSV) && !defined(__QNX__)) || defined(linux)
432a6d9b409Smrg	if (addp && host)
433a6d9b409Smrg		(void) strncpy (u->ut_host, host, sizeof (u->ut_host));
434a6d9b409Smrg	else
435a6d9b409Smrg		bzero (u->ut_host, sizeof (u->ut_host));
436a6d9b409Smrg#endif
437a6d9b409Smrg	u->ut_time = date;
438a6d9b409Smrg}
4391e5fa1c5Smrg#endif /* USE_UTMP */
440a6d9b409Smrg
441a6d9b409Smrg#ifdef USE_UTMPX
442a6d9b409Smrgstatic int
443a6d9b409SmrgUtmpxIdOpen( char *utmpId )
444a6d9b409Smrg{
445a6d9b409Smrg	struct utmpx *u;	/* pointer to entry in utmp file           */
446a6d9b409Smrg	int    status = 1;	/* return code                             */
4471e5fa1c5Smrg
4481e5fa1c5Smrg	setutxent();
449a6d9b409Smrg
450a6d9b409Smrg	while ( (u = getutxent()) != NULL ) {
451a6d9b409Smrg
452a6d9b409Smrg		if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
453a6d9b409Smrg		     u->ut_type != DEAD_PROCESS ) {
454a6d9b409Smrg
455a6d9b409Smrg			status = 0;
456a6d9b409Smrg			break;
457a6d9b409Smrg		}
458a6d9b409Smrg	}
459a6d9b409Smrg
4601e5fa1c5Smrg	endutxent();
461a6d9b409Smrg	return (status);
462a6d9b409Smrg}
463a6d9b409Smrg
464a6d9b409Smrgstatic void
465a6d9b409Smrgset_utmpx (struct utmpx *u, const char *line, const char *user,
466a6d9b409Smrg	   const char *host, Time_t date, int addp)
467a6d9b409Smrg{
468a6d9b409Smrg	static const char letters[] =
469a6d9b409Smrg	       "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
470a6d9b409Smrg
471a6d9b409Smrg        if (line)
472a6d9b409Smrg	{
473a6d9b409Smrg                if(strcmp(line, ":0") == 0)
474a6d9b409Smrg                        (void) strcpy(u->ut_line, "console");
475a6d9b409Smrg                else
476a6d9b409Smrg                        (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
477a6d9b409Smrg
478a6d9b409Smrg		strncpy(u->ut_host, line, sizeof(u->ut_host));
4791e5fa1c5Smrg#if HAVE_UTMPX_UT_SYSLEN
480a6d9b409Smrg		u->ut_syslen = strlen(line);
4811e5fa1c5Smrg#endif
482a6d9b409Smrg	}
483a6d9b409Smrg        else
484a6d9b409Smrg                bzero (u->ut_line, sizeof (u->ut_line));
485a6d9b409Smrg        if (addp && user)
4861e5fa1c5Smrg                (void) strncpy (u->ut_user, user, sizeof (u->ut_user));
487a6d9b409Smrg        else
4881e5fa1c5Smrg                bzero (u->ut_user, sizeof (u->ut_user));
489a6d9b409Smrg
490a6d9b409Smrg        if (line) {
491a6d9b409Smrg                int     i;
492a6d9b409Smrg                /*
493a6d9b409Smrg                 * this is a bit crufty, but
494a6d9b409Smrg                 * follows the apparent conventions in
495a6d9b409Smrg                 * the ttys file.  ut_id is only 4 bytes
496a6d9b409Smrg                 * long, and the last 4 bytes of the line
497a6d9b409Smrg                 * name are written into it, left justified.
498a6d9b409Smrg                 */
499a6d9b409Smrg                i = strlen (line);
500a6d9b409Smrg                if (i >= sizeof (u->ut_id))
501a6d9b409Smrg                        i -= sizeof (u->ut_id);
502a6d9b409Smrg                else
503a6d9b409Smrg                        i = 0;
504a6d9b409Smrg                (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
505a6d9b409Smrg
506a6d9b409Smrg		/* make sure there is no entry using identical ut_id */
507a6d9b409Smrg		if (!UtmpxIdOpen(u->ut_id) && addp) {
508a6d9b409Smrg                        int limit = sizeof(letters) - 1;
509a6d9b409Smrg                        int t = 0;
510a6d9b409Smrg
511a6d9b409Smrg                        u->ut_id[1] = line[i];
512a6d9b409Smrg                        u->ut_id[2] = line[i+1];
513a6d9b409Smrg                        u->ut_id[3] = line[i+2];
514a6d9b409Smrg                        do {
515a6d9b409Smrg                                u->ut_id[0] = letters[t];
516a6d9b409Smrg                                t++;
517a6d9b409Smrg                        } while (!UtmpxIdOpen(u->ut_id) && (t < limit));
518a6d9b409Smrg                }
519a6d9b409Smrg                if (!addp && strstr(line, ":") != NULL) {
520a6d9b409Smrg                        struct utmpx *tmpu;
521a6d9b409Smrg
522a6d9b409Smrg                        while ( (tmpu = getutxent()) != NULL ) {
523a6d9b409Smrg                                if ( (strcmp(tmpu->ut_host, line) == 0 ) &&
524a6d9b409Smrg                                        tmpu->ut_type != DEAD_PROCESS ) {
525a6d9b409Smrg                                        strncpy(u->ut_id, tmpu->ut_id,
526a6d9b409Smrg						sizeof(u->ut_id));
527a6d9b409Smrg                                        break;
528a6d9b409Smrg                                }
529a6d9b409Smrg                        }
530a6d9b409Smrg                        endutxent();
531a6d9b409Smrg                }
532a6d9b409Smrg        } else
533a6d9b409Smrg                bzero (u->ut_id, sizeof (u->ut_id));
534a6d9b409Smrg
535a6d9b409Smrg        if (addp) {
536a6d9b409Smrg                u->ut_pid = getppid ();
537a6d9b409Smrg                u->ut_type = USER_PROCESS;
538a6d9b409Smrg        } else {
539a6d9b409Smrg                u->ut_pid = 0;
540a6d9b409Smrg                u->ut_type = DEAD_PROCESS;
541a6d9b409Smrg        }
542a6d9b409Smrg	u->ut_tv.tv_sec = date;
543a6d9b409Smrg	u->ut_tv.tv_usec = 0;
544a6d9b409Smrg}
545a6d9b409Smrg#endif /* USE_UTMPX */
546a6d9b409Smrg
5471e5fa1c5Smrg#if defined(USE_UTMP) && !defined(SYSV)
548a6d9b409Smrg/*
549a6d9b409Smrg * compute the slot-number for an X display.  This is computed
550a6d9b409Smrg * by counting the lines in /etc/ttys and adding the line-number
551a6d9b409Smrg * that the display appears on in Xservers.  This is a poor
552a6d9b409Smrg * design, but is limited by the non-existant interface to utmp.
553a6d9b409Smrg * If host_name is non-NULL, assume it contains the display name,
554a6d9b409Smrg * otherwise use the tty_line argument (i.e., the tty name).
555a6d9b409Smrg */
556a6d9b409Smrg
557a6d9b409Smrgstatic int
558a6d9b409SmrgXslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name,
559a6d9b409Smrg       int addp)
560a6d9b409Smrg{
561a6d9b409Smrg	FILE	*ttys, *servers;
562a6d9b409Smrg	int	c;
563a6d9b409Smrg	int	slot = 1;
564a6d9b409Smrg	int	column0 = 1;
565a6d9b409Smrg	char	servers_line[1024];
566a6d9b409Smrg	char	disp_name[512];
567a6d9b409Smrg	int	len;
568a6d9b409Smrg	char	*pos;
569a6d9b409Smrg
570a6d9b409Smrg	/* remove screen number from the display name */
571a6d9b409Smrg	memset(disp_name, 0, sizeof(disp_name));
572a6d9b409Smrg	strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1);
573a6d9b409Smrg	pos = strrchr(disp_name, ':');
574a6d9b409Smrg	if (pos) {
575a6d9b409Smrg	    pos = strchr(pos, '.');
576a6d9b409Smrg	    if (pos)
577a6d9b409Smrg		*pos = '\0';
578a6d9b409Smrg	}
579a6d9b409Smrg	sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file);
580a6d9b409Smrg	while ((c = getc (ttys)) != EOF)
581a6d9b409Smrg		if (c == '\n') {
582a6d9b409Smrg			++slot;
583a6d9b409Smrg			column0 = 1;
584a6d9b409Smrg		} else
585a6d9b409Smrg			column0 = 0;
586a6d9b409Smrg	if (!column0)
587a6d9b409Smrg		++slot;
588a6d9b409Smrg	(void) fclose (ttys);
589a6d9b409Smrg	sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file);
590a6d9b409Smrg
591a6d9b409Smrg	len = strlen (disp_name);
592a6d9b409Smrg	column0 = 1;
593a6d9b409Smrg	while (fgets (servers_line, sizeof (servers_line), servers)) {
594a6d9b409Smrg		if (column0 && *servers_line != '#') {
595a6d9b409Smrg			if (!strncmp (disp_name, servers_line, len) &&
596a6d9b409Smrg			    (servers_line[len] == ' ' ||
597a6d9b409Smrg			     servers_line[len] == '\t'))
598a6d9b409Smrg				return slot;
599a6d9b409Smrg			++slot;
600a6d9b409Smrg		}
601a6d9b409Smrg		if (servers_line[strlen(servers_line)-1] != '\n')
602a6d9b409Smrg			column0 = 0;
603a6d9b409Smrg		else
604a6d9b409Smrg			column0 = 1;
605a6d9b409Smrg	}
606a6d9b409Smrg	/*
607a6d9b409Smrg	 * display not found in Xservers file - allocate utmp entry dinamically
608a6d9b409Smrg	 */
609a6d9b409Smrg	return findslot (tty_line, host_name, addp, slot);
610a6d9b409Smrg}
611a6d9b409Smrg
612a6d9b409Smrg/*
613a6d9b409Smrg * find a free utmp slot for the X display.  This allocates a new entry
614a6d9b409Smrg * past the regular tty entries if necessary, reusing existing entries
615a6d9b409Smrg * (identified by (line,hostname)) if possible.
616a6d9b409Smrg */
617a6d9b409Smrgstatic int
618a6d9b409Smrgfindslot (char *line_name, char *host_name, int addp, int slot)
619a6d9b409Smrg{
620a6d9b409Smrg	int	utmp;
621a6d9b409Smrg	struct	utmp entry;
622a6d9b409Smrg	int	found = 0;
623a6d9b409Smrg	int	freeslot = -1;
624a6d9b409Smrg
625a6d9b409Smrg	syserr(utmp = open (utmp_file, O_RDONLY), "open utmp");
626a6d9b409Smrg
627a6d9b409Smrg	/*
628a6d9b409Smrg	 * first, try to locate a previous entry for this display
629a6d9b409Smrg	 * also record location of a free slots in case we need a new one
630a6d9b409Smrg	 */
631a6d9b409Smrg	syserr ((int) lseek (utmp, (long) slot * sizeof (struct utmp), 0), "lseek");
632a6d9b409Smrg
633a6d9b409Smrg	if (!host_name)
634a6d9b409Smrg		host_name = "";
635a6d9b409Smrg
636a6d9b409Smrg	while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) {
637a6d9b409Smrg		if (strncmp(entry.ut_line, line_name,
638a6d9b409Smrg			sizeof(entry.ut_line)) == 0
639a6d9b409Smrg#ifndef __QNX__
640a6d9b409Smrg                    &&
641a6d9b409Smrg		    strncmp(entry.ut_host, host_name,
642a6d9b409Smrg			sizeof(entry.ut_host)) == 0
643a6d9b409Smrg#endif
644a6d9b409Smrg                   ) {
645a6d9b409Smrg			found = 1;
646a6d9b409Smrg			break;
647a6d9b409Smrg		}
648a6d9b409Smrg		if (freeslot < 0 && *entry.ut_name == '\0')
649a6d9b409Smrg			freeslot = slot;
650a6d9b409Smrg		++slot;
651a6d9b409Smrg	}
652a6d9b409Smrg
653a6d9b409Smrg	close (utmp);
654a6d9b409Smrg
655a6d9b409Smrg	if (found)
656a6d9b409Smrg		return slot;
657a6d9b409Smrg	else if (!addp)
658a6d9b409Smrg		return 0;	/* trying to delete a non-existing entry */
659a6d9b409Smrg	else if (freeslot < 0)
660a6d9b409Smrg		return slot;	/* first slot past current entries */
661a6d9b409Smrg	else
662a6d9b409Smrg		return freeslot;
663a6d9b409Smrg}
664a6d9b409Smrg#endif
665