xref: /illumos-gate/usr/src/lib/libc/port/gen/getutx.c (revision 00ae5933)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
210293487cSraf 
227c478bd9Sstevel@tonic-gate /*
23a574db85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
2837337afaSToomas Soome /*	  All Rights Reserved	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate  * The Regents of the University of California
337c478bd9Sstevel@tonic-gate  * All Rights Reserved
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate  * contributors.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * Routines to read and write the /etc/utmpx file. Also contains
437c478bd9Sstevel@tonic-gate  * binary compatibility routines to support the old utmp interfaces
447c478bd9Sstevel@tonic-gate  * on systems with MAXPID <= SHRT_MAX.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477257d1b4Sraf #include "lint.h"
487c478bd9Sstevel@tonic-gate #include <sys/types.h>
497c478bd9Sstevel@tonic-gate #include <stdio.h>
507c478bd9Sstevel@tonic-gate #include <sys/param.h>
517c478bd9Sstevel@tonic-gate #include <sys/stat.h>
527c478bd9Sstevel@tonic-gate #include <utmpx.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <fcntl.h>
557c478bd9Sstevel@tonic-gate #include <string.h>
567c478bd9Sstevel@tonic-gate #include <strings.h>
577c478bd9Sstevel@tonic-gate #include <unistd.h>
587c478bd9Sstevel@tonic-gate #include <ctype.h>
597c478bd9Sstevel@tonic-gate #include <stdlib.h>
607c478bd9Sstevel@tonic-gate #include <sys/wait.h>
61a574db85Sraf #include <pthread.h>
627c478bd9Sstevel@tonic-gate #include <limits.h>
637c478bd9Sstevel@tonic-gate #include <signal.h>
647c478bd9Sstevel@tonic-gate #include <spawn.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	IDLEN		4	/* length of id field in utmp */
677c478bd9Sstevel@tonic-gate #define	SC_WILDC	0xff	/* wild char for utmp ids */
687c478bd9Sstevel@tonic-gate #define	MAXFILE		79	/* Maximum pathname length for "utmpx" file */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	MAXVAL		255		/* max value for an id `character' */
7192ba7109Seschrock #define	IPIPE		"/var/run/initpipe"	/* FIFO to send pids to init */
7292ba7109Seschrock #define	UPIPE		"/var/run/utmppipe"	/* FIFO to send pids to utmpd */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #define	VAR_UTMPX_FILE	"/var/adm/utmpx" /* for sanity check only */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * format of message sent to init
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate typedef struct	pidrec {
827c478bd9Sstevel@tonic-gate 	int	pd_type;	/* command type */
837c478bd9Sstevel@tonic-gate 	pid_t	pd_pid;		/* pid */
847c478bd9Sstevel@tonic-gate } pidrec_t;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * pd_type's
887c478bd9Sstevel@tonic-gate  */
897c478bd9Sstevel@tonic-gate #define	ADDPID 1	/* add a pid to "godchild" list */
907c478bd9Sstevel@tonic-gate #define	REMPID 2	/* remove a pid to "godchild" list */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static void	utmpx_frec2api(const struct futmpx *, struct utmpx *);
937c478bd9Sstevel@tonic-gate static void	utmpx_api2frec(const struct utmpx *, struct futmpx *);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static void	unlockutx(void);
967c478bd9Sstevel@tonic-gate static void	sendpid(int, pid_t);
977c478bd9Sstevel@tonic-gate static void	sendupid(int, pid_t);
987c478bd9Sstevel@tonic-gate static int	idcmp(const char *, const char *);
997c478bd9Sstevel@tonic-gate static int	allocid(char *, unsigned char *);
1007c478bd9Sstevel@tonic-gate static int	lockutx(void);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static struct utmpx *invoke_utmp_update(const struct utmpx *);
1037c478bd9Sstevel@tonic-gate static struct futmpx *getoneutx(off_t *);
1047c478bd9Sstevel@tonic-gate static void	putoneutx(const struct utmpx *, off_t);
1057c478bd9Sstevel@tonic-gate static int	big_pids_in_use(void);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * prototypes for utmp compatibility routines (in getut.c)
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate extern struct utmp *_compat_getutent(void);
1117c478bd9Sstevel@tonic-gate extern struct utmp *_compat_getutid(const struct utmp *);
1127c478bd9Sstevel@tonic-gate extern struct utmp *_compat_getutline(const struct utmp *);
1137c478bd9Sstevel@tonic-gate extern struct utmp *_compat_pututline(const struct utmp *);
1147c478bd9Sstevel@tonic-gate extern void _compat_setutent(void);
1157c478bd9Sstevel@tonic-gate extern void _compat_endutent(void);
1167c478bd9Sstevel@tonic-gate extern void _compat_updwtmp(const char *, struct utmp *);
1177c478bd9Sstevel@tonic-gate extern struct utmp *_compat_makeut(struct utmp *);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static int fd = -1;	/* File descriptor for the utmpx file. */
1207c478bd9Sstevel@tonic-gate static int ut_got_maxpid = 0;	/* Flag set when sysconf(_SC_MAXPID) called */
1217c478bd9Sstevel@tonic-gate static pid_t ut_maxpid = 0;	/* Value of MAXPID from sysconf */
1227c478bd9Sstevel@tonic-gate static int tempfd = -1;  /* To store fd between lockutx() and unlockutx() */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static	FILE	*fp = NULL;	/* Buffered file descriptior for utmpx file */
1257c478bd9Sstevel@tonic-gate static int changed_name = 0;	/* Flag set when not using utmpx file */
1267c478bd9Sstevel@tonic-gate static char utmpxfile[MAXFILE+1] = UTMPX_FILE;	/* Name of the current */
1277c478bd9Sstevel@tonic-gate char _compat_utmpfile[MAXFILE+1];
1287c478bd9Sstevel@tonic-gate static int compat_utmpflag = 0;	/* old compat mode flag */
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static struct futmpx fubuf;	/* Copy of last entry read in. */
1317c478bd9Sstevel@tonic-gate static struct utmpx ubuf;	/* Last entry returned to client */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static struct utmp utmpcompat;	/* Buffer for returning utmp-format data */
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * In the 64-bit world, the utmpx data structure grows because of
1367c478bd9Sstevel@tonic-gate  * the ut_time field (a struct timeval) grows in the middle of it.
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate static void
utmpx_frec2api(const struct futmpx * src,struct utmpx * dst)1397c478bd9Sstevel@tonic-gate utmpx_frec2api(const struct futmpx *src, struct utmpx *dst)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	if (src == NULL)
1427c478bd9Sstevel@tonic-gate 		return;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
1457c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
1467c478bd9Sstevel@tonic-gate 	(void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
1477c478bd9Sstevel@tonic-gate 	dst->ut_pid = src->ut_pid;
1487c478bd9Sstevel@tonic-gate 	dst->ut_type = src->ut_type;
1497c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_termination = src->ut_exit.e_termination;
1507c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_exit = src->ut_exit.e_exit;
1517c478bd9Sstevel@tonic-gate 	dst->ut_tv.tv_sec = (time_t)src->ut_tv.tv_sec;
1527c478bd9Sstevel@tonic-gate 	dst->ut_tv.tv_usec = (suseconds_t)src->ut_tv.tv_usec;
1537c478bd9Sstevel@tonic-gate 	dst->ut_session = src->ut_session;
1547c478bd9Sstevel@tonic-gate 	bzero(dst->pad, sizeof (dst->pad));
1557c478bd9Sstevel@tonic-gate 	dst->ut_syslen = src->ut_syslen;
1567c478bd9Sstevel@tonic-gate 	(void) memcpy(dst->ut_host, src->ut_host, sizeof (dst->ut_host));
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static void
utmpx_api2frec(const struct utmpx * src,struct futmpx * dst)1607c478bd9Sstevel@tonic-gate utmpx_api2frec(const struct utmpx *src, struct futmpx *dst)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	if (src == NULL)
1637c478bd9Sstevel@tonic-gate 		return;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
1667c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
1677c478bd9Sstevel@tonic-gate 	(void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
1687c478bd9Sstevel@tonic-gate 	dst->ut_pid = src->ut_pid;
1697c478bd9Sstevel@tonic-gate 	dst->ut_type = src->ut_type;
1707c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_termination = src->ut_exit.e_termination;
1717c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_exit = src->ut_exit.e_exit;
1727c478bd9Sstevel@tonic-gate 	dst->ut_tv.tv_sec = (time32_t)src->ut_tv.tv_sec;
1737c478bd9Sstevel@tonic-gate 	dst->ut_tv.tv_usec = (int32_t)src->ut_tv.tv_usec;
1747c478bd9Sstevel@tonic-gate 	dst->ut_session = src->ut_session;
1757c478bd9Sstevel@tonic-gate 	bzero(dst->pad, sizeof (dst->pad));
1767c478bd9Sstevel@tonic-gate 	dst->ut_syslen = src->ut_syslen;
1777c478bd9Sstevel@tonic-gate 	(void) memcpy(dst->ut_host, src->ut_host, sizeof (dst->ut_host));
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate  * "getutxent_frec" gets the raw version of the next entry in the utmpx file.
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate static struct futmpx *
getutxent_frec(void)1847c478bd9Sstevel@tonic-gate getutxent_frec(void)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * If the "utmpx" file is not open, attempt to open it for
1887c478bd9Sstevel@tonic-gate 	 * reading.  If there is no file, attempt to create one.  If
1897c478bd9Sstevel@tonic-gate 	 * both attempts fail, return NULL.  If the file exists, but
1907c478bd9Sstevel@tonic-gate 	 * isn't readable and writeable, do not attempt to create.
1917c478bd9Sstevel@tonic-gate 	 */
1927c478bd9Sstevel@tonic-gate 	if (fd < 0) {
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 		if ((fd = open(utmpxfile, O_RDWR|O_CREAT, 0644)) < 0) {
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 			/*
1977c478bd9Sstevel@tonic-gate 			 * If the open failed for permissions, try opening
1987c478bd9Sstevel@tonic-gate 			 * it only for reading.  All "pututxline()" later
1997c478bd9Sstevel@tonic-gate 			 * will fail the writes.
2007c478bd9Sstevel@tonic-gate 			 */
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 			if ((fd = open(utmpxfile, O_RDONLY)) < 0)
2037c478bd9Sstevel@tonic-gate 				return (NULL);
2047c478bd9Sstevel@tonic-gate 
205004388ebScasper 			if ((fp = fopen(utmpxfile, "rF")) == NULL) {
2067c478bd9Sstevel@tonic-gate 				(void) close(fd);
2077c478bd9Sstevel@tonic-gate 				fd = -1;
2087c478bd9Sstevel@tonic-gate 				return (NULL);
2097c478bd9Sstevel@tonic-gate 			}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 		} else {
2127c478bd9Sstevel@tonic-gate 			/*
2137c478bd9Sstevel@tonic-gate 			 * Get the stream pointer
2147c478bd9Sstevel@tonic-gate 			 */
215004388ebScasper 			if ((fp = fopen(utmpxfile, "r+F")) == NULL) {
2167c478bd9Sstevel@tonic-gate 				(void) close(fd);
2177c478bd9Sstevel@tonic-gate 				fd = -1;
2187c478bd9Sstevel@tonic-gate 				return (NULL);
2197c478bd9Sstevel@tonic-gate 			}
2207c478bd9Sstevel@tonic-gate 		}
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/*
2247c478bd9Sstevel@tonic-gate 	 * Try to read in the next entry from the utmpx file.
2257c478bd9Sstevel@tonic-gate 	 */
2267c478bd9Sstevel@tonic-gate 	if (fread(&fubuf, sizeof (fubuf), 1, fp) != 1) {
2277c478bd9Sstevel@tonic-gate 		/*
2287c478bd9Sstevel@tonic-gate 		 * Make sure fubuf is zeroed.
2297c478bd9Sstevel@tonic-gate 		 */
2307c478bd9Sstevel@tonic-gate 		bzero(&fubuf, sizeof (fubuf));
2317c478bd9Sstevel@tonic-gate 		return (NULL);
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	return (&fubuf);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * "big_pids_in_use" determines whether large pid numbers are in use
2397c478bd9Sstevel@tonic-gate  * or not.  If MAXPID won't fit in a signed short, the utmp.ut_pid
2407c478bd9Sstevel@tonic-gate  * field will overflow.
2417c478bd9Sstevel@tonic-gate  *
2427c478bd9Sstevel@tonic-gate  * Returns 0 if small pids are in use, 1 otherwise
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate static int
big_pids_in_use(void)2457c478bd9Sstevel@tonic-gate big_pids_in_use(void)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	if (!ut_got_maxpid) {
2487c478bd9Sstevel@tonic-gate 		ut_got_maxpid++;
2497c478bd9Sstevel@tonic-gate 		ut_maxpid = sysconf(_SC_MAXPID);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 	return (ut_maxpid > SHRT_MAX ? 1 : 0);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * "getutxent" gets the next entry in the utmpx file.
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate struct utmpx *
getutxent(void)2587c478bd9Sstevel@tonic-gate getutxent(void)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	struct futmpx *futxp;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	futxp = getutxent_frec();
2637c478bd9Sstevel@tonic-gate 	utmpx_frec2api(&fubuf, &ubuf);
2647c478bd9Sstevel@tonic-gate 	if (futxp == NULL)
2657c478bd9Sstevel@tonic-gate 		return (NULL);
2667c478bd9Sstevel@tonic-gate 	return (&ubuf);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate  * "getutent" gets the next entry in the utmp file.
2707c478bd9Sstevel@tonic-gate  */
2717c478bd9Sstevel@tonic-gate struct utmp *
getutent(void)2727c478bd9Sstevel@tonic-gate getutent(void)
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (compat_utmpflag)
2777c478bd9Sstevel@tonic-gate 		return (_compat_getutent());
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	/* fail if we can't represent maxpid properly */
2807c478bd9Sstevel@tonic-gate 	if (big_pids_in_use()) {
2817c478bd9Sstevel@tonic-gate 		errno = EOVERFLOW;
2827c478bd9Sstevel@tonic-gate 		return (NULL);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	if ((utmpx = getutxent()) == NULL)
2867c478bd9Sstevel@tonic-gate 		return (NULL);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	getutmp(utmpx, &utmpcompat);
2897c478bd9Sstevel@tonic-gate 	return (&utmpcompat);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * "getutxid" finds the specified entry in the utmpx file.  If
2947c478bd9Sstevel@tonic-gate  * it can't find it, it returns NULL.
2957c478bd9Sstevel@tonic-gate  */
2967c478bd9Sstevel@tonic-gate struct utmpx *
getutxid(const struct utmpx * entry)2977c478bd9Sstevel@tonic-gate getutxid(const struct utmpx *entry)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	short type;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/*
3027c478bd9Sstevel@tonic-gate 	 * From XPG5: "The getutxid() or getutxline() may cache data.
3037c478bd9Sstevel@tonic-gate 	 * For this reason, to use getutxline() to search for multiple
3047c478bd9Sstevel@tonic-gate 	 * occurrences, it is necessary to zero out the static data after
3057c478bd9Sstevel@tonic-gate 	 * each success, or getutxline() could just return a pointer to
3067c478bd9Sstevel@tonic-gate 	 * the same utmpx structure over and over again."
3077c478bd9Sstevel@tonic-gate 	 */
3087c478bd9Sstevel@tonic-gate 	utmpx_api2frec(&ubuf, &fubuf);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * Start looking for entry. Look in our current buffer before
3127c478bd9Sstevel@tonic-gate 	 * reading in new entries.
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 	do {
3157c478bd9Sstevel@tonic-gate 		/*
3167c478bd9Sstevel@tonic-gate 		 * If there is no entry in "fubuf", skip to the read.
3177c478bd9Sstevel@tonic-gate 		 */
3187c478bd9Sstevel@tonic-gate 		if (fubuf.ut_type != EMPTY) {
3197c478bd9Sstevel@tonic-gate 			switch (entry->ut_type) {
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 			/*
3227c478bd9Sstevel@tonic-gate 			 * Do not look for an entry if the user sent
3237c478bd9Sstevel@tonic-gate 			 * us an EMPTY entry.
3247c478bd9Sstevel@tonic-gate 			 */
3257c478bd9Sstevel@tonic-gate 			case EMPTY:
3267c478bd9Sstevel@tonic-gate 				return (NULL);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 			/*
3297c478bd9Sstevel@tonic-gate 			 * For RUN_LVL, BOOT_TIME, OLD_TIME, and NEW_TIME
3307c478bd9Sstevel@tonic-gate 			 * entries, only the types have to match.  If they do,
3317c478bd9Sstevel@tonic-gate 			 * return the address of internal buffer.
3327c478bd9Sstevel@tonic-gate 			 */
3337c478bd9Sstevel@tonic-gate 			case RUN_LVL:
3347c478bd9Sstevel@tonic-gate 			case BOOT_TIME:
3357c478bd9Sstevel@tonic-gate 			case DOWN_TIME:
3367c478bd9Sstevel@tonic-gate 			case OLD_TIME:
3377c478bd9Sstevel@tonic-gate 			case NEW_TIME:
3387c478bd9Sstevel@tonic-gate 				if (entry->ut_type == fubuf.ut_type) {
3397c478bd9Sstevel@tonic-gate 					utmpx_frec2api(&fubuf, &ubuf);
3407c478bd9Sstevel@tonic-gate 					return (&ubuf);
3417c478bd9Sstevel@tonic-gate 				}
3427c478bd9Sstevel@tonic-gate 				break;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 			/*
3457c478bd9Sstevel@tonic-gate 			 * For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS,
3467c478bd9Sstevel@tonic-gate 			 * and DEAD_PROCESS the type of the entry in "fubuf",
3477c478bd9Sstevel@tonic-gate 			 * must be one of the above and id's must match.
3487c478bd9Sstevel@tonic-gate 			 */
3497c478bd9Sstevel@tonic-gate 			case INIT_PROCESS:
3507c478bd9Sstevel@tonic-gate 			case LOGIN_PROCESS:
3517c478bd9Sstevel@tonic-gate 			case USER_PROCESS:
3527c478bd9Sstevel@tonic-gate 			case DEAD_PROCESS:
3537c478bd9Sstevel@tonic-gate 				if (((type = fubuf.ut_type) == INIT_PROCESS ||
3547c478bd9Sstevel@tonic-gate 				    type == LOGIN_PROCESS ||
3557c478bd9Sstevel@tonic-gate 				    type == USER_PROCESS ||
3567c478bd9Sstevel@tonic-gate 				    type == DEAD_PROCESS) &&
3577c478bd9Sstevel@tonic-gate 				    (fubuf.ut_id[0] == entry->ut_id[0]) &&
3587c478bd9Sstevel@tonic-gate 				    (fubuf.ut_id[1] == entry->ut_id[1]) &&
3597c478bd9Sstevel@tonic-gate 				    (fubuf.ut_id[2] == entry->ut_id[2]) &&
3607c478bd9Sstevel@tonic-gate 				    (fubuf.ut_id[3] == entry->ut_id[3])) {
3617c478bd9Sstevel@tonic-gate 					utmpx_frec2api(&fubuf, &ubuf);
3627c478bd9Sstevel@tonic-gate 					return (&ubuf);
3637c478bd9Sstevel@tonic-gate 				}
3647c478bd9Sstevel@tonic-gate 				break;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 			/*
3677c478bd9Sstevel@tonic-gate 			 * Do not search for illegal types of entry.
3687c478bd9Sstevel@tonic-gate 			 */
3697c478bd9Sstevel@tonic-gate 			default:
3707c478bd9Sstevel@tonic-gate 				return (NULL);
3717c478bd9Sstevel@tonic-gate 			}
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 	} while (getutxent_frec() != NULL);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	/*
3767c478bd9Sstevel@tonic-gate 	 * Return NULL since the proper entry wasn't found.
3777c478bd9Sstevel@tonic-gate 	 */
3787c478bd9Sstevel@tonic-gate 	utmpx_frec2api(&fubuf, &ubuf);
3797c478bd9Sstevel@tonic-gate 	return (NULL);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * "getutid" finds the specified entry in the utmp file.  If
3847c478bd9Sstevel@tonic-gate  * it can't find it, it returns NULL.
3857c478bd9Sstevel@tonic-gate  */
3867c478bd9Sstevel@tonic-gate struct utmp *
getutid(const struct utmp * entry)3877c478bd9Sstevel@tonic-gate getutid(const struct utmp *entry)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
3907c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx2;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	if (compat_utmpflag)
3937c478bd9Sstevel@tonic-gate 		return (_compat_getutid(entry));
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* fail if we can't represent maxpid properly */
3967c478bd9Sstevel@tonic-gate 	if (big_pids_in_use()) {
3977c478bd9Sstevel@tonic-gate 		errno = EOVERFLOW;
3987c478bd9Sstevel@tonic-gate 		return (NULL);
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 	getutmpx(entry, &utmpx);
4017c478bd9Sstevel@tonic-gate 	if ((utmpx2 = getutxid(&utmpx)) == NULL)
4027c478bd9Sstevel@tonic-gate 		return (NULL);
4037c478bd9Sstevel@tonic-gate 	getutmp(utmpx2, &utmpcompat);
4047c478bd9Sstevel@tonic-gate 	return (&utmpcompat);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * "getutxline" searches the "utmpx" file for a LOGIN_PROCESS or
4097c478bd9Sstevel@tonic-gate  * USER_PROCESS with the same "line" as the specified "entry".
4107c478bd9Sstevel@tonic-gate  */
4117c478bd9Sstevel@tonic-gate struct utmpx *
getutxline(const struct utmpx * entry)4127c478bd9Sstevel@tonic-gate getutxline(const struct utmpx *entry)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	/*
4157c478bd9Sstevel@tonic-gate 	 * From XPG5: "The getutxid() or getutxline() may cache data.
4167c478bd9Sstevel@tonic-gate 	 * For this reason, to use getutxline() to search for multiple
4177c478bd9Sstevel@tonic-gate 	 * occurrences, it is necessary to zero out the static data after
4187c478bd9Sstevel@tonic-gate 	 * each success, or getutxline() could just return a pointer to
4197c478bd9Sstevel@tonic-gate 	 * the same utmpx structure over and over again."
4207c478bd9Sstevel@tonic-gate 	 */
4217c478bd9Sstevel@tonic-gate 	utmpx_api2frec(&ubuf, &fubuf);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	do {
4247c478bd9Sstevel@tonic-gate 		/*
4257c478bd9Sstevel@tonic-gate 		 * If the current entry is the one we are interested in,
4267c478bd9Sstevel@tonic-gate 		 * return a pointer to it.
4277c478bd9Sstevel@tonic-gate 		 */
4287c478bd9Sstevel@tonic-gate 		if (fubuf.ut_type != EMPTY &&
4297c478bd9Sstevel@tonic-gate 		    (fubuf.ut_type == LOGIN_PROCESS ||
4307c478bd9Sstevel@tonic-gate 		    fubuf.ut_type == USER_PROCESS) &&
4317c478bd9Sstevel@tonic-gate 		    strncmp(&entry->ut_line[0], &fubuf.ut_line[0],
4327c478bd9Sstevel@tonic-gate 		    sizeof (fubuf.ut_line)) == 0) {
4337c478bd9Sstevel@tonic-gate 			utmpx_frec2api(&fubuf, &ubuf);
4347c478bd9Sstevel@tonic-gate 			return (&ubuf);
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 	} while (getutxent_frec() != NULL);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	/*
4397c478bd9Sstevel@tonic-gate 	 * Since entry wasn't found, return NULL.
4407c478bd9Sstevel@tonic-gate 	 */
4417c478bd9Sstevel@tonic-gate 	utmpx_frec2api(&fubuf, &ubuf);
4427c478bd9Sstevel@tonic-gate 	return (NULL);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate  * "getutline" searches the "utmp" file for a LOGIN_PROCESS or
4477c478bd9Sstevel@tonic-gate  * USER_PROCESS with the same "line" as the specified "entry".
4487c478bd9Sstevel@tonic-gate  */
4497c478bd9Sstevel@tonic-gate struct utmp *
getutline(const struct utmp * entry)4507c478bd9Sstevel@tonic-gate getutline(const struct utmp *entry)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
4537c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx2;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	if (compat_utmpflag)
4567c478bd9Sstevel@tonic-gate 		return (_compat_getutline(entry));
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/* fail if we can't represent maxpid properly */
4597c478bd9Sstevel@tonic-gate 	if (big_pids_in_use()) {
4607c478bd9Sstevel@tonic-gate 		errno = EOVERFLOW;
4617c478bd9Sstevel@tonic-gate 		return (NULL);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 	/* call getutxline */
4647c478bd9Sstevel@tonic-gate 	getutmpx(entry, &utmpx);
4657c478bd9Sstevel@tonic-gate 	if ((utmpx2 = getutxline(&utmpx)) == NULL)
4667c478bd9Sstevel@tonic-gate 		return (NULL);
4677c478bd9Sstevel@tonic-gate 	getutmp(utmpx2, &utmpcompat);
4687c478bd9Sstevel@tonic-gate 	return (&utmpcompat);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate /*
4727c478bd9Sstevel@tonic-gate  * invoke_utmp_update
4737c478bd9Sstevel@tonic-gate  *
4747c478bd9Sstevel@tonic-gate  * Invokes the utmp_update program which has the privilege to write
4757c478bd9Sstevel@tonic-gate  * to the /etc/utmp file.
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate 
47837337afaSToomas Soome #define	UTMP_UPDATE	"/usr/lib/utmp_update"
4797c478bd9Sstevel@tonic-gate #define	STRSZ	64	/* Size of char buffer for argument strings */
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate static struct utmpx *
invoke_utmp_update(const struct utmpx * entryx)4827c478bd9Sstevel@tonic-gate invoke_utmp_update(const struct utmpx *entryx)
4837c478bd9Sstevel@tonic-gate {
48459f081edSraf 	extern char **_environ;
4857c478bd9Sstevel@tonic-gate 
486657b1f3dSraf 	posix_spawnattr_t attr;
4877c478bd9Sstevel@tonic-gate 	int status;
488a574db85Sraf 	int cancel_state;
4897c478bd9Sstevel@tonic-gate 	pid_t child;
4907c478bd9Sstevel@tonic-gate 	pid_t w;
4917c478bd9Sstevel@tonic-gate 	int i;
4927c478bd9Sstevel@tonic-gate 	char user[STRSZ], id[STRSZ], line[STRSZ], pid[STRSZ], type[STRSZ],
4937c478bd9Sstevel@tonic-gate 	    term[STRSZ], exit[STRSZ], time[STRSZ], time_usec[STRSZ],
4947c478bd9Sstevel@tonic-gate 	    session_id[STRSZ], syslen[32];
4957c478bd9Sstevel@tonic-gate 	char pad[sizeof (entryx->pad) * 2 + 1];
4967c478bd9Sstevel@tonic-gate 	char host[sizeof (entryx->ut_host) + 1];
4977c478bd9Sstevel@tonic-gate 	struct utmpx *curx = NULL;
4987c478bd9Sstevel@tonic-gate 	char bin2hex[] = "0123456789ABCDEF";
4997c478bd9Sstevel@tonic-gate 	unsigned char *cp;
5007c478bd9Sstevel@tonic-gate 	char *argvec[15];
5017c478bd9Sstevel@tonic-gate 	int error;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/*
5047c478bd9Sstevel@tonic-gate 	 * Convert the utmp struct to strings for command line arguments.
5057c478bd9Sstevel@tonic-gate 	 */
5067c478bd9Sstevel@tonic-gate 	(void) strncpy(user, entryx->ut_user, sizeof (entryx->ut_user));
5077c478bd9Sstevel@tonic-gate 	user[sizeof (entryx->ut_user)] = '\0';
5087c478bd9Sstevel@tonic-gate 	(void) strncpy(id, entryx->ut_id, sizeof (entryx->ut_id));
5097c478bd9Sstevel@tonic-gate 	id[sizeof (entryx->ut_id)] = '\0';
5107c478bd9Sstevel@tonic-gate 	(void) strncpy(line, entryx->ut_line, sizeof (entryx->ut_line));
5117c478bd9Sstevel@tonic-gate 	line[sizeof (entryx->ut_line)] = '\0';
5128793b36bSNick Todd 	(void) sprintf(pid, "%d", (int)entryx->ut_pid);
5137c478bd9Sstevel@tonic-gate 	(void) sprintf(type, "%d", entryx->ut_type);
5147c478bd9Sstevel@tonic-gate 	(void) sprintf(term, "%d", entryx->ut_exit.e_termination);
5157c478bd9Sstevel@tonic-gate 	(void) sprintf(exit, "%d", entryx->ut_exit.e_exit);
5167c478bd9Sstevel@tonic-gate 	(void) sprintf(time, "%ld", entryx->ut_tv.tv_sec);
5177c478bd9Sstevel@tonic-gate 	(void) sprintf(time_usec, "%ld", entryx->ut_tv.tv_usec);
5187c478bd9Sstevel@tonic-gate 	(void) sprintf(session_id, "%d", entryx->ut_session);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	cp = (unsigned char *)entryx->pad;
5217c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (entryx->pad); ++i) {
5227c478bd9Sstevel@tonic-gate 		pad[i << 1] = bin2hex[(cp[i] >> 4) & 0xF];
5237c478bd9Sstevel@tonic-gate 		pad[(i << 1) + 1] = bin2hex[cp[i] & 0xF];
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 	pad[sizeof (pad) - 1] = '\0';
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	(void) sprintf(syslen, "%d", entryx->ut_syslen);
5287c478bd9Sstevel@tonic-gate 	(void) strlcpy(host, entryx->ut_host, sizeof (host));
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	argvec[0] = UTMP_UPDATE;
5317c478bd9Sstevel@tonic-gate 	argvec[1] = user;
5327c478bd9Sstevel@tonic-gate 	argvec[2] = id;
5337c478bd9Sstevel@tonic-gate 	argvec[3] = line;
5347c478bd9Sstevel@tonic-gate 	argvec[4] = pid;
5357c478bd9Sstevel@tonic-gate 	argvec[5] = type;
5367c478bd9Sstevel@tonic-gate 	argvec[6] = term;
5377c478bd9Sstevel@tonic-gate 	argvec[7] = exit;
5387c478bd9Sstevel@tonic-gate 	argvec[8] = time;
5397c478bd9Sstevel@tonic-gate 	argvec[9] = time_usec;
5407c478bd9Sstevel@tonic-gate 	argvec[10] = session_id;
5417c478bd9Sstevel@tonic-gate 	argvec[11] = pad;
5427c478bd9Sstevel@tonic-gate 	argvec[12] = syslen;
5437c478bd9Sstevel@tonic-gate 	argvec[13] = host;
5447c478bd9Sstevel@tonic-gate 	argvec[14] = NULL;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	/*
547657b1f3dSraf 	 * No SIGCHLD, please, and let no one else reap our child.
5487c478bd9Sstevel@tonic-gate 	 */
549657b1f3dSraf 	error = posix_spawnattr_init(&attr);
550657b1f3dSraf 	if (error) {
551657b1f3dSraf 		errno = error;
552657b1f3dSraf 		goto out;
553657b1f3dSraf 	}
554657b1f3dSraf 	error = posix_spawnattr_setflags(&attr,
555657b1f3dSraf 	    POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP);
556657b1f3dSraf 	if (error) {
557657b1f3dSraf 		(void) posix_spawnattr_destroy(&attr);
558657b1f3dSraf 		errno = error;
559657b1f3dSraf 		goto out;
560657b1f3dSraf 	}
56159f081edSraf 	error = posix_spawn(&child, UTMP_UPDATE, NULL, &attr, argvec, _environ);
562657b1f3dSraf 	(void) posix_spawnattr_destroy(&attr);
5637c478bd9Sstevel@tonic-gate 	if (error) {
5647c478bd9Sstevel@tonic-gate 		errno = error;
5657c478bd9Sstevel@tonic-gate 		goto out;
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
568a574db85Sraf 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
5697c478bd9Sstevel@tonic-gate 	do {
5707c478bd9Sstevel@tonic-gate 		w = waitpid(child, &status, 0);
5717c478bd9Sstevel@tonic-gate 	} while (w == -1 && errno == EINTR);
572a574db85Sraf 	(void) pthread_setcancelstate(cancel_state, NULL);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	/*
5757c478bd9Sstevel@tonic-gate 	 * We can get ECHILD if the process is ignoring SIGCLD.
5767c478bd9Sstevel@tonic-gate 	 */
5777c478bd9Sstevel@tonic-gate 	if (!(w == -1 && errno == ECHILD) &&
5787c478bd9Sstevel@tonic-gate 	    (w == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
5797c478bd9Sstevel@tonic-gate 		/*
5807c478bd9Sstevel@tonic-gate 		 * The child encountered an error,
5817c478bd9Sstevel@tonic-gate 		 */
5827c478bd9Sstevel@tonic-gate 		goto out;
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	/*
5867c478bd9Sstevel@tonic-gate 	 * Normal termination.  Return a pointer to the entry we just made.
5877c478bd9Sstevel@tonic-gate 	 */
5887c478bd9Sstevel@tonic-gate 	setutxent();	/* Reset file pointer */
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	while ((curx = getutxent()) != NULL) {
5917c478bd9Sstevel@tonic-gate 		if (curx->ut_type != EMPTY &&
5927c478bd9Sstevel@tonic-gate 		    (curx->ut_type == LOGIN_PROCESS ||
5937c478bd9Sstevel@tonic-gate 		    curx->ut_type == USER_PROCESS ||
5947c478bd9Sstevel@tonic-gate 		    curx->ut_type == DEAD_PROCESS) &&
5957c478bd9Sstevel@tonic-gate 		    strncmp(&entryx->ut_line[0], &curx->ut_line[0],
5967c478bd9Sstevel@tonic-gate 		    sizeof (curx->ut_line)) == 0)
5977c478bd9Sstevel@tonic-gate 			break;
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate out:
6017c478bd9Sstevel@tonic-gate 	return (curx);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate  * "pututxline" writes the structure sent into the utmpx file.
6067c478bd9Sstevel@tonic-gate  * If there is already an entry with the same id, then it is
6077c478bd9Sstevel@tonic-gate  * overwritten, otherwise a new entry is made at the end of the
6087c478bd9Sstevel@tonic-gate  * utmpx file.
6097c478bd9Sstevel@tonic-gate  */
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate struct utmpx *
pututxline(const struct utmpx * entry)6127c478bd9Sstevel@tonic-gate pututxline(const struct utmpx *entry)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	struct utmpx *answer;
6157c478bd9Sstevel@tonic-gate 	int lock = 0;
6167c478bd9Sstevel@tonic-gate 	struct utmpx tmpxbuf;
6177c478bd9Sstevel@tonic-gate 	struct futmpx ftmpxbuf;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/*
6207c478bd9Sstevel@tonic-gate 	 * Copy the user supplied entry into our temporary buffer to
6217c478bd9Sstevel@tonic-gate 	 * avoid the possibility that the user is actually passing us
6227c478bd9Sstevel@tonic-gate 	 * the address of "ubuf".
6237c478bd9Sstevel@tonic-gate 	 */
6247c478bd9Sstevel@tonic-gate 	if (entry == NULL)
6257c478bd9Sstevel@tonic-gate 		return (NULL);
6267c478bd9Sstevel@tonic-gate 
6270293487cSraf 	(void) memcpy(&tmpxbuf, entry, sizeof (tmpxbuf));
6287c478bd9Sstevel@tonic-gate 	utmpx_api2frec(entry, &ftmpxbuf);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (fd < 0) {
6317c478bd9Sstevel@tonic-gate 		(void) getutxent_frec();
6327c478bd9Sstevel@tonic-gate 		if (fd < 0)
6337c478bd9Sstevel@tonic-gate 			return ((struct utmpx *)NULL);
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * If we are not the superuser than we can't write to /etc/utmp,
6387c478bd9Sstevel@tonic-gate 	 * so invoke update_utmp(8) to write the entry for us.
6397c478bd9Sstevel@tonic-gate 	 */
6407c478bd9Sstevel@tonic-gate 	if (changed_name == 0 && geteuid() != 0)
6417c478bd9Sstevel@tonic-gate 		return (invoke_utmp_update(entry));
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/*
6447c478bd9Sstevel@tonic-gate 	 * Find the proper entry in the utmpx file.  Start at the current
6457c478bd9Sstevel@tonic-gate 	 * location.  If it isn't found from here to the end of the
6467c478bd9Sstevel@tonic-gate 	 * file, then reset to the beginning of the file and try again.
6477c478bd9Sstevel@tonic-gate 	 * If it still isn't found, then write a new entry at the end of
6487c478bd9Sstevel@tonic-gate 	 * the file.  (Making sure the location is an integral number of
6497c478bd9Sstevel@tonic-gate 	 * utmp structures into the file incase the file is scribbled.)
6507c478bd9Sstevel@tonic-gate 	 */
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	if (getutxid(&tmpxbuf) == NULL) {
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		setutxent();
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		/*
6577c478bd9Sstevel@tonic-gate 		 * Lock the the entire file from here onwards.
6587c478bd9Sstevel@tonic-gate 		 */
6597c478bd9Sstevel@tonic-gate 		if (getutxid(&tmpxbuf) == NULL) {
6607c478bd9Sstevel@tonic-gate 			lock++;
661e86c3f00SToomas Soome 			if (lockf(fd, F_LOCK, 0) < 0)
6627c478bd9Sstevel@tonic-gate 				return (NULL);
6637c478bd9Sstevel@tonic-gate 			(void) fseek(fp, 0, SEEK_END);
6647c478bd9Sstevel@tonic-gate 		} else
6657c478bd9Sstevel@tonic-gate 			(void) fseek(fp, -(long)sizeof (struct futmpx),
6667c478bd9Sstevel@tonic-gate 			    SEEK_CUR);
6677c478bd9Sstevel@tonic-gate 	} else
6687c478bd9Sstevel@tonic-gate 		(void) fseek(fp, -(long)sizeof (struct futmpx), SEEK_CUR);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/*
6717c478bd9Sstevel@tonic-gate 	 * Write out the user supplied structure.  If the write fails,
6727c478bd9Sstevel@tonic-gate 	 * then the user probably doesn't have permission to write the
6737c478bd9Sstevel@tonic-gate 	 * utmpx file.
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	if (fwrite(&ftmpxbuf, sizeof (ftmpxbuf), 1, fp) != 1) {
6767c478bd9Sstevel@tonic-gate 		answer = (struct utmpx *)NULL;
6777c478bd9Sstevel@tonic-gate 	} else {
6787c478bd9Sstevel@tonic-gate 		/*
6797c478bd9Sstevel@tonic-gate 		 * Save the new user structure into ubuf and fubuf so that
6807c478bd9Sstevel@tonic-gate 		 * it will be up to date in the future.
6817c478bd9Sstevel@tonic-gate 		 */
6827c478bd9Sstevel@tonic-gate 		(void) fflush(fp);
6830293487cSraf 		(void) memcpy(&fubuf, &ftmpxbuf, sizeof (fubuf));
6847c478bd9Sstevel@tonic-gate 		utmpx_frec2api(&fubuf, &ubuf);
6857c478bd9Sstevel@tonic-gate 		answer = &ubuf;
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	if (lock)
6897c478bd9Sstevel@tonic-gate 		(void) lockf(fd, F_ULOCK, 0);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	if (answer != NULL && (tmpxbuf.ut_type == USER_PROCESS ||
6927c478bd9Sstevel@tonic-gate 	    tmpxbuf.ut_type == DEAD_PROCESS))
6937c478bd9Sstevel@tonic-gate 		sendupid(tmpxbuf.ut_type == USER_PROCESS ? ADDPID : REMPID,
6947c478bd9Sstevel@tonic-gate 		    (pid_t)tmpxbuf.ut_pid);
6957c478bd9Sstevel@tonic-gate 	return (answer);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * "pututline" is a wrapper that calls pututxline after converting
6997c478bd9Sstevel@tonic-gate  * the utmp record to a utmpx record.
7007c478bd9Sstevel@tonic-gate  */
7017c478bd9Sstevel@tonic-gate struct utmp *
pututline(const struct utmp * entry)7027c478bd9Sstevel@tonic-gate pututline(const struct utmp *entry)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
7057c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx2;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if (compat_utmpflag)
7087c478bd9Sstevel@tonic-gate 		return (_compat_pututline(entry));
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	getutmpx(entry, &utmpx);
7117c478bd9Sstevel@tonic-gate 	if ((utmpx2 = pututxline(&utmpx)) == NULL)
7127c478bd9Sstevel@tonic-gate 		return (NULL);
7137c478bd9Sstevel@tonic-gate 	getutmp(utmpx2, &utmpcompat);
7147c478bd9Sstevel@tonic-gate 	return (&utmpcompat);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate  * "setutxent" just resets the utmpx file back to the beginning.
7197c478bd9Sstevel@tonic-gate  */
7207c478bd9Sstevel@tonic-gate void
setutxent(void)7217c478bd9Sstevel@tonic-gate setutxent(void)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	if (fd != -1)
7247c478bd9Sstevel@tonic-gate 		(void) lseek(fd, 0L, SEEK_SET);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if (fp != NULL)
7277c478bd9Sstevel@tonic-gate 		(void) fseek(fp, 0L, SEEK_SET);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	/*
7307c478bd9Sstevel@tonic-gate 	 * Zero the stored copy of the last entry read, since we are
7317c478bd9Sstevel@tonic-gate 	 * resetting to the beginning of the file.
7327c478bd9Sstevel@tonic-gate 	 */
7337c478bd9Sstevel@tonic-gate 	bzero(&ubuf, sizeof (ubuf));
7347c478bd9Sstevel@tonic-gate 	bzero(&fubuf, sizeof (fubuf));
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate  * "setutent" is a wrapper that calls setutxent
7397c478bd9Sstevel@tonic-gate  */
7407c478bd9Sstevel@tonic-gate void
setutent(void)7417c478bd9Sstevel@tonic-gate setutent(void)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	if (compat_utmpflag) {
7447c478bd9Sstevel@tonic-gate 		_compat_setutent();
7457c478bd9Sstevel@tonic-gate 		return;
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	setutxent();
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate  * "endutxent" closes the utmpx file.
7537c478bd9Sstevel@tonic-gate  */
7547c478bd9Sstevel@tonic-gate void
endutxent(void)7557c478bd9Sstevel@tonic-gate endutxent(void)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate 	if (fd != -1)
7587c478bd9Sstevel@tonic-gate 		(void) close(fd);
7597c478bd9Sstevel@tonic-gate 	fd = -1;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	if (fp != NULL)
7627c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
7637c478bd9Sstevel@tonic-gate 	fp = NULL;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	bzero(&ubuf, sizeof (ubuf));
7667c478bd9Sstevel@tonic-gate 	bzero(&fubuf, sizeof (fubuf));
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate  * "endutent" is a wrapper that calls endutxent
7717c478bd9Sstevel@tonic-gate  * and clears the utmp compatibility buffer.
7727c478bd9Sstevel@tonic-gate  */
7737c478bd9Sstevel@tonic-gate void
endutent(void)7747c478bd9Sstevel@tonic-gate endutent(void)
7757c478bd9Sstevel@tonic-gate {
7767c478bd9Sstevel@tonic-gate 	if (compat_utmpflag) {
7777c478bd9Sstevel@tonic-gate 		_compat_endutent();
7787c478bd9Sstevel@tonic-gate 		return;
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	endutxent();
7827c478bd9Sstevel@tonic-gate 	bzero(&utmpcompat, sizeof (utmpcompat));
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate  * "utmpxname" allows the user to read a file other than the
7877c478bd9Sstevel@tonic-gate  * normal "utmpx" file.
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate int
utmpxname(const char * newfile)7907c478bd9Sstevel@tonic-gate utmpxname(const char *newfile)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate 	size_t len;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	/*
7957c478bd9Sstevel@tonic-gate 	 * Determine if the new filename will fit.  If not, return 0.
7967c478bd9Sstevel@tonic-gate 	 */
7977c478bd9Sstevel@tonic-gate 	if ((len = strlen(newfile)) > MAXFILE-1)
7987c478bd9Sstevel@tonic-gate 		return (0);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	/*
8017c478bd9Sstevel@tonic-gate 	 * The name of the utmpx file has to end with 'x'
8027c478bd9Sstevel@tonic-gate 	 */
8037c478bd9Sstevel@tonic-gate 	if (newfile[len-1] != 'x')
8047c478bd9Sstevel@tonic-gate 		return (0);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	/*
8077c478bd9Sstevel@tonic-gate 	 * Otherwise copy in the new file name.
8087c478bd9Sstevel@tonic-gate 	 */
8097c478bd9Sstevel@tonic-gate 	else
8107c478bd9Sstevel@tonic-gate 		(void) strcpy(&utmpxfile[0], newfile);
8117c478bd9Sstevel@tonic-gate 	/*
8127c478bd9Sstevel@tonic-gate 	 * Make sure everything is reset to the beginning state.
8137c478bd9Sstevel@tonic-gate 	 */
8147c478bd9Sstevel@tonic-gate 	endutxent();
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	/*
8177c478bd9Sstevel@tonic-gate 	 * If the file is being changed to /etc/utmpx or /var/adm/utmpx then
8187c478bd9Sstevel@tonic-gate 	 * we clear the flag so pututxline invokes utmp_update.  Otherwise
8197c478bd9Sstevel@tonic-gate 	 * we set the flag indicating that they changed to another name.
8207c478bd9Sstevel@tonic-gate 	 */
8217c478bd9Sstevel@tonic-gate 	if (strcmp(utmpxfile, UTMPX_FILE) == 0 ||
8227c478bd9Sstevel@tonic-gate 	    strcmp(utmpxfile, VAR_UTMPX_FILE) == 0)
8237c478bd9Sstevel@tonic-gate 		changed_name = 0;
8247c478bd9Sstevel@tonic-gate 	else
8257c478bd9Sstevel@tonic-gate 		changed_name = 1;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	return (1);
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate /*
8317c478bd9Sstevel@tonic-gate  * "utmpname" allows the user to read a file other than the
8327c478bd9Sstevel@tonic-gate  * normal "utmp" file. If the file specified is "/var/adm/utmp"
8337c478bd9Sstevel@tonic-gate  * or "/var/adm/wtmp", it is translated to the corresponding "utmpx"
8347c478bd9Sstevel@tonic-gate  * format name, and all "utmp" operations become wrapped calls
8357c478bd9Sstevel@tonic-gate  * to the equivalent "utmpx" routines, with data conversions
8367c478bd9Sstevel@tonic-gate  * as appropriate.  In the event the application wishes to read
8377c478bd9Sstevel@tonic-gate  * an actual "old" utmp file (named something other than /var/adm/utmp),
8387c478bd9Sstevel@tonic-gate  * calling this function with that name enables backward compatibility
8397c478bd9Sstevel@tonic-gate  * mode, where we actually call the old utmp routines to operate on
8407c478bd9Sstevel@tonic-gate  * the old file.
8417c478bd9Sstevel@tonic-gate  */
8427c478bd9Sstevel@tonic-gate int
utmpname(const char * newfile)8437c478bd9Sstevel@tonic-gate utmpname(const char *newfile)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 	char name[MAXFILE+1];
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	if (strlen(newfile) > MAXFILE)
8487c478bd9Sstevel@tonic-gate 		return (0);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	if (strcmp(newfile, "/var/adm/utmp") == 0 ||
8517c478bd9Sstevel@tonic-gate 	    strcmp(newfile, "/var/adm/wtmp") == 0) {
8527c478bd9Sstevel@tonic-gate 		(void) strcpy(name, newfile);
8537c478bd9Sstevel@tonic-gate 		(void) strcat(name, "x");
8547c478bd9Sstevel@tonic-gate 		compat_utmpflag = 0;	/* turn off old compat mode */
8557c478bd9Sstevel@tonic-gate 		return (utmpxname(name));
8567c478bd9Sstevel@tonic-gate 	} else {
8577c478bd9Sstevel@tonic-gate 		(void) strcpy(_compat_utmpfile, newfile);
8587c478bd9Sstevel@tonic-gate 		compat_utmpflag = 1;
8597c478bd9Sstevel@tonic-gate 		return (1);
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate /*
8647c478bd9Sstevel@tonic-gate  * Add the record to wtmpx.
8657c478bd9Sstevel@tonic-gate  */
8667c478bd9Sstevel@tonic-gate void
updwtmpx(const char * filex,struct utmpx * utx)8677c478bd9Sstevel@tonic-gate updwtmpx(const char *filex, struct utmpx *utx)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	struct futmpx futx;
8707c478bd9Sstevel@tonic-gate 	int wfdx;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	if ((wfdx = open(filex, O_WRONLY | O_APPEND)) < 0)
8737c478bd9Sstevel@tonic-gate 		return;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	(void) lseek(wfdx, 0, SEEK_END);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	utmpx_api2frec(utx, &futx);
8787c478bd9Sstevel@tonic-gate 	(void) write(wfdx, &futx, sizeof (futx));
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	(void) close(wfdx);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate  * Add record to wtmp (actually wtmpx). If not updating /var/adm/wtmp,
8857c478bd9Sstevel@tonic-gate  * use the old utmp compatibility routine to write a utmp-format
8867c478bd9Sstevel@tonic-gate  * record to the file specified.
8877c478bd9Sstevel@tonic-gate  */
8887c478bd9Sstevel@tonic-gate void
updwtmp(const char * file,struct utmp * ut)8897c478bd9Sstevel@tonic-gate updwtmp(const char *file, struct utmp *ut)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
8927c478bd9Sstevel@tonic-gate 	char xfile[MAXFILE + 1];
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if (strcmp(file, "/var/adm/wtmp") == 0) {
8957c478bd9Sstevel@tonic-gate 		(void) strlcpy(xfile, file, sizeof (xfile) - 1);
8967c478bd9Sstevel@tonic-gate 		(void) strcat(xfile, "x");
8977c478bd9Sstevel@tonic-gate 		getutmpx(ut, &utmpx);
8987c478bd9Sstevel@tonic-gate 		updwtmpx((const char *)&xfile, &utmpx);
8997c478bd9Sstevel@tonic-gate 	} else
9007c478bd9Sstevel@tonic-gate 		_compat_updwtmp(file, ut);
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate /*
9047c478bd9Sstevel@tonic-gate  * modutx - modify a utmpx entry.  Also notify init about new pids or
9057c478bd9Sstevel@tonic-gate  *	old pids that it no longer needs to care about
9067c478bd9Sstevel@tonic-gate  *
9077c478bd9Sstevel@tonic-gate  *	args:	utp- point to utmpx structure to be created
9087c478bd9Sstevel@tonic-gate  */
9097c478bd9Sstevel@tonic-gate struct utmpx *
modutx(const struct utmpx * utp)9107c478bd9Sstevel@tonic-gate modutx(const struct utmpx *utp)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 	int i;
9137c478bd9Sstevel@tonic-gate 	struct utmpx utmp;		/* holding area */
9147c478bd9Sstevel@tonic-gate 	struct utmpx *ucp = &utmp;	/* and a pointer to it */
9157c478bd9Sstevel@tonic-gate 	struct utmpx *up;		/* "current" utmpx entry */
9167c478bd9Sstevel@tonic-gate 	struct futmpx *fup;		/* being examined */
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i) {
9197c478bd9Sstevel@tonic-gate 		if ((unsigned char)utp->ut_id[i] == SC_WILDC)
9207c478bd9Sstevel@tonic-gate 			return (NULL);
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	/*
9247c478bd9Sstevel@tonic-gate 	 * copy the supplied utmpx structure someplace safe
9257c478bd9Sstevel@tonic-gate 	 */
9260293487cSraf 	(void) memcpy(&utmp, utp, sizeof (utmp));
9277c478bd9Sstevel@tonic-gate 	setutxent();
928*00ae5933SToomas Soome 	while ((fup = getutxent_frec()) != NULL) {
9297c478bd9Sstevel@tonic-gate 		if (idcmp(ucp->ut_id, fup->ut_id))
9307c478bd9Sstevel@tonic-gate 			continue;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		/*
9337c478bd9Sstevel@tonic-gate 		 * only get here if ids are the same, i.e. found right entry
9347c478bd9Sstevel@tonic-gate 		 */
9357c478bd9Sstevel@tonic-gate 		if (ucp->ut_pid != fup->ut_pid) {
9367c478bd9Sstevel@tonic-gate 			sendpid(REMPID, (pid_t)fup->ut_pid);
9377c478bd9Sstevel@tonic-gate 			sendpid(ADDPID, (pid_t)ucp->ut_pid);
9387c478bd9Sstevel@tonic-gate 		}
9397c478bd9Sstevel@tonic-gate 		break;
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 	up = pututxline(ucp);
9427c478bd9Sstevel@tonic-gate 	if (ucp->ut_type == DEAD_PROCESS)
9437c478bd9Sstevel@tonic-gate 		sendpid(REMPID, (pid_t)ucp->ut_pid);
9447c478bd9Sstevel@tonic-gate 	if (up)
9457c478bd9Sstevel@tonic-gate 		updwtmpx(WTMPX_FILE, up);
9467c478bd9Sstevel@tonic-gate 	endutxent();
9477c478bd9Sstevel@tonic-gate 	return (up);
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate /*
9517c478bd9Sstevel@tonic-gate  * modut - modify a utmp entry.	 Also notify init about new pids or
9527c478bd9Sstevel@tonic-gate  *	old pids that it no longer needs to care about
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  *	args:	utmp - point to utmp structure to be created
9557c478bd9Sstevel@tonic-gate  */
9567c478bd9Sstevel@tonic-gate struct utmp *
modut(struct utmp * utp)9577c478bd9Sstevel@tonic-gate modut(struct utmp *utp)
9587c478bd9Sstevel@tonic-gate {
9597c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
9607c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx2;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	getutmpx(utp, &utmpx);
9637c478bd9Sstevel@tonic-gate 	if ((utmpx2 = modutx(&utmpx)) == NULL)
9647c478bd9Sstevel@tonic-gate 		return (NULL);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	getutmp(utmpx2, utp);
9677c478bd9Sstevel@tonic-gate 	return (utp);
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate  * idcmp - compare two id strings, return  0 if same, non-zero if not *
9727c478bd9Sstevel@tonic-gate  *	args:	s1 - first id string
9737c478bd9Sstevel@tonic-gate  *		s2 - second id string
9747c478bd9Sstevel@tonic-gate  */
9757c478bd9Sstevel@tonic-gate static int
idcmp(const char * s1,const char * s2)9767c478bd9Sstevel@tonic-gate idcmp(const char *s1, const char *s2)
9777c478bd9Sstevel@tonic-gate {
9787c478bd9Sstevel@tonic-gate 	int i;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i)
9817c478bd9Sstevel@tonic-gate 		if ((unsigned char) *s1 != SC_WILDC && (*s1++ != *s2++))
9827c478bd9Sstevel@tonic-gate 			return (-1);
9837c478bd9Sstevel@tonic-gate 	return (0);
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate /*
9887c478bd9Sstevel@tonic-gate  * allocid - allocate an unused id for utmp, either by recycling a
9897c478bd9Sstevel@tonic-gate  *	DEAD_PROCESS entry or creating a new one.  This routine only
9907c478bd9Sstevel@tonic-gate  *	gets called if a wild card character was specified.
9917c478bd9Sstevel@tonic-gate  *
9927c478bd9Sstevel@tonic-gate  *	args:	srcid - pattern for new id
9937c478bd9Sstevel@tonic-gate  *		saveid - last id matching pattern for a non-dead process
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate static int
allocid(char * srcid,unsigned char * saveid)9967c478bd9Sstevel@tonic-gate allocid(char *srcid, unsigned char *saveid)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	int i;		/* scratch variable */
9997c478bd9Sstevel@tonic-gate 	int changed;		/* flag to indicate that a new id has */
10007c478bd9Sstevel@tonic-gate 				/* been generated */
10017c478bd9Sstevel@tonic-gate 	char copyid[IDLEN];	/* work area */
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	(void) memcpy(copyid, srcid, IDLEN);
10047c478bd9Sstevel@tonic-gate 	changed = 0;
10057c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i) {
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 		/*
10087c478bd9Sstevel@tonic-gate 		 * if this character isn't wild, it'll be part of the
10097c478bd9Sstevel@tonic-gate 		 * generated id
10107c478bd9Sstevel@tonic-gate 		 */
10117c478bd9Sstevel@tonic-gate 		if ((unsigned char) copyid[i] != SC_WILDC)
10127c478bd9Sstevel@tonic-gate 			continue;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 		/*
10157c478bd9Sstevel@tonic-gate 		 * it's a wild character, retrieve the character from the
10167c478bd9Sstevel@tonic-gate 		 * saved id
10177c478bd9Sstevel@tonic-gate 		 */
10187c478bd9Sstevel@tonic-gate 		copyid[i] = saveid[i];
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		/*
10217c478bd9Sstevel@tonic-gate 		 * if we haven't changed anything yet, try to find a new char
10227c478bd9Sstevel@tonic-gate 		 * to use
10237c478bd9Sstevel@tonic-gate 		 */
10247c478bd9Sstevel@tonic-gate 		if (!changed && (saveid[i] < MAXVAL)) {
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		/*
10277c478bd9Sstevel@tonic-gate 		 * Note: this algorithm is taking the "last matched" id
10287c478bd9Sstevel@tonic-gate 		 * and trying to make a 1 character change to it to create
10297c478bd9Sstevel@tonic-gate 		 * a new one.  Rather than special-case the first time
10307c478bd9Sstevel@tonic-gate 		 * (when no perturbation is really necessary), just don't
10317c478bd9Sstevel@tonic-gate 		 * allocate the first valid id.
10327c478bd9Sstevel@tonic-gate 		 */
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 			while (++saveid[i] < MAXVAL) {
10357c478bd9Sstevel@tonic-gate 				/*
10367c478bd9Sstevel@tonic-gate 				 * make sure new char is alphanumeric
10377c478bd9Sstevel@tonic-gate 				 */
10387c478bd9Sstevel@tonic-gate 				if (isalnum(saveid[i])) {
10397c478bd9Sstevel@tonic-gate 					copyid[i] = saveid[i];
10407c478bd9Sstevel@tonic-gate 					changed = 1;
10417c478bd9Sstevel@tonic-gate 					break;
10427c478bd9Sstevel@tonic-gate 				}
10437c478bd9Sstevel@tonic-gate 			}
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 			if (!changed) {
10467c478bd9Sstevel@tonic-gate 				/*
10477c478bd9Sstevel@tonic-gate 				 * Then 'reset' the current count at
10487c478bd9Sstevel@tonic-gate 				 * this position to it's lowest valid
10497c478bd9Sstevel@tonic-gate 				 * value, and propagate the carry to
10507c478bd9Sstevel@tonic-gate 				 * the next wild-card slot
10517c478bd9Sstevel@tonic-gate 				 *
10527c478bd9Sstevel@tonic-gate 				 * See 1113208.
10537c478bd9Sstevel@tonic-gate 				 */
10547c478bd9Sstevel@tonic-gate 				saveid[i] = 0;
10557c478bd9Sstevel@tonic-gate 				while (!isalnum(saveid[i]))
105637337afaSToomas Soome 					saveid[i]++;
10577c478bd9Sstevel@tonic-gate 				copyid[i] = ++saveid[i];
10587c478bd9Sstevel@tonic-gate 			}
10597c478bd9Sstevel@tonic-gate 		}
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 	/*
10627c478bd9Sstevel@tonic-gate 	 * changed is true if we were successful in allocating an id
10637c478bd9Sstevel@tonic-gate 	 */
10647c478bd9Sstevel@tonic-gate 	if (changed) {
10657c478bd9Sstevel@tonic-gate 		(void) memcpy(srcid, copyid, IDLEN);
10667c478bd9Sstevel@tonic-gate 		return (0);
10677c478bd9Sstevel@tonic-gate 	} else {
10687c478bd9Sstevel@tonic-gate 		return (-1);
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate  * lockutx - lock utmpx file
10757c478bd9Sstevel@tonic-gate  */
10767c478bd9Sstevel@tonic-gate static int
lockutx(void)10777c478bd9Sstevel@tonic-gate lockutx(void)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate 	int lockfd;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	if ((lockfd = open(UTMPX_FILE, O_RDWR|O_CREAT, 0644)) < 0)
10827c478bd9Sstevel@tonic-gate 		return (-1);
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	if (lockf(lockfd, F_LOCK, 0) < 0) {
10857c478bd9Sstevel@tonic-gate 		(void) close(lockfd);
10867c478bd9Sstevel@tonic-gate 		return (-1);
10877c478bd9Sstevel@tonic-gate 	}
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	tempfd = fd;
10907c478bd9Sstevel@tonic-gate 	fd = lockfd;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	return (0);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate /*
10997c478bd9Sstevel@tonic-gate  * unlockutx - unlock utmpx file
11007c478bd9Sstevel@tonic-gate  */
11017c478bd9Sstevel@tonic-gate static void
unlockutx(void)11027c478bd9Sstevel@tonic-gate unlockutx(void)
11037c478bd9Sstevel@tonic-gate {
11047c478bd9Sstevel@tonic-gate 	(void) lockf(fd, F_ULOCK, 0);
11057c478bd9Sstevel@tonic-gate 	(void) close(fd);
11067c478bd9Sstevel@tonic-gate 	fd = tempfd;
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate /*
11117c478bd9Sstevel@tonic-gate  * sendpid - send message to init to add or remove a pid from the
11127c478bd9Sstevel@tonic-gate  *	"godchild" list
11137c478bd9Sstevel@tonic-gate  *
11147c478bd9Sstevel@tonic-gate  *	args:	cmd - ADDPID or REMPID
11157c478bd9Sstevel@tonic-gate  *		pid - pid of "godchild"
11167c478bd9Sstevel@tonic-gate  */
11177c478bd9Sstevel@tonic-gate static void
sendpid(int cmd,pid_t pid)11187c478bd9Sstevel@tonic-gate sendpid(int cmd, pid_t pid)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate 	int pfd;		/* file desc. for init pipe */
11217c478bd9Sstevel@tonic-gate 	pidrec_t prec;		/* place for message to be built */
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	/*
11247c478bd9Sstevel@tonic-gate 	 * if for some reason init didn't open initpipe, open it read/write
11257c478bd9Sstevel@tonic-gate 	 * here to avoid sending SIGPIPE to the calling process
11267c478bd9Sstevel@tonic-gate 	 */
11277c478bd9Sstevel@tonic-gate 	pfd = open(IPIPE, O_RDWR);
11287c478bd9Sstevel@tonic-gate 	if (pfd < 0)
11297c478bd9Sstevel@tonic-gate 		return;
11307c478bd9Sstevel@tonic-gate 	prec.pd_pid = pid;
11317c478bd9Sstevel@tonic-gate 	prec.pd_type = cmd;
11327c478bd9Sstevel@tonic-gate 	(void) write(pfd, &prec, sizeof (pidrec_t));
11337c478bd9Sstevel@tonic-gate 	(void) close(pfd);
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate /*
11377c478bd9Sstevel@tonic-gate  * makeutx - create a utmpx entry, recycling an id if a wild card is
11387c478bd9Sstevel@tonic-gate  *	specified.  Also notify init about the new pid
11397c478bd9Sstevel@tonic-gate  *
11407c478bd9Sstevel@tonic-gate  *	args:	utmpx - point to utmpx structure to be created
11417c478bd9Sstevel@tonic-gate  */
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate struct utmpx *
makeutx(const struct utmpx * utmp)11447c478bd9Sstevel@tonic-gate makeutx(const struct utmpx *utmp)
11457c478bd9Sstevel@tonic-gate {
11467c478bd9Sstevel@tonic-gate 	struct utmpx *utp;
11477c478bd9Sstevel@tonic-gate 	struct futmpx *ut;		/* "current" utmpx being examined */
11487c478bd9Sstevel@tonic-gate 	unsigned char saveid[IDLEN];	/* the last id we matched that was */
11497c478bd9Sstevel@tonic-gate 					/* NOT a dead proc */
11507c478bd9Sstevel@tonic-gate 	int falphanum = 0x30;		/* first alpha num char */
11517c478bd9Sstevel@tonic-gate 	off_t offset;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	/*
11547c478bd9Sstevel@tonic-gate 	 * Are any wild card char's present in the idlen string?
11557c478bd9Sstevel@tonic-gate 	 */
11567c478bd9Sstevel@tonic-gate 	if (memchr(utmp->ut_id, SC_WILDC, IDLEN) != NULL) {
11577c478bd9Sstevel@tonic-gate 		/*
11587c478bd9Sstevel@tonic-gate 		 * try to lock the utmpx file, only needed if
11597c478bd9Sstevel@tonic-gate 		 * we're doing wildcard matching
11607c478bd9Sstevel@tonic-gate 		 */
11617c478bd9Sstevel@tonic-gate 		if (lockutx())
11627c478bd9Sstevel@tonic-gate 			return (NULL);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		/*
11657c478bd9Sstevel@tonic-gate 		 * used in allocid
11667c478bd9Sstevel@tonic-gate 		 */
11677c478bd9Sstevel@tonic-gate 		(void) memset(saveid, falphanum, IDLEN);
11687c478bd9Sstevel@tonic-gate 
1169*00ae5933SToomas Soome 		while ((ut = getoneutx(&offset)) != NULL)
11707c478bd9Sstevel@tonic-gate 			if (idcmp(utmp->ut_id, ut->ut_id)) {
11717c478bd9Sstevel@tonic-gate 				continue;
11727c478bd9Sstevel@tonic-gate 			} else {
11737c478bd9Sstevel@tonic-gate 				/*
11747c478bd9Sstevel@tonic-gate 				 * Found a match. We are done if this is
11757c478bd9Sstevel@tonic-gate 				 * a free slot. Else record this id. We
11767c478bd9Sstevel@tonic-gate 				 * will need it to generate the next new id.
11777c478bd9Sstevel@tonic-gate 				 */
11787c478bd9Sstevel@tonic-gate 				if (ut->ut_type == DEAD_PROCESS)
11797c478bd9Sstevel@tonic-gate 					break;
11807c478bd9Sstevel@tonic-gate 				else
11817c478bd9Sstevel@tonic-gate 					(void) memcpy(saveid, ut->ut_id,
11827c478bd9Sstevel@tonic-gate 					    IDLEN);
11837c478bd9Sstevel@tonic-gate 			}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 		if (ut) {
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 			/*
11887c478bd9Sstevel@tonic-gate 			 * Unused entry, reuse it. We know the offset. So
11897c478bd9Sstevel@tonic-gate 			 * just go to that offset  utmpx and write it out.
11907c478bd9Sstevel@tonic-gate 			 */
11917c478bd9Sstevel@tonic-gate 			(void) memcpy((caddr_t)utmp->ut_id, ut->ut_id, IDLEN);
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 			putoneutx(utmp, offset);
11947c478bd9Sstevel@tonic-gate 			updwtmpx(WTMPX_FILE, (struct utmpx *)utmp);
11957c478bd9Sstevel@tonic-gate 			unlockutx();
11967c478bd9Sstevel@tonic-gate 			sendpid(ADDPID, (pid_t)utmp->ut_pid);
11977c478bd9Sstevel@tonic-gate 			return ((struct utmpx *)utmp);
11987c478bd9Sstevel@tonic-gate 		} else {
11997c478bd9Sstevel@tonic-gate 			/*
12007c478bd9Sstevel@tonic-gate 			 * nothing available, allocate an id and
12017c478bd9Sstevel@tonic-gate 			 * write it out at the end.
12027c478bd9Sstevel@tonic-gate 			 */
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 			if (allocid((char *)utmp->ut_id, saveid)) {
12057c478bd9Sstevel@tonic-gate 				unlockutx();
12067c478bd9Sstevel@tonic-gate 				return (NULL);
12077c478bd9Sstevel@tonic-gate 			} else {
12087c478bd9Sstevel@tonic-gate 				/*
12097c478bd9Sstevel@tonic-gate 				 * Seek to end and write out the entry
12107c478bd9Sstevel@tonic-gate 				 * and also update the utmpx file.
12117c478bd9Sstevel@tonic-gate 				 */
12127c478bd9Sstevel@tonic-gate 				(void) lseek(fd, 0L, SEEK_END);
12137c478bd9Sstevel@tonic-gate 				offset = lseek(fd, 0L, SEEK_CUR);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 				putoneutx(utmp, offset);
12167c478bd9Sstevel@tonic-gate 				updwtmpx(WTMPX_FILE, (struct utmpx *)utmp);
12177c478bd9Sstevel@tonic-gate 				unlockutx();
12187c478bd9Sstevel@tonic-gate 				sendpid(ADDPID, (pid_t)utmp->ut_pid);
12197c478bd9Sstevel@tonic-gate 				return ((struct utmpx *)utmp);
12207c478bd9Sstevel@tonic-gate 			}
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 	} else {
12237c478bd9Sstevel@tonic-gate 		utp = pututxline(utmp);
12247c478bd9Sstevel@tonic-gate 		if (utp)
12257c478bd9Sstevel@tonic-gate 			updwtmpx(WTMPX_FILE, utp);
12267c478bd9Sstevel@tonic-gate 		endutxent();
12277c478bd9Sstevel@tonic-gate 		sendpid(ADDPID, (pid_t)utmp->ut_pid);
12287c478bd9Sstevel@tonic-gate 		return (utp);
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate /*
12337c478bd9Sstevel@tonic-gate  * makeut - create a utmp entry, recycling an id if a wild card is
12347c478bd9Sstevel@tonic-gate  *	specified.  Also notify init about the new pid
12357c478bd9Sstevel@tonic-gate  *
12367c478bd9Sstevel@tonic-gate  *	args:	utmp - point to utmp structure to be created
12377c478bd9Sstevel@tonic-gate  */
12387c478bd9Sstevel@tonic-gate struct utmp *
makeut(struct utmp * utmp)12397c478bd9Sstevel@tonic-gate makeut(struct utmp *utmp)
12407c478bd9Sstevel@tonic-gate {
12417c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
12427c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx2;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (compat_utmpflag)
12457c478bd9Sstevel@tonic-gate 		return (_compat_makeut(utmp));
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	getutmpx(utmp, &utmpx);
12487c478bd9Sstevel@tonic-gate 	if ((utmpx2 = makeutx(&utmpx)) == NULL)
12497c478bd9Sstevel@tonic-gate 		return (NULL);
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	getutmp(utmpx2, utmp);
12527c478bd9Sstevel@tonic-gate 	return (utmp);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate #define	UTMPNBUF	200	/* Approx 8k (FS Block) size */
12577c478bd9Sstevel@tonic-gate static struct futmpx	*utmpbuf = NULL;
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate /*
12607c478bd9Sstevel@tonic-gate  * Buffered read routine to get one entry from utmpx file
12617c478bd9Sstevel@tonic-gate  */
12627c478bd9Sstevel@tonic-gate static struct futmpx *
getoneutx(off_t * off)12637c478bd9Sstevel@tonic-gate getoneutx(off_t *off)
12647c478bd9Sstevel@tonic-gate {
12657c478bd9Sstevel@tonic-gate 	static	size_t idx = 0;	/* Current index in the utmpbuf */
12667c478bd9Sstevel@tonic-gate 	static	size_t nidx = 0;	/* Max entries in this utmpbuf */
12677c478bd9Sstevel@tonic-gate 	static	int nbuf = 0;	/* number of utmpbufs read from disk */
12687c478bd9Sstevel@tonic-gate 	ssize_t	nbytes, bufsz = sizeof (struct futmpx) * UTMPNBUF;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	if (utmpbuf == NULL)
12717c478bd9Sstevel@tonic-gate 		if ((utmpbuf = malloc(bufsz)) == NULL) {
12727c478bd9Sstevel@tonic-gate 			perror("malloc");
12737c478bd9Sstevel@tonic-gate 			return (NULL);
12747c478bd9Sstevel@tonic-gate 		}
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	if (idx == nidx) {
12777c478bd9Sstevel@tonic-gate 		/*
12787c478bd9Sstevel@tonic-gate 		 *	We have read all entries in the utmpbuf. Read
12797c478bd9Sstevel@tonic-gate 		 *	the buffer from the disk.
12807c478bd9Sstevel@tonic-gate 		 */
12817c478bd9Sstevel@tonic-gate 		if ((nbytes = read(fd, utmpbuf, bufsz)) < bufsz) {
12827c478bd9Sstevel@tonic-gate 			/*
12837c478bd9Sstevel@tonic-gate 			 *	Partial read only. keep count of the
12847c478bd9Sstevel@tonic-gate 			 *	number of valid entries in the buffer
12857c478bd9Sstevel@tonic-gate 			 */
12867c478bd9Sstevel@tonic-gate 			nidx = nbytes / sizeof (struct futmpx);
12877c478bd9Sstevel@tonic-gate 		} else {
12887c478bd9Sstevel@tonic-gate 			/*
12897c478bd9Sstevel@tonic-gate 			 *	We read in the full UTMPNBUF entries
12907c478bd9Sstevel@tonic-gate 			 *	Great !
12917c478bd9Sstevel@tonic-gate 			 */
12927c478bd9Sstevel@tonic-gate 			nidx = UTMPNBUF;
12937c478bd9Sstevel@tonic-gate 		}
12947c478bd9Sstevel@tonic-gate 		nbuf++;		/* Number of buf we have read in. */
12957c478bd9Sstevel@tonic-gate 		idx = 0;	/* reset index within utmpbuf */
12967c478bd9Sstevel@tonic-gate 	}
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	/*
12997c478bd9Sstevel@tonic-gate 	 *	Current offset of this buffer in the file
13007c478bd9Sstevel@tonic-gate 	 */
13017c478bd9Sstevel@tonic-gate 	*off = (((nbuf - 1) * UTMPNBUF) + idx) * sizeof (struct futmpx);
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	if (idx < nidx) {
13047c478bd9Sstevel@tonic-gate 		/*
13057c478bd9Sstevel@tonic-gate 		 *	We still have at least one valid buffer in
13067c478bd9Sstevel@tonic-gate 		 *	utmpbuf to be passed to the caller.
13077c478bd9Sstevel@tonic-gate 		 */
13087c478bd9Sstevel@tonic-gate 		return (&utmpbuf[idx++]);
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	/*
13127c478bd9Sstevel@tonic-gate 	 *	Reached EOF. Return NULL. Offset is set correctly
13137c478bd9Sstevel@tonic-gate 	 *	to append at the end of the file
13147c478bd9Sstevel@tonic-gate 	 */
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	return (NULL);
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate static void
putoneutx(const struct utmpx * utpx,off_t off)13207c478bd9Sstevel@tonic-gate putoneutx(const struct utmpx *utpx, off_t off)
13217c478bd9Sstevel@tonic-gate {
13227c478bd9Sstevel@tonic-gate 	struct	futmpx futx;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	utmpx_api2frec(utpx, &futx);
13257c478bd9Sstevel@tonic-gate 	(void) lseek(fd, off, SEEK_SET);	/* seek in the utmpx file */
13267c478bd9Sstevel@tonic-gate 	(void) write(fd, &futx, sizeof (futx));
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate /*
13307c478bd9Sstevel@tonic-gate  * sendupid - send message to utmpd to add or remove a pid from the
13317c478bd9Sstevel@tonic-gate  *	list of procs to watch
13327c478bd9Sstevel@tonic-gate  *
13337c478bd9Sstevel@tonic-gate  *	args:	cmd - ADDPID or REMPID
13347c478bd9Sstevel@tonic-gate  *		pid - process ID of process to watch
13357c478bd9Sstevel@tonic-gate  */
13367c478bd9Sstevel@tonic-gate static void
sendupid(int cmd,pid_t pid)13377c478bd9Sstevel@tonic-gate sendupid(int cmd, pid_t pid)
13387c478bd9Sstevel@tonic-gate {
13397c478bd9Sstevel@tonic-gate 	int pfd;		/* file desc. for utmp pipe */
13407c478bd9Sstevel@tonic-gate 	pidrec_t prec;		/* place for message to be built */
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	/*
13437c478bd9Sstevel@tonic-gate 	 * if for some reason utmp didn't open utmppipe, open it read/write
13447c478bd9Sstevel@tonic-gate 	 * here to avoid sending SIGPIPE to the calling process
13457c478bd9Sstevel@tonic-gate 	 */
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	pfd = open(UPIPE, O_RDWR | O_NONBLOCK | O_NDELAY);
13487c478bd9Sstevel@tonic-gate 	if (pfd < 0)
13497c478bd9Sstevel@tonic-gate 		return;
13507c478bd9Sstevel@tonic-gate 	prec.pd_pid = pid;
13517c478bd9Sstevel@tonic-gate 	prec.pd_type = cmd;
13527c478bd9Sstevel@tonic-gate 	(void) write(pfd, &prec, sizeof (pidrec_t));
13537c478bd9Sstevel@tonic-gate 	(void) close(pfd);
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate /*
13577c478bd9Sstevel@tonic-gate  * getutmpx - convert a utmp record into a utmpx record
13587c478bd9Sstevel@tonic-gate  */
13597c478bd9Sstevel@tonic-gate void
getutmpx(const struct utmp * ut,struct utmpx * utx)13607c478bd9Sstevel@tonic-gate getutmpx(const struct utmp *ut, struct utmpx *utx)
13617c478bd9Sstevel@tonic-gate {
13627c478bd9Sstevel@tonic-gate 	(void) memcpy(utx->ut_user, ut->ut_user, sizeof (ut->ut_user));
13637c478bd9Sstevel@tonic-gate 	(void) bzero(&utx->ut_user[sizeof (ut->ut_user)],
13647c478bd9Sstevel@tonic-gate 	    sizeof (utx->ut_user) - sizeof (ut->ut_user));
13657c478bd9Sstevel@tonic-gate 	(void) memcpy(utx->ut_line, ut->ut_line, sizeof (ut->ut_line));
13667c478bd9Sstevel@tonic-gate 	(void) bzero(&utx->ut_line[sizeof (ut->ut_line)],
13677c478bd9Sstevel@tonic-gate 	    sizeof (utx->ut_line) - sizeof (ut->ut_line));
13687c478bd9Sstevel@tonic-gate 	(void) memcpy(utx->ut_id, ut->ut_id, sizeof (ut->ut_id));
13697c478bd9Sstevel@tonic-gate 	utx->ut_pid = ut->ut_pid;
13707c478bd9Sstevel@tonic-gate 	utx->ut_type = ut->ut_type;
13717c478bd9Sstevel@tonic-gate 	utx->ut_exit = ut->ut_exit;
13727c478bd9Sstevel@tonic-gate 	utx->ut_tv.tv_sec = ut->ut_time;
13737c478bd9Sstevel@tonic-gate 	utx->ut_tv.tv_usec = 0;
13747c478bd9Sstevel@tonic-gate 	utx->ut_session = 0;
13757c478bd9Sstevel@tonic-gate 	bzero(utx->pad, sizeof (utx->pad));
13767c478bd9Sstevel@tonic-gate 	bzero(utx->ut_host, sizeof (utx->ut_host));
13777c478bd9Sstevel@tonic-gate 	utx->ut_syslen = 0;
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate /*
13817c478bd9Sstevel@tonic-gate  * getutmp - convert a utmpx record into a utmp record
13827c478bd9Sstevel@tonic-gate  */
13837c478bd9Sstevel@tonic-gate void
getutmp(const struct utmpx * utx,struct utmp * ut)13847c478bd9Sstevel@tonic-gate getutmp(const struct utmpx *utx, struct utmp *ut)
13857c478bd9Sstevel@tonic-gate {
13867c478bd9Sstevel@tonic-gate 	(void) memcpy(ut->ut_user, utx->ut_user, sizeof (ut->ut_user));
13877c478bd9Sstevel@tonic-gate 	(void) memcpy(ut->ut_line, utx->ut_line, sizeof (ut->ut_line));
13887c478bd9Sstevel@tonic-gate 	(void) memcpy(ut->ut_id, utx->ut_id, sizeof (utx->ut_id));
13897c478bd9Sstevel@tonic-gate 	ut->ut_pid = utx->ut_pid;
13907c478bd9Sstevel@tonic-gate 	ut->ut_type = utx->ut_type;
13917c478bd9Sstevel@tonic-gate 	ut->ut_exit = utx->ut_exit;
13927c478bd9Sstevel@tonic-gate 	ut->ut_time = utx->ut_tv.tv_sec;
13937c478bd9Sstevel@tonic-gate }
1394