xref: /minix3/usr.bin/who/utmpentry.c (revision b6d4a4c155b8d689603434c3da8b55571af40e3b)
1*b6d4a4c1SThomas Cort /*	$NetBSD: utmpentry.c,v 1.17 2009/05/01 14:26:10 christos Exp $	*/
2*b6d4a4c1SThomas Cort 
3*b6d4a4c1SThomas Cort /*-
4*b6d4a4c1SThomas Cort  * Copyright (c) 2002 The NetBSD Foundation, Inc.
5*b6d4a4c1SThomas Cort  * All rights reserved.
6*b6d4a4c1SThomas Cort  *
7*b6d4a4c1SThomas Cort  * This code is derived from software contributed to The NetBSD Foundation
8*b6d4a4c1SThomas Cort  * by Christos Zoulas.
9*b6d4a4c1SThomas Cort  *
10*b6d4a4c1SThomas Cort  * Redistribution and use in source and binary forms, with or without
11*b6d4a4c1SThomas Cort  * modification, are permitted provided that the following conditions
12*b6d4a4c1SThomas Cort  * are met:
13*b6d4a4c1SThomas Cort  * 1. Redistributions of source code must retain the above copyright
14*b6d4a4c1SThomas Cort  *    notice, this list of conditions and the following disclaimer.
15*b6d4a4c1SThomas Cort  * 2. Redistributions in binary form must reproduce the above copyright
16*b6d4a4c1SThomas Cort  *    notice, this list of conditions and the following disclaimer in the
17*b6d4a4c1SThomas Cort  *    documentation and/or other materials provided with the distribution.
18*b6d4a4c1SThomas Cort  *
19*b6d4a4c1SThomas Cort  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*b6d4a4c1SThomas Cort  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*b6d4a4c1SThomas Cort  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*b6d4a4c1SThomas Cort  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*b6d4a4c1SThomas Cort  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*b6d4a4c1SThomas Cort  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*b6d4a4c1SThomas Cort  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*b6d4a4c1SThomas Cort  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*b6d4a4c1SThomas Cort  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*b6d4a4c1SThomas Cort  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*b6d4a4c1SThomas Cort  * POSSIBILITY OF SUCH DAMAGE.
30*b6d4a4c1SThomas Cort  */
31*b6d4a4c1SThomas Cort 
32*b6d4a4c1SThomas Cort #include <sys/cdefs.h>
33*b6d4a4c1SThomas Cort #ifndef lint
34*b6d4a4c1SThomas Cort __RCSID("$NetBSD: utmpentry.c,v 1.17 2009/05/01 14:26:10 christos Exp $");
35*b6d4a4c1SThomas Cort #endif
36*b6d4a4c1SThomas Cort 
37*b6d4a4c1SThomas Cort #include <sys/stat.h>
38*b6d4a4c1SThomas Cort 
39*b6d4a4c1SThomas Cort #include <time.h>
40*b6d4a4c1SThomas Cort #include <string.h>
41*b6d4a4c1SThomas Cort #include <err.h>
42*b6d4a4c1SThomas Cort #include <stdlib.h>
43*b6d4a4c1SThomas Cort 
44*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
45*b6d4a4c1SThomas Cort #include <utmp.h>
46*b6d4a4c1SThomas Cort #endif
47*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
48*b6d4a4c1SThomas Cort #include <utmpx.h>
49*b6d4a4c1SThomas Cort #endif
50*b6d4a4c1SThomas Cort 
51*b6d4a4c1SThomas Cort #include "utmpentry.h"
52*b6d4a4c1SThomas Cort 
53*b6d4a4c1SThomas Cort 
54*b6d4a4c1SThomas Cort /* Fail the compile if x is not true, by constructing an illegal type. */
55*b6d4a4c1SThomas Cort #define COMPILE_ASSERT(x) /*LINTED null effect */ \
56*b6d4a4c1SThomas Cort 	((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
57*b6d4a4c1SThomas Cort 
58*b6d4a4c1SThomas Cort 
59*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
60*b6d4a4c1SThomas Cort static void getentry(struct utmpentry *, struct utmp *);
61*b6d4a4c1SThomas Cort static struct timespec utmptime = {0, 0};
62*b6d4a4c1SThomas Cort #endif
63*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
64*b6d4a4c1SThomas Cort static void getentryx(struct utmpentry *, struct utmpx *);
65*b6d4a4c1SThomas Cort static struct timespec utmpxtime = {0, 0};
66*b6d4a4c1SThomas Cort #endif
67*b6d4a4c1SThomas Cort #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
68*b6d4a4c1SThomas Cort static int setup(const char *);
69*b6d4a4c1SThomas Cort static void adjust_size(struct utmpentry *e);
70*b6d4a4c1SThomas Cort #endif
71*b6d4a4c1SThomas Cort 
72*b6d4a4c1SThomas Cort int maxname = 8, maxline = 8, maxhost = 16;
73*b6d4a4c1SThomas Cort int etype = 1 << USER_PROCESS;
74*b6d4a4c1SThomas Cort static int numutmp = 0;
75*b6d4a4c1SThomas Cort static struct utmpentry *ehead;
76*b6d4a4c1SThomas Cort 
77*b6d4a4c1SThomas Cort #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
78*b6d4a4c1SThomas Cort static void
adjust_size(struct utmpentry * e)79*b6d4a4c1SThomas Cort adjust_size(struct utmpentry *e)
80*b6d4a4c1SThomas Cort {
81*b6d4a4c1SThomas Cort 	int max;
82*b6d4a4c1SThomas Cort 
83*b6d4a4c1SThomas Cort 	if ((max = strlen(e->name)) > maxname)
84*b6d4a4c1SThomas Cort 		maxname = max;
85*b6d4a4c1SThomas Cort 	if ((max = strlen(e->line)) > maxline)
86*b6d4a4c1SThomas Cort 		maxline = max;
87*b6d4a4c1SThomas Cort 	if ((max = strlen(e->host)) > maxhost)
88*b6d4a4c1SThomas Cort 		maxhost = max;
89*b6d4a4c1SThomas Cort }
90*b6d4a4c1SThomas Cort 
91*b6d4a4c1SThomas Cort static int
setup(const char * fname)92*b6d4a4c1SThomas Cort setup(const char *fname)
93*b6d4a4c1SThomas Cort {
94*b6d4a4c1SThomas Cort 	int what = 3;
95*b6d4a4c1SThomas Cort 	struct stat st;
96*b6d4a4c1SThomas Cort 	const char *sfname;
97*b6d4a4c1SThomas Cort 
98*b6d4a4c1SThomas Cort 	if (fname == NULL) {
99*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
100*b6d4a4c1SThomas Cort 		setutxent();
101*b6d4a4c1SThomas Cort #endif
102*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
103*b6d4a4c1SThomas Cort 		setutent();
104*b6d4a4c1SThomas Cort #endif
105*b6d4a4c1SThomas Cort 	} else {
106*b6d4a4c1SThomas Cort 		size_t len = strlen(fname);
107*b6d4a4c1SThomas Cort 		if (len == 0)
108*b6d4a4c1SThomas Cort 			errx(1, "Filename cannot be 0 length.");
109*b6d4a4c1SThomas Cort 		what = fname[len - 1] == 'x' ? 1 : 2;
110*b6d4a4c1SThomas Cort 		if (what == 1) {
111*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
112*b6d4a4c1SThomas Cort 			if (utmpxname(fname) == 0)
113*b6d4a4c1SThomas Cort 				warnx("Cannot set utmpx file to `%s'",
114*b6d4a4c1SThomas Cort 				    fname);
115*b6d4a4c1SThomas Cort #else
116*b6d4a4c1SThomas Cort 			warnx("utmpx support not compiled in");
117*b6d4a4c1SThomas Cort #endif
118*b6d4a4c1SThomas Cort 		} else {
119*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
120*b6d4a4c1SThomas Cort 			if (utmpname(fname) == 0)
121*b6d4a4c1SThomas Cort 				warnx("Cannot set utmp file to `%s'",
122*b6d4a4c1SThomas Cort 				    fname);
123*b6d4a4c1SThomas Cort #else
124*b6d4a4c1SThomas Cort 			warnx("utmp support not compiled in");
125*b6d4a4c1SThomas Cort #endif
126*b6d4a4c1SThomas Cort 		}
127*b6d4a4c1SThomas Cort 	}
128*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
129*b6d4a4c1SThomas Cort 	if (what & 1) {
130*b6d4a4c1SThomas Cort 		sfname = fname ? fname : _PATH_UTMPX;
131*b6d4a4c1SThomas Cort 		if (stat(sfname, &st) == -1) {
132*b6d4a4c1SThomas Cort 			warn("Cannot stat `%s'", sfname);
133*b6d4a4c1SThomas Cort 			what &= ~1;
134*b6d4a4c1SThomas Cort 		} else {
135*b6d4a4c1SThomas Cort 			if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
136*b6d4a4c1SThomas Cort 			    utmpxtime = st.st_mtimespec;
137*b6d4a4c1SThomas Cort 			else
138*b6d4a4c1SThomas Cort 			    what &= ~1;
139*b6d4a4c1SThomas Cort 		}
140*b6d4a4c1SThomas Cort 	}
141*b6d4a4c1SThomas Cort #endif
142*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
143*b6d4a4c1SThomas Cort 	if (what & 2) {
144*b6d4a4c1SThomas Cort 		sfname = fname ? fname : _PATH_UTMP;
145*b6d4a4c1SThomas Cort 		if (stat(sfname, &st) == -1) {
146*b6d4a4c1SThomas Cort 			warn("Cannot stat `%s'", sfname);
147*b6d4a4c1SThomas Cort 			what &= ~2;
148*b6d4a4c1SThomas Cort 		} else {
149*b6d4a4c1SThomas Cort 			if (timespeccmp(&st.st_mtimespec, &utmptime, >))
150*b6d4a4c1SThomas Cort 				utmptime = st.st_mtimespec;
151*b6d4a4c1SThomas Cort 			else
152*b6d4a4c1SThomas Cort 				what &= ~2;
153*b6d4a4c1SThomas Cort 		}
154*b6d4a4c1SThomas Cort 	}
155*b6d4a4c1SThomas Cort #endif
156*b6d4a4c1SThomas Cort 	return what;
157*b6d4a4c1SThomas Cort }
158*b6d4a4c1SThomas Cort #endif
159*b6d4a4c1SThomas Cort 
160*b6d4a4c1SThomas Cort void
endutentries(void)161*b6d4a4c1SThomas Cort endutentries(void)
162*b6d4a4c1SThomas Cort {
163*b6d4a4c1SThomas Cort 	struct utmpentry *ep;
164*b6d4a4c1SThomas Cort 
165*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
166*b6d4a4c1SThomas Cort 	timespecclear(&utmptime);
167*b6d4a4c1SThomas Cort #endif
168*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
169*b6d4a4c1SThomas Cort 	timespecclear(&utmpxtime);
170*b6d4a4c1SThomas Cort #endif
171*b6d4a4c1SThomas Cort 	ep = ehead;
172*b6d4a4c1SThomas Cort 	while (ep) {
173*b6d4a4c1SThomas Cort 		struct utmpentry *sep = ep;
174*b6d4a4c1SThomas Cort 		ep = ep->next;
175*b6d4a4c1SThomas Cort 		free(sep);
176*b6d4a4c1SThomas Cort 	}
177*b6d4a4c1SThomas Cort 	ehead = NULL;
178*b6d4a4c1SThomas Cort 	numutmp = 0;
179*b6d4a4c1SThomas Cort }
180*b6d4a4c1SThomas Cort 
181*b6d4a4c1SThomas Cort int
getutentries(const char * fname,struct utmpentry ** epp)182*b6d4a4c1SThomas Cort getutentries(const char *fname, struct utmpentry **epp)
183*b6d4a4c1SThomas Cort {
184*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
185*b6d4a4c1SThomas Cort 	struct utmpx *utx;
186*b6d4a4c1SThomas Cort #endif
187*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
188*b6d4a4c1SThomas Cort 	struct utmp *ut;
189*b6d4a4c1SThomas Cort #endif
190*b6d4a4c1SThomas Cort #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
191*b6d4a4c1SThomas Cort 	struct utmpentry *ep;
192*b6d4a4c1SThomas Cort 	int what = setup(fname);
193*b6d4a4c1SThomas Cort 	struct utmpentry **nextp = &ehead;
194*b6d4a4c1SThomas Cort 	switch (what) {
195*b6d4a4c1SThomas Cort 	case 0:
196*b6d4a4c1SThomas Cort 		/* No updates */
197*b6d4a4c1SThomas Cort 		*epp = ehead;
198*b6d4a4c1SThomas Cort 		return numutmp;
199*b6d4a4c1SThomas Cort 	default:
200*b6d4a4c1SThomas Cort 		/* Need to re-scan */
201*b6d4a4c1SThomas Cort 		ehead = NULL;
202*b6d4a4c1SThomas Cort 		numutmp = 0;
203*b6d4a4c1SThomas Cort 	}
204*b6d4a4c1SThomas Cort #endif
205*b6d4a4c1SThomas Cort 
206*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
207*b6d4a4c1SThomas Cort 	while ((what & 1) && (utx = getutxent()) != NULL) {
208*b6d4a4c1SThomas Cort 		if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
209*b6d4a4c1SThomas Cort 			continue;
210*b6d4a4c1SThomas Cort 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
211*b6d4a4c1SThomas Cort 			warn(NULL);
212*b6d4a4c1SThomas Cort 			return 0;
213*b6d4a4c1SThomas Cort 		}
214*b6d4a4c1SThomas Cort 		getentryx(ep, utx);
215*b6d4a4c1SThomas Cort 		*nextp = ep;
216*b6d4a4c1SThomas Cort 		nextp = &(ep->next);
217*b6d4a4c1SThomas Cort 	}
218*b6d4a4c1SThomas Cort #endif
219*b6d4a4c1SThomas Cort 
220*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
221*b6d4a4c1SThomas Cort 	if ((etype & (1 << USER_PROCESS)) != 0) {
222*b6d4a4c1SThomas Cort 		while ((what & 2) && (ut = getutent()) != NULL) {
223*b6d4a4c1SThomas Cort 			if (fname == NULL && (*ut->ut_name == '\0' ||
224*b6d4a4c1SThomas Cort 			    *ut->ut_line == '\0'))
225*b6d4a4c1SThomas Cort 				continue;
226*b6d4a4c1SThomas Cort 			/* Don't process entries that we have utmpx for */
227*b6d4a4c1SThomas Cort 			for (ep = ehead; ep != NULL; ep = ep->next) {
228*b6d4a4c1SThomas Cort 				if (strncmp(ep->line, ut->ut_line,
229*b6d4a4c1SThomas Cort 				    sizeof(ut->ut_line)) == 0)
230*b6d4a4c1SThomas Cort 					break;
231*b6d4a4c1SThomas Cort 			}
232*b6d4a4c1SThomas Cort 			if (ep != NULL)
233*b6d4a4c1SThomas Cort 				continue;
234*b6d4a4c1SThomas Cort 			if ((ep = calloc(1, sizeof(*ep))) == NULL) {
235*b6d4a4c1SThomas Cort 				warn(NULL);
236*b6d4a4c1SThomas Cort 				return 0;
237*b6d4a4c1SThomas Cort 			}
238*b6d4a4c1SThomas Cort 			getentry(ep, ut);
239*b6d4a4c1SThomas Cort 			*nextp = ep;
240*b6d4a4c1SThomas Cort 			nextp = &(ep->next);
241*b6d4a4c1SThomas Cort 		}
242*b6d4a4c1SThomas Cort 	}
243*b6d4a4c1SThomas Cort #endif
244*b6d4a4c1SThomas Cort 	numutmp = 0;
245*b6d4a4c1SThomas Cort #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
246*b6d4a4c1SThomas Cort 	if (ehead != NULL) {
247*b6d4a4c1SThomas Cort 		struct utmpentry *from = ehead, *save;
248*b6d4a4c1SThomas Cort 
249*b6d4a4c1SThomas Cort 		ehead = NULL;
250*b6d4a4c1SThomas Cort 		while (from != NULL) {
251*b6d4a4c1SThomas Cort 			for (nextp = &ehead;
252*b6d4a4c1SThomas Cort 			    (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
253*b6d4a4c1SThomas Cort 			    nextp = &(*nextp)->next)
254*b6d4a4c1SThomas Cort 				continue;
255*b6d4a4c1SThomas Cort 			save = from;
256*b6d4a4c1SThomas Cort 			from = from->next;
257*b6d4a4c1SThomas Cort 			save->next = *nextp;
258*b6d4a4c1SThomas Cort 			*nextp = save;
259*b6d4a4c1SThomas Cort 			numutmp++;
260*b6d4a4c1SThomas Cort 		}
261*b6d4a4c1SThomas Cort 	}
262*b6d4a4c1SThomas Cort 	*epp = ehead;
263*b6d4a4c1SThomas Cort 	return numutmp;
264*b6d4a4c1SThomas Cort #else
265*b6d4a4c1SThomas Cort 	*epp = NULL;
266*b6d4a4c1SThomas Cort 	return 0;
267*b6d4a4c1SThomas Cort #endif
268*b6d4a4c1SThomas Cort }
269*b6d4a4c1SThomas Cort 
270*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMP
271*b6d4a4c1SThomas Cort static void
getentry(struct utmpentry * e,struct utmp * up)272*b6d4a4c1SThomas Cort getentry(struct utmpentry *e, struct utmp *up)
273*b6d4a4c1SThomas Cort {
274*b6d4a4c1SThomas Cort 	COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
275*b6d4a4c1SThomas Cort 	COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
276*b6d4a4c1SThomas Cort 	COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
277*b6d4a4c1SThomas Cort 
278*b6d4a4c1SThomas Cort 	/*
279*b6d4a4c1SThomas Cort 	 * e has just been calloc'd. We don't need to clear it or
280*b6d4a4c1SThomas Cort 	 * append null-terminators, because its length is strictly
281*b6d4a4c1SThomas Cort 	 * greater than the source string. Use strncpy to _read_
282*b6d4a4c1SThomas Cort 	 * up->ut_* because they may not be terminated. For this
283*b6d4a4c1SThomas Cort 	 * reason we use the size of the _source_ as the length
284*b6d4a4c1SThomas Cort 	 * argument.
285*b6d4a4c1SThomas Cort 	 */
286*b6d4a4c1SThomas Cort 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
287*b6d4a4c1SThomas Cort 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
288*b6d4a4c1SThomas Cort 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
289*b6d4a4c1SThomas Cort 
290*b6d4a4c1SThomas Cort 	e->tv.tv_sec = up->ut_time;
291*b6d4a4c1SThomas Cort 	e->tv.tv_usec = 0;
292*b6d4a4c1SThomas Cort 	e->pid = 0;
293*b6d4a4c1SThomas Cort 	e->term = 0;
294*b6d4a4c1SThomas Cort 	e->exit = 0;
295*b6d4a4c1SThomas Cort 	e->sess = 0;
296*b6d4a4c1SThomas Cort 	e->type = USER_PROCESS;
297*b6d4a4c1SThomas Cort 	adjust_size(e);
298*b6d4a4c1SThomas Cort }
299*b6d4a4c1SThomas Cort #endif
300*b6d4a4c1SThomas Cort 
301*b6d4a4c1SThomas Cort #ifdef SUPPORT_UTMPX
302*b6d4a4c1SThomas Cort static void
getentryx(struct utmpentry * e,struct utmpx * up)303*b6d4a4c1SThomas Cort getentryx(struct utmpentry *e, struct utmpx *up)
304*b6d4a4c1SThomas Cort {
305*b6d4a4c1SThomas Cort 	COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
306*b6d4a4c1SThomas Cort 	COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
307*b6d4a4c1SThomas Cort 	COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
308*b6d4a4c1SThomas Cort 
309*b6d4a4c1SThomas Cort 	/*
310*b6d4a4c1SThomas Cort 	 * e has just been calloc'd. We don't need to clear it or
311*b6d4a4c1SThomas Cort 	 * append null-terminators, because its length is strictly
312*b6d4a4c1SThomas Cort 	 * greater than the source string. Use strncpy to _read_
313*b6d4a4c1SThomas Cort 	 * up->ut_* because they may not be terminated. For this
314*b6d4a4c1SThomas Cort 	 * reason we use the size of the _source_ as the length
315*b6d4a4c1SThomas Cort 	 * argument.
316*b6d4a4c1SThomas Cort 	 */
317*b6d4a4c1SThomas Cort 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
318*b6d4a4c1SThomas Cort 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
319*b6d4a4c1SThomas Cort 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
320*b6d4a4c1SThomas Cort 
321*b6d4a4c1SThomas Cort 	e->tv = up->ut_tv;
322*b6d4a4c1SThomas Cort 	e->pid = up->ut_pid;
323*b6d4a4c1SThomas Cort 	e->term = up->ut_exit.e_termination;
324*b6d4a4c1SThomas Cort 	e->exit = up->ut_exit.e_exit;
325*b6d4a4c1SThomas Cort 	e->sess = up->ut_session;
326*b6d4a4c1SThomas Cort 	e->type = up->ut_type;
327*b6d4a4c1SThomas Cort 	adjust_size(e);
328*b6d4a4c1SThomas Cort }
329*b6d4a4c1SThomas Cort #endif
330