Ultrix-3.1/src/libc/sysV/getut.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/* SCCSID: @(#)getut.c 3.0 4/22/86 */
/* (System 5) 1.3 */
/* Routines to read and write the /etc/utmp file. */
/* */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#include <errno.h>
#include <fcntl.h>
#define MAXFILE 79 /* Maximum pathname length for "utmp" file */
#ifdef DEBUG
#undef UTMP_FILE
#define UTMP_FILE "utmp"
#endif
static int fd = -1; /* File descriptor for the utmp file. */
static char utmpfile[MAXFILE+1] = UTMP_FILE; /* Name of the current
* "utmp" like file.
*/
static long loc_utmp; /* Where in "utmp" the current "ubuf" was
* found.
*/
static struct utmp ubuf; /* Copy of last entry read in. */
/* "getutent" gets the next entry in the utmp file.
*/
struct utmp *getutent()
{
extern int fd;
extern char utmpfile[];
extern struct utmp ubuf;
extern long loc_utmp,lseek();
extern int errno;
register char *u;
register int i;
struct stat stbuf;
/* If the "utmp" file is not open, attempt to open it for
* reading. If there is no file, attempt to create one. If
* both attempts fail, return NULL. If the file exists, but
* isn't readable and writeable, do not attempt to create.
*/
if (fd < 0) {
/* Make sure file is a multiple of 'utmp' entries long */
if (stat(utmpfile,&stbuf) == 0) {
if((stbuf.st_size % sizeof(struct utmp)) != 0) {
unlink(utmpfile);
}
}
if ((fd = open(utmpfile, O_RDWR|O_CREAT, 0644)) < 0) {
/* If the open failed for permissions, try opening it only for
* reading. All "pututline()" later will fail the writes.
*/
if (errno == EACCES
&& (fd = open(utmpfile, O_RDONLY)) < 0)
return(NULL);
}
}
/* Try to read in the next entry from the utmp file. */
if (read(fd,&ubuf,sizeof(ubuf)) != sizeof(ubuf)) {
/* Make sure ubuf is zeroed. */
for (i=0,u=(char *)(&ubuf); i<sizeof(ubuf); i++) *u++ = '\0';
loc_utmp = 0;
return(NULL);
}
/* Save the location in the file where this entry was found. */
loc_utmp = lseek(fd,0L,1) - (long)(sizeof(struct utmp));
return(&ubuf);
}
/* "getutid" finds the specified entry in the utmp file. If */
/* it can't find it, it returns NULL. */
struct utmp *getutid(entry)
register struct utmp *entry;
{
extern struct utmp ubuf;
struct utmp *getutent();
register short type;
/* Start looking for entry. Look in our current buffer before */
/* reading in new entries. */
do {
/* If there is no entry in "ubuf", skip to the read. */
if (ubuf.ut_type != EMPTY) {
switch(entry->ut_type) {
/* Do not look for an entry if the user sent us an EMPTY entry. */
case EMPTY:
return(NULL);
/* For RUN_LVL, BOOT_TIME, OLD_TIME, and NEW_TIME entries, only */
/* the types have to match. If they do, return the address of */
/* internal buffer. */
case RUN_LVL:
case BOOT_TIME:
case OLD_TIME:
case NEW_TIME:
if (entry->ut_type == ubuf.ut_type) return(&ubuf);
break;
/* For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, and DEAD_PROCESS */
/* the type of the entry in "ubuf", must be one of the above and */
/* id's must match. */
case INIT_PROCESS:
case LOGIN_PROCESS:
case USER_PROCESS:
case DEAD_PROCESS:
if (((type = ubuf.ut_type) == INIT_PROCESS
|| type == LOGIN_PROCESS
|| type == USER_PROCESS
|| type == DEAD_PROCESS)
&& ubuf.ut_id[0] == entry->ut_id[0]
&& ubuf.ut_id[1] == entry->ut_id[1]
&& ubuf.ut_id[2] == entry->ut_id[2]
&& ubuf.ut_id[3] == entry->ut_id[3])
return(&ubuf);
break;
/* Do not search for illegal types of entry. */
default:
return(NULL);
}
}
} while (getutent() != NULL);
/* Return NULL since the proper entry wasn't found. */
return(NULL);
}
/* "getutline" searches the "utmp" file for a LOGIN_PROCESS or
* USER_PROCESS with the same "line" as the specified "entry".
*/
struct utmp *getutline(entry)
register struct utmp *entry;
{
extern struct utmp ubuf,*getutent();
register struct utmp *cur;
/* Start by using the entry currently incore. This prevents */
/* doing reads that aren't necessary. */
cur = &ubuf;
do {
/* If the current entry is the one we are interested in, return */
/* a pointer to it. */
if (cur->ut_type != EMPTY && (cur->ut_type == LOGIN_PROCESS
|| cur->ut_type == USER_PROCESS) && strncmp(&entry->ut_line[0],
&cur->ut_line[0],sizeof(cur->ut_line)) == 0) return(cur);
} while ((cur = getutent()) != NULL);
/* Since entry wasn't found, return NULL. */
return(NULL);
}
/* "pututline" writes the structure sent into the utmp file. */
/* If there is already an entry with the same id, then it is */
/* overwritten, otherwise a new entry is made at the end of the */
/* utmp file. */
struct utmp *pututline(entry)
struct utmp *entry;
{
int fc;
struct utmp *answer;
extern long time();
extern struct utmp ubuf;
extern long loc_utmp,lseek();
extern struct utmp *getutid();
extern int fd,errno;
struct utmp tmpbuf;
/* Copy the user supplied entry into our temporary buffer to */
/* avoid the possibility that the user is actually passing us */
/* the address of "ubuf". */
tmpbuf = *entry;
getutent();
if (fd < 0) {
#ifdef ERRDEBUG
gdebug("pututline: Unable to create utmp file.\n");
#endif
return((struct utmp *)NULL);
}
/* Make sure file is writable */
if ((fc=fcntl(fd, F_GETFL, NULL)) == -1
|| (fc & O_RDWR) != O_RDWR) {
return((struct utmp *)NULL);
}
/* Find the proper entry in the utmp file. Start at the current */
/* location. If it isn't found from here to the end of the */
/* file, then reset to the beginning of the file and try again. */
/* If it still isn't found, then write a new entry at the end of */
/* the file. (Making sure the location is an integral number of */
/* utmp structures into the file incase the file is scribbled.) */
if (getutid(&tmpbuf) == NULL) {
#ifdef ERRDEBUG
gdebug("First getutid() failed. fd: %d",fd);
#endif
setutent();
if (getutid(&tmpbuf) == NULL) {
#ifdef ERRDEBUG
loc_utmp = lseek(fd, 0L, 1);
gdebug("Second getutid() failed. fd: %d loc_utmp: %ld\n",fd,loc_utmp);
#endif
fcntl(fd, F_SETFL, fc | O_APPEND);
} else {
lseek(fd, -(long)sizeof(struct utmp), 1);
}
} else {
lseek(fd, -(long)sizeof(struct utmp), 1);
}
/* Write out the user supplied structure. If the write fails, */
/* then the user probably doesn't have permission to write the */
/* utmp file. */
if (write(fd,&tmpbuf,sizeof(tmpbuf)) != sizeof(tmpbuf)) {
#ifdef ERRDEBUG
gdebug("pututline failed: write-%d\n",errno);
#endif
answer = (struct utmp *)NULL;
} else {
/* Copy the user structure into ubuf so that it will be up to */
/* date in the future. */
ubuf = tmpbuf;
answer = &ubuf;
#ifdef ERRDEBUG
gdebug("id: %c%c loc: %x\n",ubuf.ut_id[0],ubuf.ut_id[1],
ubuf.ut_id[2],ubuf.ut_id[3],loc_utmp);
#endif
}
fcntl(fd, F_SETFL, fc);
return(answer);
}
/* "setutent" just resets the utmp file back to the beginning. */
setutent()
{
register char *ptr;
register int i;
extern int fd;
extern struct utmp ubuf;
extern long loc_utmp;
if (fd != -1) lseek(fd,0L,0);
/* Zero the stored copy of the last entry read, since we are */
/* resetting to the beginning of the file. */
for (i=0,ptr=(char*)&ubuf; i < sizeof(ubuf);i++) *ptr++ = '\0';
loc_utmp = 0L;
}
/* "endutent" closes the utmp file. */
endutent()
{
extern int fd;
extern long loc_utmp;
extern struct utmp ubuf;
register char *ptr;
register int i;
if (fd != -1) close(fd);
fd = -1;
loc_utmp = 0;
for (i=0,ptr= (char *)(&ubuf); i < sizeof(ubuf);i++) *ptr++ = '\0';
}
/* "utmpname" allows the user to read a file other than the */
/* normal "utmp" file. */
utmpname(newfile)
char *newfile;
{
extern char utmpfile[];
/* Determine if the new filename will fit. If not, return 0. */
if (strlen(newfile) > MAXFILE) return (0);
/* Otherwise copy in the new file name. */
else strcpy(&utmpfile[0],newfile);
/* Make sure everything is reset to the beginning state. */
endutent();
return(1);
}
#ifdef ERRDEBUG
#include <stdio.h>
gdebug(format,arg1,arg2,arg3,arg4,arg5,arg6)
char *format;
int arg1,arg2,arg3,arg4,arg5,arg6;
{
register FILE *fp;
register int errnum;
extern int errno;
if ((fp = fopen("/etc/dbg.getut","a+")) == NULL) return;
fprintf(fp,format,arg1,arg2,arg3,arg4,arg5,arg6);
fclose(fp);
}
#endif