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 */ 287c478bd9Sstevel@tonic-gate /* 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 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 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 * 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 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 * 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 * 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 * 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 * 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 * 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 * 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 4787c478bd9Sstevel@tonic-gate #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 * 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'; 512*8793b36bSNick 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 * 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++; 6617c478bd9Sstevel@tonic-gate if (lockf(fd, F_LOCK, 0) < NULL) 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 * 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 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 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 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 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 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 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 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 done: 8817c478bd9Sstevel@tonic-gate (void) close(wfdx); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * Add record to wtmp (actually wtmpx). If not updating /var/adm/wtmp, 8867c478bd9Sstevel@tonic-gate * use the old utmp compatibility routine to write a utmp-format 8877c478bd9Sstevel@tonic-gate * record to the file specified. 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate void 8907c478bd9Sstevel@tonic-gate updwtmp(const char *file, struct utmp *ut) 8917c478bd9Sstevel@tonic-gate { 8927c478bd9Sstevel@tonic-gate struct utmpx utmpx; 8937c478bd9Sstevel@tonic-gate char xfile[MAXFILE + 1]; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate if (strcmp(file, "/var/adm/wtmp") == 0) { 8967c478bd9Sstevel@tonic-gate (void) strlcpy(xfile, file, sizeof (xfile) - 1); 8977c478bd9Sstevel@tonic-gate (void) strcat(xfile, "x"); 8987c478bd9Sstevel@tonic-gate getutmpx(ut, &utmpx); 8997c478bd9Sstevel@tonic-gate updwtmpx((const char *)&xfile, &utmpx); 9007c478bd9Sstevel@tonic-gate } else 9017c478bd9Sstevel@tonic-gate _compat_updwtmp(file, ut); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * modutx - modify a utmpx entry. Also notify init about new pids or 9067c478bd9Sstevel@tonic-gate * old pids that it no longer needs to care about 9077c478bd9Sstevel@tonic-gate * 9087c478bd9Sstevel@tonic-gate * args: utp- point to utmpx structure to be created 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate struct utmpx * 9117c478bd9Sstevel@tonic-gate modutx(const struct utmpx *utp) 9127c478bd9Sstevel@tonic-gate { 9137c478bd9Sstevel@tonic-gate int i; 9147c478bd9Sstevel@tonic-gate struct utmpx utmp; /* holding area */ 9157c478bd9Sstevel@tonic-gate struct utmpx *ucp = &utmp; /* and a pointer to it */ 9167c478bd9Sstevel@tonic-gate struct utmpx *up; /* "current" utmpx entry */ 9177c478bd9Sstevel@tonic-gate struct futmpx *fup; /* being examined */ 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate for (i = 0; i < IDLEN; ++i) { 9207c478bd9Sstevel@tonic-gate if ((unsigned char)utp->ut_id[i] == SC_WILDC) 9217c478bd9Sstevel@tonic-gate return (NULL); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * copy the supplied utmpx structure someplace safe 9267c478bd9Sstevel@tonic-gate */ 9270293487cSraf (void) memcpy(&utmp, utp, sizeof (utmp)); 9287c478bd9Sstevel@tonic-gate setutxent(); 9297c478bd9Sstevel@tonic-gate while (fup = getutxent_frec()) { 9307c478bd9Sstevel@tonic-gate if (idcmp(ucp->ut_id, fup->ut_id)) 9317c478bd9Sstevel@tonic-gate continue; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * only get here if ids are the same, i.e. found right entry 9357c478bd9Sstevel@tonic-gate */ 9367c478bd9Sstevel@tonic-gate if (ucp->ut_pid != fup->ut_pid) { 9377c478bd9Sstevel@tonic-gate sendpid(REMPID, (pid_t)fup->ut_pid); 9387c478bd9Sstevel@tonic-gate sendpid(ADDPID, (pid_t)ucp->ut_pid); 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate break; 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate up = pututxline(ucp); 9437c478bd9Sstevel@tonic-gate if (ucp->ut_type == DEAD_PROCESS) 9447c478bd9Sstevel@tonic-gate sendpid(REMPID, (pid_t)ucp->ut_pid); 9457c478bd9Sstevel@tonic-gate if (up) 9467c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, up); 9477c478bd9Sstevel@tonic-gate endutxent(); 9487c478bd9Sstevel@tonic-gate return (up); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * modut - modify a utmp entry. Also notify init about new pids or 9537c478bd9Sstevel@tonic-gate * old pids that it no longer needs to care about 9547c478bd9Sstevel@tonic-gate * 9557c478bd9Sstevel@tonic-gate * args: utmp - point to utmp structure to be created 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate struct utmp * 9587c478bd9Sstevel@tonic-gate modut(struct utmp *utp) 9597c478bd9Sstevel@tonic-gate { 9607c478bd9Sstevel@tonic-gate struct utmpx utmpx; 9617c478bd9Sstevel@tonic-gate struct utmpx *utmpx2; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate getutmpx(utp, &utmpx); 9647c478bd9Sstevel@tonic-gate if ((utmpx2 = modutx(&utmpx)) == NULL) 9657c478bd9Sstevel@tonic-gate return (NULL); 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate getutmp(utmpx2, utp); 9687c478bd9Sstevel@tonic-gate return (utp); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * idcmp - compare two id strings, return 0 if same, non-zero if not * 9737c478bd9Sstevel@tonic-gate * args: s1 - first id string 9747c478bd9Sstevel@tonic-gate * s2 - second id string 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate static int 9777c478bd9Sstevel@tonic-gate idcmp(const char *s1, const char *s2) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate int i; 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate for (i = 0; i < IDLEN; ++i) 9827c478bd9Sstevel@tonic-gate if ((unsigned char) *s1 != SC_WILDC && (*s1++ != *s2++)) 9837c478bd9Sstevel@tonic-gate return (-1); 9847c478bd9Sstevel@tonic-gate return (0); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* 9897c478bd9Sstevel@tonic-gate * allocid - allocate an unused id for utmp, either by recycling a 9907c478bd9Sstevel@tonic-gate * DEAD_PROCESS entry or creating a new one. This routine only 9917c478bd9Sstevel@tonic-gate * gets called if a wild card character was specified. 9927c478bd9Sstevel@tonic-gate * 9937c478bd9Sstevel@tonic-gate * args: srcid - pattern for new id 9947c478bd9Sstevel@tonic-gate * saveid - last id matching pattern for a non-dead process 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate static int 9977c478bd9Sstevel@tonic-gate allocid(char *srcid, unsigned char *saveid) 9987c478bd9Sstevel@tonic-gate { 9997c478bd9Sstevel@tonic-gate int i; /* scratch variable */ 10007c478bd9Sstevel@tonic-gate int changed; /* flag to indicate that a new id has */ 10017c478bd9Sstevel@tonic-gate /* been generated */ 10027c478bd9Sstevel@tonic-gate char copyid[IDLEN]; /* work area */ 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate (void) memcpy(copyid, srcid, IDLEN); 10057c478bd9Sstevel@tonic-gate changed = 0; 10067c478bd9Sstevel@tonic-gate for (i = 0; i < IDLEN; ++i) { 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate /* 10097c478bd9Sstevel@tonic-gate * if this character isn't wild, it'll be part of the 10107c478bd9Sstevel@tonic-gate * generated id 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate if ((unsigned char) copyid[i] != SC_WILDC) 10137c478bd9Sstevel@tonic-gate continue; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate /* 10167c478bd9Sstevel@tonic-gate * it's a wild character, retrieve the character from the 10177c478bd9Sstevel@tonic-gate * saved id 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate copyid[i] = saveid[i]; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate /* 10227c478bd9Sstevel@tonic-gate * if we haven't changed anything yet, try to find a new char 10237c478bd9Sstevel@tonic-gate * to use 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate if (!changed && (saveid[i] < MAXVAL)) { 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * Note: this algorithm is taking the "last matched" id 10297c478bd9Sstevel@tonic-gate * and trying to make a 1 character change to it to create 10307c478bd9Sstevel@tonic-gate * a new one. Rather than special-case the first time 10317c478bd9Sstevel@tonic-gate * (when no perturbation is really necessary), just don't 10327c478bd9Sstevel@tonic-gate * allocate the first valid id. 10337c478bd9Sstevel@tonic-gate */ 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate while (++saveid[i] < MAXVAL) { 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * make sure new char is alphanumeric 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate if (isalnum(saveid[i])) { 10407c478bd9Sstevel@tonic-gate copyid[i] = saveid[i]; 10417c478bd9Sstevel@tonic-gate changed = 1; 10427c478bd9Sstevel@tonic-gate break; 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate if (!changed) { 10477c478bd9Sstevel@tonic-gate /* 10487c478bd9Sstevel@tonic-gate * Then 'reset' the current count at 10497c478bd9Sstevel@tonic-gate * this position to it's lowest valid 10507c478bd9Sstevel@tonic-gate * value, and propagate the carry to 10517c478bd9Sstevel@tonic-gate * the next wild-card slot 10527c478bd9Sstevel@tonic-gate * 10537c478bd9Sstevel@tonic-gate * See 1113208. 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate saveid[i] = 0; 10567c478bd9Sstevel@tonic-gate while (!isalnum(saveid[i])) 10577c478bd9Sstevel@tonic-gate saveid[i]++; 10587c478bd9Sstevel@tonic-gate copyid[i] = ++saveid[i]; 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * changed is true if we were successful in allocating an id 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate if (changed) { 10667c478bd9Sstevel@tonic-gate (void) memcpy(srcid, copyid, IDLEN); 10677c478bd9Sstevel@tonic-gate return (0); 10687c478bd9Sstevel@tonic-gate } else { 10697c478bd9Sstevel@tonic-gate return (-1); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate /* 10757c478bd9Sstevel@tonic-gate * lockutx - lock utmpx file 10767c478bd9Sstevel@tonic-gate */ 10777c478bd9Sstevel@tonic-gate static int 10787c478bd9Sstevel@tonic-gate lockutx(void) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate int lockfd; 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate if ((lockfd = open(UTMPX_FILE, O_RDWR|O_CREAT, 0644)) < 0) 10837c478bd9Sstevel@tonic-gate return (-1); 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if (lockf(lockfd, F_LOCK, 0) < 0) { 10867c478bd9Sstevel@tonic-gate (void) close(lockfd); 10877c478bd9Sstevel@tonic-gate return (-1); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate tempfd = fd; 10917c478bd9Sstevel@tonic-gate fd = lockfd; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate return (0); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate /* 11007c478bd9Sstevel@tonic-gate * unlockutx - unlock utmpx file 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate static void 11037c478bd9Sstevel@tonic-gate unlockutx(void) 11047c478bd9Sstevel@tonic-gate { 11057c478bd9Sstevel@tonic-gate (void) lockf(fd, F_ULOCK, 0); 11067c478bd9Sstevel@tonic-gate (void) close(fd); 11077c478bd9Sstevel@tonic-gate fd = tempfd; 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate /* 11127c478bd9Sstevel@tonic-gate * sendpid - send message to init to add or remove a pid from the 11137c478bd9Sstevel@tonic-gate * "godchild" list 11147c478bd9Sstevel@tonic-gate * 11157c478bd9Sstevel@tonic-gate * args: cmd - ADDPID or REMPID 11167c478bd9Sstevel@tonic-gate * pid - pid of "godchild" 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate static void 11197c478bd9Sstevel@tonic-gate sendpid(int cmd, pid_t pid) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate int pfd; /* file desc. for init pipe */ 11227c478bd9Sstevel@tonic-gate pidrec_t prec; /* place for message to be built */ 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * if for some reason init didn't open initpipe, open it read/write 11267c478bd9Sstevel@tonic-gate * here to avoid sending SIGPIPE to the calling process 11277c478bd9Sstevel@tonic-gate */ 11287c478bd9Sstevel@tonic-gate pfd = open(IPIPE, O_RDWR); 11297c478bd9Sstevel@tonic-gate if (pfd < 0) 11307c478bd9Sstevel@tonic-gate return; 11317c478bd9Sstevel@tonic-gate prec.pd_pid = pid; 11327c478bd9Sstevel@tonic-gate prec.pd_type = cmd; 11337c478bd9Sstevel@tonic-gate (void) write(pfd, &prec, sizeof (pidrec_t)); 11347c478bd9Sstevel@tonic-gate (void) close(pfd); 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * makeutx - create a utmpx entry, recycling an id if a wild card is 11397c478bd9Sstevel@tonic-gate * specified. Also notify init about the new pid 11407c478bd9Sstevel@tonic-gate * 11417c478bd9Sstevel@tonic-gate * args: utmpx - point to utmpx structure to be created 11427c478bd9Sstevel@tonic-gate */ 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate struct utmpx * 11457c478bd9Sstevel@tonic-gate makeutx(const struct utmpx *utmp) 11467c478bd9Sstevel@tonic-gate { 11477c478bd9Sstevel@tonic-gate struct utmpx *utp; 11487c478bd9Sstevel@tonic-gate struct futmpx *ut; /* "current" utmpx being examined */ 11497c478bd9Sstevel@tonic-gate unsigned char saveid[IDLEN]; /* the last id we matched that was */ 11507c478bd9Sstevel@tonic-gate /* NOT a dead proc */ 11517c478bd9Sstevel@tonic-gate int falphanum = 0x30; /* first alpha num char */ 11527c478bd9Sstevel@tonic-gate off_t offset; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* 11557c478bd9Sstevel@tonic-gate * Are any wild card char's present in the idlen string? 11567c478bd9Sstevel@tonic-gate */ 11577c478bd9Sstevel@tonic-gate if (memchr(utmp->ut_id, SC_WILDC, IDLEN) != NULL) { 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * try to lock the utmpx file, only needed if 11607c478bd9Sstevel@tonic-gate * we're doing wildcard matching 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate if (lockutx()) 11637c478bd9Sstevel@tonic-gate return (NULL); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* 11667c478bd9Sstevel@tonic-gate * used in allocid 11677c478bd9Sstevel@tonic-gate */ 11687c478bd9Sstevel@tonic-gate (void) memset(saveid, falphanum, IDLEN); 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate while (ut = getoneutx(&offset)) 11717c478bd9Sstevel@tonic-gate if (idcmp(utmp->ut_id, ut->ut_id)) { 11727c478bd9Sstevel@tonic-gate continue; 11737c478bd9Sstevel@tonic-gate } else { 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * Found a match. We are done if this is 11767c478bd9Sstevel@tonic-gate * a free slot. Else record this id. We 11777c478bd9Sstevel@tonic-gate * will need it to generate the next new id. 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate if (ut->ut_type == DEAD_PROCESS) 11807c478bd9Sstevel@tonic-gate break; 11817c478bd9Sstevel@tonic-gate else 11827c478bd9Sstevel@tonic-gate (void) memcpy(saveid, ut->ut_id, 11837c478bd9Sstevel@tonic-gate IDLEN); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate if (ut) { 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * Unused entry, reuse it. We know the offset. So 11907c478bd9Sstevel@tonic-gate * just go to that offset utmpx and write it out. 11917c478bd9Sstevel@tonic-gate */ 11927c478bd9Sstevel@tonic-gate (void) memcpy((caddr_t)utmp->ut_id, ut->ut_id, IDLEN); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate putoneutx(utmp, offset); 11957c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 11967c478bd9Sstevel@tonic-gate unlockutx(); 11977c478bd9Sstevel@tonic-gate sendpid(ADDPID, (pid_t)utmp->ut_pid); 11987c478bd9Sstevel@tonic-gate return ((struct utmpx *)utmp); 11997c478bd9Sstevel@tonic-gate } else { 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * nothing available, allocate an id and 12027c478bd9Sstevel@tonic-gate * write it out at the end. 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate if (allocid((char *)utmp->ut_id, saveid)) { 12067c478bd9Sstevel@tonic-gate unlockutx(); 12077c478bd9Sstevel@tonic-gate return (NULL); 12087c478bd9Sstevel@tonic-gate } else { 12097c478bd9Sstevel@tonic-gate /* 12107c478bd9Sstevel@tonic-gate * Seek to end and write out the entry 12117c478bd9Sstevel@tonic-gate * and also update the utmpx file. 12127c478bd9Sstevel@tonic-gate */ 12137c478bd9Sstevel@tonic-gate (void) lseek(fd, 0L, SEEK_END); 12147c478bd9Sstevel@tonic-gate offset = lseek(fd, 0L, SEEK_CUR); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate putoneutx(utmp, offset); 12177c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 12187c478bd9Sstevel@tonic-gate unlockutx(); 12197c478bd9Sstevel@tonic-gate sendpid(ADDPID, (pid_t)utmp->ut_pid); 12207c478bd9Sstevel@tonic-gate return ((struct utmpx *)utmp); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate } else { 12247c478bd9Sstevel@tonic-gate utp = pututxline(utmp); 12257c478bd9Sstevel@tonic-gate if (utp) 12267c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, utp); 12277c478bd9Sstevel@tonic-gate endutxent(); 12287c478bd9Sstevel@tonic-gate sendpid(ADDPID, (pid_t)utmp->ut_pid); 12297c478bd9Sstevel@tonic-gate return (utp); 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * makeut - create a utmp entry, recycling an id if a wild card is 12357c478bd9Sstevel@tonic-gate * specified. Also notify init about the new pid 12367c478bd9Sstevel@tonic-gate * 12377c478bd9Sstevel@tonic-gate * args: utmp - point to utmp structure to be created 12387c478bd9Sstevel@tonic-gate */ 12397c478bd9Sstevel@tonic-gate struct utmp * 12407c478bd9Sstevel@tonic-gate makeut(struct utmp *utmp) 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate struct utmpx utmpx; 12437c478bd9Sstevel@tonic-gate struct utmpx *utmpx2; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate if (compat_utmpflag) 12467c478bd9Sstevel@tonic-gate return (_compat_makeut(utmp)); 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate getutmpx(utmp, &utmpx); 12497c478bd9Sstevel@tonic-gate if ((utmpx2 = makeutx(&utmpx)) == NULL) 12507c478bd9Sstevel@tonic-gate return (NULL); 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate getutmp(utmpx2, utmp); 12537c478bd9Sstevel@tonic-gate return (utmp); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate #define UTMPNBUF 200 /* Approx 8k (FS Block) size */ 12587c478bd9Sstevel@tonic-gate static struct futmpx *utmpbuf = NULL; 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate /* 12617c478bd9Sstevel@tonic-gate * Buffered read routine to get one entry from utmpx file 12627c478bd9Sstevel@tonic-gate */ 12637c478bd9Sstevel@tonic-gate static struct futmpx * 12647c478bd9Sstevel@tonic-gate getoneutx(off_t *off) 12657c478bd9Sstevel@tonic-gate { 12667c478bd9Sstevel@tonic-gate static size_t idx = 0; /* Current index in the utmpbuf */ 12677c478bd9Sstevel@tonic-gate static size_t nidx = 0; /* Max entries in this utmpbuf */ 12687c478bd9Sstevel@tonic-gate static int nbuf = 0; /* number of utmpbufs read from disk */ 12697c478bd9Sstevel@tonic-gate ssize_t nbytes, bufsz = sizeof (struct futmpx) * UTMPNBUF; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate if (utmpbuf == NULL) 12727c478bd9Sstevel@tonic-gate if ((utmpbuf = malloc(bufsz)) == NULL) { 12737c478bd9Sstevel@tonic-gate perror("malloc"); 12747c478bd9Sstevel@tonic-gate return (NULL); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate if (idx == nidx) { 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * We have read all entries in the utmpbuf. Read 12807c478bd9Sstevel@tonic-gate * the buffer from the disk. 12817c478bd9Sstevel@tonic-gate */ 12827c478bd9Sstevel@tonic-gate if ((nbytes = read(fd, utmpbuf, bufsz)) < bufsz) { 12837c478bd9Sstevel@tonic-gate /* 12847c478bd9Sstevel@tonic-gate * Partial read only. keep count of the 12857c478bd9Sstevel@tonic-gate * number of valid entries in the buffer 12867c478bd9Sstevel@tonic-gate */ 12877c478bd9Sstevel@tonic-gate nidx = nbytes / sizeof (struct futmpx); 12887c478bd9Sstevel@tonic-gate } else { 12897c478bd9Sstevel@tonic-gate /* 12907c478bd9Sstevel@tonic-gate * We read in the full UTMPNBUF entries 12917c478bd9Sstevel@tonic-gate * Great ! 12927c478bd9Sstevel@tonic-gate */ 12937c478bd9Sstevel@tonic-gate nidx = UTMPNBUF; 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate nbuf++; /* Number of buf we have read in. */ 12967c478bd9Sstevel@tonic-gate idx = 0; /* reset index within utmpbuf */ 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007c478bd9Sstevel@tonic-gate * Current offset of this buffer in the file 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate *off = (((nbuf - 1) * UTMPNBUF) + idx) * sizeof (struct futmpx); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate if (idx < nidx) { 13057c478bd9Sstevel@tonic-gate /* 13067c478bd9Sstevel@tonic-gate * We still have at least one valid buffer in 13077c478bd9Sstevel@tonic-gate * utmpbuf to be passed to the caller. 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate return (&utmpbuf[idx++]); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate /* 13137c478bd9Sstevel@tonic-gate * Reached EOF. Return NULL. Offset is set correctly 13147c478bd9Sstevel@tonic-gate * to append at the end of the file 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate return (NULL); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate static void 13217c478bd9Sstevel@tonic-gate putoneutx(const struct utmpx *utpx, off_t off) 13227c478bd9Sstevel@tonic-gate { 13237c478bd9Sstevel@tonic-gate struct futmpx futx; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate utmpx_api2frec(utpx, &futx); 13267c478bd9Sstevel@tonic-gate (void) lseek(fd, off, SEEK_SET); /* seek in the utmpx file */ 13277c478bd9Sstevel@tonic-gate (void) write(fd, &futx, sizeof (futx)); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate /* 13317c478bd9Sstevel@tonic-gate * sendupid - send message to utmpd to add or remove a pid from the 13327c478bd9Sstevel@tonic-gate * list of procs to watch 13337c478bd9Sstevel@tonic-gate * 13347c478bd9Sstevel@tonic-gate * args: cmd - ADDPID or REMPID 13357c478bd9Sstevel@tonic-gate * pid - process ID of process to watch 13367c478bd9Sstevel@tonic-gate */ 13377c478bd9Sstevel@tonic-gate static void 13387c478bd9Sstevel@tonic-gate sendupid(int cmd, pid_t pid) 13397c478bd9Sstevel@tonic-gate { 13407c478bd9Sstevel@tonic-gate int pfd; /* file desc. for utmp pipe */ 13417c478bd9Sstevel@tonic-gate pidrec_t prec; /* place for message to be built */ 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* 13447c478bd9Sstevel@tonic-gate * if for some reason utmp didn't open utmppipe, open it read/write 13457c478bd9Sstevel@tonic-gate * here to avoid sending SIGPIPE to the calling process 13467c478bd9Sstevel@tonic-gate */ 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate pfd = open(UPIPE, O_RDWR | O_NONBLOCK | O_NDELAY); 13497c478bd9Sstevel@tonic-gate if (pfd < 0) 13507c478bd9Sstevel@tonic-gate return; 13517c478bd9Sstevel@tonic-gate prec.pd_pid = pid; 13527c478bd9Sstevel@tonic-gate prec.pd_type = cmd; 13537c478bd9Sstevel@tonic-gate (void) write(pfd, &prec, sizeof (pidrec_t)); 13547c478bd9Sstevel@tonic-gate (void) close(pfd); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate /* 13587c478bd9Sstevel@tonic-gate * getutmpx - convert a utmp record into a utmpx record 13597c478bd9Sstevel@tonic-gate */ 13607c478bd9Sstevel@tonic-gate void 13617c478bd9Sstevel@tonic-gate getutmpx(const struct utmp *ut, struct utmpx *utx) 13627c478bd9Sstevel@tonic-gate { 13637c478bd9Sstevel@tonic-gate (void) memcpy(utx->ut_user, ut->ut_user, sizeof (ut->ut_user)); 13647c478bd9Sstevel@tonic-gate (void) bzero(&utx->ut_user[sizeof (ut->ut_user)], 13657c478bd9Sstevel@tonic-gate sizeof (utx->ut_user) - sizeof (ut->ut_user)); 13667c478bd9Sstevel@tonic-gate (void) memcpy(utx->ut_line, ut->ut_line, sizeof (ut->ut_line)); 13677c478bd9Sstevel@tonic-gate (void) bzero(&utx->ut_line[sizeof (ut->ut_line)], 13687c478bd9Sstevel@tonic-gate sizeof (utx->ut_line) - sizeof (ut->ut_line)); 13697c478bd9Sstevel@tonic-gate (void) memcpy(utx->ut_id, ut->ut_id, sizeof (ut->ut_id)); 13707c478bd9Sstevel@tonic-gate utx->ut_pid = ut->ut_pid; 13717c478bd9Sstevel@tonic-gate utx->ut_type = ut->ut_type; 13727c478bd9Sstevel@tonic-gate utx->ut_exit = ut->ut_exit; 13737c478bd9Sstevel@tonic-gate utx->ut_tv.tv_sec = ut->ut_time; 13747c478bd9Sstevel@tonic-gate utx->ut_tv.tv_usec = 0; 13757c478bd9Sstevel@tonic-gate utx->ut_session = 0; 13767c478bd9Sstevel@tonic-gate bzero(utx->pad, sizeof (utx->pad)); 13777c478bd9Sstevel@tonic-gate bzero(utx->ut_host, sizeof (utx->ut_host)); 13787c478bd9Sstevel@tonic-gate utx->ut_syslen = 0; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * getutmp - convert a utmpx record into a utmp record 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate void 13857c478bd9Sstevel@tonic-gate getutmp(const struct utmpx *utx, struct utmp *ut) 13867c478bd9Sstevel@tonic-gate { 13877c478bd9Sstevel@tonic-gate (void) memcpy(ut->ut_user, utx->ut_user, sizeof (ut->ut_user)); 13887c478bd9Sstevel@tonic-gate (void) memcpy(ut->ut_line, utx->ut_line, sizeof (ut->ut_line)); 13897c478bd9Sstevel@tonic-gate (void) memcpy(ut->ut_id, utx->ut_id, sizeof (utx->ut_id)); 13907c478bd9Sstevel@tonic-gate ut->ut_pid = utx->ut_pid; 13917c478bd9Sstevel@tonic-gate ut->ut_type = utx->ut_type; 13927c478bd9Sstevel@tonic-gate ut->ut_exit = utx->ut_exit; 13937c478bd9Sstevel@tonic-gate ut->ut_time = utx->ut_tv.tv_sec; 13947c478bd9Sstevel@tonic-gate } 1395