Logo Search packages:      
Sourcecode: fbgetty version File versions  Download package

utmp.c

/* $Id: utmp.c,v 1.5.2.3 2001/11/24 12:48:53 ydroneaud Exp $
 * fbgetty : a getty for framebuffer 
 * Copyright (C) 2000 2001 Yann Droneaud <ydroneaud@meuh.eu.org>. 
 *
 * fbgetty is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * fbgetty is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
 *
 */

/*
 * This file deals with user accouting database
 *  read, write, update
 *
 */


#include <fbgetty/global.h>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <fcntl.h>

#include <paths.h>

#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#else
#include <utmp.h>

/* compatibility defines */
#define utmpxname utmpname
#define setutxent setutent
#define getutxent getutent
#define endutxent endutent
#define pututxline pututline
#define utmpx utmp
#define updwtmpx updwtmp
#define wtmpx_file wtmp_file
#define wtmpx_locktimeout wtmp_locktimeout 

#define _PATH_UTMPX _PATH_UTMP
#define _PATH_WTMPX _PATH_WTMP

#endif

#if !defined(HAVE_UPDWTMP) && !defined(HAVE_UPDWTMPX)
int updwtmpx(const char *file, const struct utmpx *utx);
#endif
#if !defined(HAVE_SETUTENT) && !defined(HAVE_SETUTXENT)
void setutxent (void);
#endif
#if !defined(HAVE_GETUTENT) && !defined(HAVE_GETUTXENT)
struct utmpx *getutxent (void);
#endif
#if !defined(HAVE_ENDUTENT) && !defined(HAVE_ENDUTXENT)
void endutxent (void);
#endif
#if !defined(HAVE_PUTUTLINE) && !defined(HAVE_PUTUTXLINE)
struct utmpx * pututxline (const struct utmpx *ut);
#endif
#if !defined(HAVE_PUTUTLINE) && !defined(HAVE_PUTUTXLINE)
int utmpxname (const char *file);
#endif


#include <signal.h>
#include <errno.h>
#include <string.h>

#include <fbgetty/errors.h>
#include <fbgetty/options.h>

#include <fbgetty/utmp.h>


/* return the number logged into the system */
int 
utmp_get_users_count(void)
{
  struct utmpx *utx;
  int users = 0;

  setutxent ();

  do
    {
      utx = getutxent ();
      if (utx != NULL && 
        utx->ut_type == USER_PROCESS &&
        *(utx->ut_user) != '\0')
      users ++;
    }
  while (utx != NULL);
  
  endutxent ();

  return users;
}

/*
 * utmp_update - update our utmp entry
 * and a log entry in wtmp
 */
int
utmp_update(void)
{
  struct utmpx utx;
  struct utmpx *utxp = NULL;
  pid_t pid;


#ifdef FB_GETTY_DEBUG
  error("updating utmp");
#endif

  utmpxname (_PATH_UTMPX); /* This not needed on GNU systems */
  
  /* find fbgetty in /var/run/utmp (the utmp record is stored by init */
  setutxent ();

  pid = getpid();
  while ((utxp = getutxent ()) != NULL )
    {
      if (utxp->ut_pid == pid)
      break;
    }
  
  if (utxp != NULL )
    {
      /* copy information from the utmp entry found */
      memcpy (&utx, utxp, sizeof (struct utmpx));
    }
  else
    {
      /* some inits don't initialize utmp...
       * so create a new one, may cause some problem
       */
      memset (&utx, 0, sizeof (struct utmpx));
      
#if defined(HAVE_UTMPX_H) || defined(HAVE_HAVE_STRUCT_UTMP_UT_ID)
      {
      char tty_number[16];

#ifndef HAVE_SNPRINTF 
      sprintf(tty_number, "%d", fgoptions->tty_number);
#else
      snprintf(tty_number, 16, "%d", fgoptions->tty_number);
#endif      
      strncpy(utx.ut_id, tty_number, 4 * sizeof(char)); /* ut_id is an array of 4 bytes */
      }
#endif
    }

  /* the line (tty device without /dev/ prefix) */
#if defined(HAVE_UTMPX_H) || defined(HAVE_HAVE_STRUCT_UTMP_UT_LINE) 
#ifndef UT_LINESIZE
#define UT_LINESIZE (sizeof (utx.ut_line))
#endif

  strncpy (utx.ut_line, strchr (fgoptions->tty_device + 1, '/') + 1 , UT_LINESIZE);
#endif    

  /* the user name: for getty use LOGIN */
#if defined(HAVE_UTMPX_H) || defined(HAVE_HAVE_STRUCT_UTMP_UT_USER) 
#ifndef UT_NAMESIZE
#define UT_NAMESIZE (sizeof (utx.ut_user))
#endif
  strncpy (utx.ut_user, "LOGIN", UT_NAMESIZE);
#endif
#if !defined(HAVE_UTMPX_H) && (!defined(HAVE_HAVE_STRUCT_UTMP_UT_USER) && \
                        defined(HAVE_HAVE_STRUCT_UTMP_UT_NAME))  
#ifndef UT_NAMESIZE
#define UT_NAMESIZE (sizeof (utx.ut_name))
#endif
  strncpy (utx.ut_name, "LOGIN", UT_NAMESIZE);
#endif

  /* the current time */
#if defined(HAVE_UTMPX_H) || defined(HAVE_HAVE_STRUCT_UTMP_UT_TV)
  gettimeofday(&utx.ut_tv, NULL);
#endif
#if !defined(HAVE_UTMPX_H) && (!defined(HAVE_HAVE_STRUCT_UTMP_UT_TV) && \
                        defined(HAVE_HAVE_STRUCT_UTMP_UT_TIME)) 
  time(&utx.ut_time);
#endif

#if !defined(HAVE_UTMPX_H) && (!defined(HAVE_HAVE_STRUCT_UTMP_UT_TV) && \
                       !defined(HAVE_HAVE_STRUCT_UTMP_UT_TIME) && \
                        defined(HAVE_HAVE_STRUCT_UTMP_UT_XTIME)) 
  time(&utx.ut_xtime);
#endif

  /* type of process, use LOGIN_PROCESS but INIT_PROCESS can suit well */
#if defined(HAVE_UTMPX_H) || defined(HAVE_HAVE_STRUCT_UTMP_UT_TYPE) 
  utx.ut_type = LOGIN_PROCESS;
#endif 

  /* program pid */
#if defined(HAVE_UTMPX_H) || defined(HAVE_HAVE_STRUCT_UTMP_UT_PID) 
  utx.ut_pid = pid;
#endif

  /* hostname from which the user trying to connect from
   *  getty only deals with local virtual terminal and serial line 
   */
#if !defined(HAVE_UTMPX_H) && defined(HAVE_HAVE_STRUCT_UTMP_UT_HOST) 
  utx.ut_host = NULL; /* only set for remote login */
#endif

#if !defined(HAVE_UTMPX_H) && defined(HAVE_HAVE_STRUCT_UTMP_UT_SESSION) 
  utx.ut_session = 0; /* reserved for X Window */
#endif

#if !defined(HAVE_UTMPX_H) && defined(HAVE_HAVE_STRUCT_UTMP_UT_ADDR_V6) 
  utx.ut_addr_v6[0] = 0;
  utx.ut_addr_v6[1] = 0;
  utx.ut_addr_v6[2] = 0;
  utx.ut_addr_v6[3] = 0;
#endif
#if !defined(HAVE_UTMPX_H) && (!defined(HAVE_HAVE_STRUCT_UTMP_UT_ADDR_V6) && \
                        defined(HAVE_HAVE_STRUCT_UTMP_UT_ADDR))
  utx.ut_addr = 0;
#endif

#if !defined(HAVE_UTMPX_H) && defined(HAVE_HAVE_STRUCT_UTMP_UT_EXIT) 
  /* some strange things !
   * must be set only by DEAD_PROCESS'es
   */
  utx.ut_exit.e_termination = 0;
  utx.ut_exit.e_exit = 0;
#endif

  pututxline (&utx);
  endutxent ();

 /* add the entry to the wtmpx log file */
  updwtmpx(_PATH_WTMPX, &utx);

#ifdef FB_GETTY_DEBUG
  error("end updating utmp");
#endif

  return(0);
}


#if (!defined(HAVE_UPDWTMP) && !defined(HAVE_UPDWTMPX)) || \
    (!defined(HAVE_SETUTENT) && !defined(HAVE_SETUTXENT)) || \
    (!defined(HAVE_GETUTENT) && !defined(HAVE_GETUTXENT)) || \
    (!defined(HAVE_ENDUTENT) && !defined(HAVE_ENDUTXENT)) || \
    (!defined(HAVE_PUTUTLINE) && !defined(HAVE_PUTUTXLINE)) || \
    (!defined(HAVE_PUTUTLINE) && !defined(HAVE_PUTUTXLINE))

static const char *utmpx_filename = _PATH_UTMPX;
static int utmpx_fd = -1;

static struct utmpx utmpx_entry;
#endif


#if !defined(HAVE_UTMPNAME) && !defined(HAVE_UTMPXNAME)
/* change the name of the UTMP
 *  must call setutxent() after
 *
 *  example:
 *   utmpxname(a_file); // set the filename 
 *   setutxent();       // open the new file, reset to the beginning
 *   ut = getutxent();  // read an entry
 *   endutxent();       // close the file, free memory
 *                      // after endutxent(), ut is invalid since it points an a freed memory block
 */
int
utmpxname (const char *file)
{
  if (access(file) == -1)
    return (-1);

  utmpx_filename = file;

  return (0);
}
#endif

#if !defined(HAVE_SETUTENT) && !defined(HAVE_SETUTXENT)
/* 
 *
 */
void
setutxent (void)
{
  if (utmpx_fd != -1)
    close(utmpx_fd);

  utmpx_fd = open(utmpx_filename, O_RDWR | O_CREAT);
  if (utmpx_fd == -1)
    utmpx_fd = open(utmpx_filename, O_RDONLY);
}
#endif


#if !defined(HAVE_GETUTENT) && !defined(HAVE_GETUTXENT)
/* read an utmpx entry
 *  return a global buffer, must be copied
 */
struct utmpx *
getutxent (void)
{
  if (utmpx_fd == -1)
    setutxent(); /* be sure the file is opened */

  if (utmpx_entry != NULL)
    {
      if (read(utmpx_fd, &utmpx_entry, sizeof(struct utmpx)) != sizeof(struct utmpx))
      {
        /* perhaps a partial entry in the file
         * or simply the End Of File
         */
        return NULL;
      }
    }
  
  return &utmpx_entry;
}
#endif

#if !defined(HAVE_ENDUTENT) && !defined(HAVE_ENDUTXENT)
void
endutxent (void)
{
  if (utmpx_fd != -1)
    {
      close (utmpx_fd);
      utmpx_fd = -1;
    }
}
#endif


#if (!defined(HAVE_PUTUTLINE) && !defined(HAVE_PUTUTXLINE)) || \
    (!defined(HAVE_UPDWTMP) && !defined(HAVE_UPDWTMPX))
 
     /* these functions need some locking feature */

static const char *utmpx_lock_filename;
static struct flock utmpx_lock;
static unsigned int utmpx_old_timeout;
static struct sigaction utmpx_sa_signal; 
static struct sigaction utmpx_sa_old;

/* error while locking a file */
static RETSIGTYPE 
utmpx_file_locktimeout (int sig)
{
  if (sig == SIGALRM)
    error("lock timeout for %s", utmpx_lock_filename);
  else
    fatal_error("unknown signal received: %d", sig);
}

/*
 * try to lock a file
 */
int
utmpx_file_lock(const char *name, int fd)
{
  /* save a possible timer */
  utmpx_old_timeout = alarm(0);

  /* set the timeout handler */
  utmpx_sa_signal.sa_handler = utmpx_file_locktimeout;
  sigemptyset(&utmpx_sa_signal.sa_mask);
  utmpx_sa_signal.sa_flags = 0;
 
  if (sigaction(SIGALRM, &utmpx_sa_signal, &utmpx_sa_old) == -1)
    error("Can't set handler for SIGALRM: %s", strerror(errno));

  alarm (1);

  /* Try to get the lock. */                                           
  memset (&utmpx_lock, '\0', sizeof (struct flock));
  utmpx_lock.l_type = F_WRLCK;    /* only lock the file for writting */
  utmpx_lock.l_whence = SEEK_SET;
  utmpx_lock.l_start = (off_t) 0;
  utmpx_lock.l_len = (off_t) 0;
  
  if (fcntl (fd, F_SETLKW, &utmpx_lock) == -1)
    {
      switch(errno)
      {
      case EINTR:
      case EDEADLK:
        error("can't lock file %s: %s", utmpx_lock_filename, strerror(errno));
        return(-1);
        break;
      default:
        fatal_error("lock failed on %s: %s", utmpx_lock_filename, strerror(errno)); 
        break;
      }
    }

  return(0);
}

/* unlock the file */
int
utmp_file_unlock(int fd)
{
  /* Unlock the file.  */
  utmpx_lock.l_type = F_UNLCK;
  if (fcntl (fd, F_SETLKW, &utmpx_lock) == -1)
    {
      switch(errno)
      {
      case EINTR:
      case EDEADLK:
        error("can't lock file %s: %s", utmpx_lock_filename, strerror(errno));
        return -1;
        break;
      default:
        fatal_error("lock failed on %s: %s", utmpx_lock_filename, strerror(errno)); 
        break;
      }
    }

  if (sigaction(SIGALRM, &utmpx_sa_old, NULL) == -1)
    error("Can't restore handler for SIGALARM: %s", strerror(errno));

  alarm(utmpx_old_timeout);

  return 0;
}
#endif


#if !defined(HAVE_PUTUTLINE) && !defined(HAVE_PUTUTXLINE)
struct utmpx *
pututxline (const struct utmpx *ut)
{
#warning "Not written yet !"
#warning "wasn't written as of 2001-10-21 (me: i notice that this day !)"
}
#endif


#if !defined(HAVE_UPDWTMP) && !defined(HAVE_UPDWTMPX)  
/* emultate the GNU updwtmpx() function
 *  some code portion was taken from glibc-2.2.3
 */
int 
updwtmpx(const char *path, const struct utmpx *utx)
{
  int result = -1;
  off_t offset;

  int fd;

  /* open wtmp */
  fd = open (path, O_WRONLY);
  if (fd == -1)
    {
      error("can't open wtmp file %s: %s", path, strerror(errno));
      return -1;
    }

  if (utmpx_file_lock(path, fd) == -1)
    goto updwtmpx_unlock_return;

  /* write on wtmp
   * first check size, if not multiple of sizeof(struct utmp) 
   */
  /* Remember original size of log file.  */
  offset = lseek(fd, 0, SEEK_END);
  if (offset % sizeof (struct utmpx) != 0)
    {
      offset -= offset % sizeof (struct utmpx);
      ftruncate (fd, offset);

      if (lseek(fd, 0, SEEK_END) < 0)
        goto updwtmpx_unlock_return;
    }

  /* Write the entry.  If we can't write all the bytes, reset the file
     size back to the original size.  That way, no partial entries
     will remain.  */
  if (write (fd, utx, sizeof (struct utmp)) != sizeof (struct utmp))
    {
      ftruncate (fd, offset);
      goto updwtmpx_unlock_return;
    }

  result = 0;
  
 updwtmpx_unlock_return:

  utmpx_file_unlock(fd);

  close (fd); 

  return(result);
}
#endif /* HAVE_UPDWTMP */

Generated by  Doxygen 1.6.0   Back to index