* configure.in: Many changes to support the rewriting of the utmp
authorTom Yu <tlyu@mit.edu>
Sat, 28 Apr 2001 02:05:38 +0000 (02:05 +0000)
committerTom Yu <tlyu@mit.edu>
Sat, 28 Apr 2001 02:05:38 +0000 (02:05 +0000)
pieces of libpty.  Do a large amount of checking for consistency
of various utmp and utmpx APIs as currently understood.  See rant
in update_utmp.c.

* dump-utmp.c: Rewrite; now has capability to use utmp{,x}name()
to extract entries from utmp and utmpx files.  Adjusts field
widths when printing as appropriate.

* libpty.h: Update call signature for update_utmp() and logwtmp();
make prototypes unconditional.

* logwtmp.c: Rewrite.  Use pututline() or pututxline() API
whenever possible.

* pty-int.h: Update call signatures for update_wtmp{,x}(); make
prototypes unconditional.

* sane_hostname.c: Use the autoconf-correct macro names.

* update_utmp.c: Rewrite.  Basically, use functions from the
pututline() or pututxline() API whenever possible, to avoid
lossage.  Inserted large rant about the conjectured history of BSD
utmp, sysV utmp, and utmpx, as well as documentation about some
known quirks.

* update_wtmp.c: Rewrite.  Add new function ptyint_logwtmpx() that
takes a utmpx rather than a utmp, so it can fail to lose data
converting to and from utmp.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13218 dc483132-0cff-0310-8789-dd5450dbe970

src/util/pty/ChangeLog
src/util/pty/configure.in
src/util/pty/dump-utmp.c
src/util/pty/libpty.h
src/util/pty/logwtmp.c
src/util/pty/pty-int.h
src/util/pty/sane_hostname.c
src/util/pty/update_utmp.c
src/util/pty/update_wtmp.c

index a68dffa279eec822532897ae914adf089ca86afd..f1877a1047d89d7770f914ae7296a9ce7edca1d3 100644 (file)
@@ -1,3 +1,35 @@
+2001-04-27  Tom Yu  <tlyu@mit.edu>
+
+       * configure.in: Many changes to support the rewriting of the utmp
+       pieces of libpty.  Do a large amount of checking for consistency
+       of various utmp and utmpx APIs as currently understood.  See rant
+       in update_utmp.c.
+
+       * dump-utmp.c: Rewrite; now has capability to use utmp{,x}name()
+       to extract entries from utmp and utmpx files.  Adjusts field
+       widths when printing as appropriate.
+
+       * libpty.h: Update call signature for update_utmp() and logwtmp();
+       make prototypes unconditional.
+
+       * logwtmp.c: Rewrite.  Use pututline() or pututxline() API
+       whenever possible.
+
+       * pty-int.h: Update call signatures for update_wtmp{,x}(); make
+       prototypes unconditional.
+
+       * sane_hostname.c: Use the autoconf-correct macro names.
+
+       * update_utmp.c: Rewrite.  Basically, use functions from the
+       pututline() or pututxline() API whenever possible, to avoid
+       lossage.  Inserted large rant about the conjectured history of BSD
+       utmp, sysV utmp, and utmpx, as well as documentation about some
+       known quirks.
+
+       * update_wtmp.c: Rewrite.  Add new function ptyint_logwtmpx() that
+       takes a utmpx rather than a utmp, so it can fail to lose data
+       converting to and from utmp.
+
 2001-01-12  Tom Yu  <tlyu@mit.edu>
 
        * sane_hostname.c: Switch off of KRB5_USE_INET6 instead of
index 52ccca73b0e3e8880b342c40e647e3ac645ac249..0ad74238c7ac0414a1f0576e96142fb51f457548 100644 (file)
@@ -52,19 +52,135 @@ AC_CHECK_LIB(util,openpty, [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lutil"])
 AC_TYPE_MODE_T
 AC_CHECK_TYPE(time_t, long)
 AC_CHECK_FUNC(strsave,[AC_DEFINE(HAS_STRSAVE)])
-AC_CHECK_FUNCS(getutent setreuid gettosbyname setsid ttyname line_push ptsname grantpt openpty logwtmp getutmpx)
-AC_CHECK_HEADERS(unistd.h stdlib.h string.h pty.h utmpx.h utmp.h sys/filio.h sys/sockio.h sys/label.h sys/tty.h ttyent.h lastlog.h sys/select.h sys/ptyvar.h)
+AC_CHECK_FUNCS(setreuid gettosbyname setsid ttyname line_push ptsname grantpt openpty)
+AC_CHECK_HEADERS(unistd.h stdlib.h string.h pty.h sys/filio.h sys/sockio.h sys/label.h sys/tty.h ttyent.h lastlog.h sys/select.h sys/ptyvar.h)
 AC_CHECK_HEADERS(sys/wait.h)
-AC_CHECK_FUNCS(waitpid updwtmpx)
+AC_CHECK_FUNCS(waitpid)
 DECLARE_SYS_ERRLIST
 KRB5_SIGTYPE
 CHECK_SIGNALS
 CHECK_SETJMP
 CHECK_DIRENT
 AC_CHECK_HEADER(termios.h,AC_CHECK_FUNC(cfsetispeed,AC_DEFINE(POSIX_TERMIOS)))
-CHECK_UTMP
-dnl
-dnl
+
+######################################################################
+#
+# utmp related hair here.  There's lots of it.
+#
+
+AC_CHECK_HEADERS(utmp.h utmpx.h)
+AC_CHECK_FUNCS(setutent setutxent updwtmp updwtmpx logwtmp getutmp getutmpx)
+AC_CHECK_FUNCS(utmpname utmpxname)
+
+AC_DEFUN(K5_CHECK_UT_MEMBER,
+[AC_MSG_CHECKING([for $2 in struct $1])
+AC_CACHE_VAL([krb5_cv_struct_$1_$2],
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>], [struct $1 u; u.$2;],
+eval "krb5_cv_struct_$1_$2=yes", eval "krb5_cv_struct_$1_$2=no")])
+if eval "test \"`echo '$krb5_cv_struct_'$1'_'$2`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  krb5_tr_ut=HAVE_STRUCT_`echo $1'_'$2 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  AC_DEFINE_UNQUOTED($krb5_tr_ut)
+else
+  AC_MSG_RESULT(no)
+fi])
+
+if test $ac_cv_header_utmp_h = yes; then
+  AC_MSG_RESULT(checking struct utmp members)
+  for krb5_mem in ut_host ut_syslen ut_addr ut_id ut_pid ut_type ut_exit; do
+    K5_CHECK_UT_MEMBER(utmp, $krb5_mem)
+  done
+fi
+
+if test $ac_cv_header_utmpx_h = yes; then
+  AC_MSG_RESULT(checking struct utmpx members)
+  for krb5_mem in ut_host ut_syslen ut_addr ut_id ut_pid ut_type ut_exit; do
+    K5_CHECK_UT_MEMBER(utmpx, $krb5_mem)
+  done
+fi
+
+AC_DEFUN(K5_CHECK_UT_EXIT_MEMBER,
+[AC_MSG_CHECKING([for ut_exit.$2 in struct $1])
+AC_CACHE_VAL([krb5_cv_struct_$1_ut_exit_$2],
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <$1.h>], [struct $1 u; u.ut_exit.$2;],
+eval "krb5_cv_struct_$1_ut_exit_$2=yes",
+eval "krb5_cv_struct_$1_ut_exit_$2=no")])
+if eval "test \"`echo '$krb5_cv_struct_'$1'_ut_exit_'$2`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  ifelse([$3], , :, [$3])
+else
+  AC_MSG_RESULT(no)
+  ifelse([$4], , :, [$4])
+fi])
+
+if test $krb5_cv_struct_utmp_ut_exit = yes; then
+  AC_MSG_RESULT(checking for working ut_exit.e_exit in struct utmp)
+  for krb5_mem in __e_exit ut_e_exit ut_exit e_exit; do
+    K5_CHECK_UT_EXIT_MEMBER(utmp, $krb5_mem,
+[krb5_utmp_e_exit=$krb5_mem
+krb5_utmp_e_termination=`echo $krb5_mem|sed -e 's%_exit$%_termination%'`], )
+  done
+  if test "${krb5_utmp_e_exit+set}" = set; then
+    AC_MSG_RESULT([working ut_exit.e_exit in utmp is $krb5_utmp_e_exit])
+    AC_DEFINE_UNQUOTED(PTY_UTMP_E_EXIT, $krb5_utmp_e_exit)
+    AC_DEFINE_UNQUOTED(PTY_UTMP_E_TERMINATION, $krb5_utmp_e_termination)
+  else
+    AC_MSG_RESULT([cannot find working ut_exit.e_exit in utmp])
+  fi
+fi
+
+if test $krb5_cv_struct_utmpx_ut_exit = yes; then
+  AC_MSG_RESULT(checking for working ut_exit.e_exit in struct utmp)
+  for krb5_mem in __e_exit ut_e_exit ut_exit e_exit; do
+    K5_CHECK_UT_EXIT_MEMBER(utmpx, $krb5_mem,
+[krb5_utmpx_e_exit=$krb5_mem
+krb5_utmpx_e_termination=`echo $krb5_mem|sed -e 's%_exit$%_termination%'`], )
+  done
+  if test "${krb5_utmpx_e_exit+set}" = set; then
+    AC_MSG_RESULT([working ut_exit.e_exit in utmpx is $krb5_utmpx_e_exit])
+    AC_DEFINE_UNQUOTED(PTY_UTMPX_E_EXIT, $krb5_utmpx_e_exit)
+    AC_DEFINE_UNQUOTED(PTY_UTMPX_E_TERMINATION, $krb5_utmpx_e_termination)
+  else
+    AC_MSG_RESULT([cannot find working ut_exit.e_exit in utmpx])
+  fi
+fi
+
+if test $ac_cv_func_setutent = yes; then
+  AC_MSG_CHECKING(consistency of sysV-ish utmp API)
+  if test $krb5_cv_struct_utmp_ut_id = no \
+    || test $krb5_cv_struct_utmp_ut_type = no \
+    || test $krb5_cv_struct_utmp_ut_pid = no; then
+    AC_MSG_RESULT(not ok)
+    AC_MSG_ERROR([have setutent but no ut_id, ut_type, or ut_pid in utmp])
+  else
+    AC_MSG_RESULT(ok)
+  fi
+fi
+
+if test $ac_cv_header_utmpx_h = yes; then
+  AC_MSG_CHECKING(consistency of utmpx API)
+  if test $ac_cv_func_setutxent = no; then
+    AC_MSG_RESULT(not ok)
+    AC_MSG_ERROR([have utmpx.h but no setutxent])
+  else
+    if test $krb5_cv_struct_utmpx_ut_id = no \
+      || test $krb5_cv_struct_utmpx_ut_type = no \
+      || test $krb5_cv_struct_utmpx_ut_pid = no; then
+      AC_MSG_RESULT(not ok)
+      AC_MSG_ERROR([have setutxent but no ut_id, ut_type, or ut_pid in utmpx])
+    else
+      AC_MSG_RESULT(ok)
+    fi
+  fi
+fi
+
+#
+# end of utmp-related hair
+#
+######################################################################
+
 AC_MSG_CHECKING([streams interface])
 AC_CACHE_VAL(krb5_cv_has_streams,
 [AC_TRY_COMPILE(
@@ -131,44 +247,6 @@ if test $krb5_cv_setpgrp_args = two; then
 AC_DEFINE(SETPGRP_TWOARG)
 fi
 dnl
-dnl
-if test $ac_cv_header_utmpx_h  = yes -a $ac_cv_func_getutmpx = no; then
-AC_MSG_CHECKING([if utmpx and utmp ut_exit structures differ])
-AC_CACHE_VAL(krb5_cv_utmp_utmpx_diff_exit_struct,
-[AC_TRY_COMPILE(
-[#include <sys/types.h>
-#include <utmp.h>
-#include <utmpx.h>],[struct utmpx utx; struct utmp ut;
-utx.ut_exit.ut_exit = ut.ut_exit.e_exit],
-krb5_cv_utmp_utmpx_diff_exit_struct=yes, krb5_cv_utmp_utmpx_diff_exit_struct=no)])
-AC_MSG_RESULT($krb5_cv_utmp_utmpx_diff_exit_struct)
-if test $krb5_cv_utmp_utmpx_diff_exit_struct = yes; then
-AC_DEFINE(UT_EXIT_STRUCTURE_DIFFER)
-fi
-fi
-dnl
-dnl Test to see if a certain prototype exists in the system header files
-dnl If we get a conflict - then we back off. Note: If our prototype matches 
-dnl exactly, then we will list it and we both win.
-if test x$ac_cv_func_getutmpx = xyes; then
-AC_CACHE_CHECK([need to provide getutmpx prototype], krb5_cv_decl_getutmpx,
-[AC_TRY_COMPILE(dnl
-[#include <sys/types.h>
-#ifdef HAVE_UTMP_H
-#include <utmp.h>
-#endif
-#ifdef HAVE_UTMPX_H
-#include <utmpx.h>
-#endif
-extern void getutmpx (const struct utmp *, struct utmpx *);
-],
-[], krb5_cv_decl_getutmpx=yes, krb5_cv_decl_getutmpx=no)])
- if test $krb5_cv_decl_getutmpx = yes; then
-       AC_DEFINE(NEED_GETUTMPX_PROTOTYPE)
- fi
-fi
-dnl
-dnl
 ADD_DEF(-DKERBEROS)
 KRB5_AC_INET6
 AC_C_CONST
index 7cc8469113b8f8f0b1b43afaf9e985601d7bbc89..81bb49ce284b144963a305d5adaa342590189316 100644 (file)
@@ -1,6 +1,29 @@
-#include <stdio.h>
+/*
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ *
+ * dump-utmp.c: dump utmp and utmpx format files for debugging purposes.
+ */
+
+#include <sys/types.h>
 #include <sys/file.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
 
 #ifndef UTMPX
 #ifdef HAVE_UTMPX_H
 #endif
 #endif
 
+#if defined(HAVE_UTMPNAME) || defined(HAVE_UTMPXNAME)
+#define UTN                    /* we can set utmp or utmpx for getut*() */
+#endif
+
 #ifdef UTMPX
 #include <utmpx.h>
+void print_utx(int, const struct utmpx *);
 #endif
 #include <utmp.h>
 
-extern char *ctime ();
+void print_ut(int, const struct utmp *);
+
+void usage(const char *);
 
 #if defined (HAVE_STRUCT_UTMP_UT_TYPE) || defined (UTMPX)
-char *ut_typename (t) {
-  switch (t) {
+char *ut_typename(int);
+
+char *
+ut_typename(int t) {
+    switch (t) {
 #define S(N) case N : return #N
 #define S2(N,N2) case N : return #N2
-  S(EMPTY);
-  S(RUN_LVL);
-  S(BOOT_TIME);
-  S(OLD_TIME);
-  S(NEW_TIME);
-  S2(INIT_PROCESS,INIT);
-  S2(LOGIN_PROCESS,LOGIN);
-  S2(USER_PROCESS,USER);
-  S2(DEAD_PROCESS,DEAD);
-  S(ACCOUNTING);
-  default: return "??";
-  }
+       S(EMPTY);
+       S(RUN_LVL);
+       S(BOOT_TIME);
+       S(OLD_TIME);
+       S(NEW_TIME);
+       S2(INIT_PROCESS,INIT);
+       S2(LOGIN_PROCESS,LOGIN);
+       S2(USER_PROCESS,USER);
+       S2(DEAD_PROCESS,DEAD);
+       S(ACCOUNTING);
+    default: return "??";
+    }
 }
 #endif
 
-int main (argc, argv) int argc; char *argv[]; {
-  int f;
-  char id[5], user[50], host[100];
-  char *file = 0;
-  int all = 0;
-  int is_utmpx = 0;
-
-  while (*++argv)
-    {
-      char *arg = *argv;
-      if (!arg)
-       break;
-      if (!strcmp ("-a", arg))
-       all = 1;
-      else if (!strcmp ("-x", arg))
-       is_utmpx = 1;
-      else if (arg[0] == '-')
-       {
-         fprintf (stderr, "unknown arg `%s'\n", arg);
-         return 1;
-       }
-      else if (file)
-       {
-         fprintf (stderr, "already got a file\n");
-         return 1;
-       }
-      else
-       file = arg;
-    }
-  f = open (file, O_RDONLY);
-  if (f < 0) {
-    perror (file);
-    exit (1);
-  }
-  id[4] = 0;
-  if (is_utmpx) {
+#define S2D(x) (sizeof(x) * 2.4 + 1.5)
+
+void
+print_ut(int all, const struct utmp *u)
+{
+    int lu, ll;
+#ifdef HAVE_STRUCT_UTMP_UT_ID
+    int lid;
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+    int lpid;
+#endif
+#ifdef PTY_UTMP_E_EXIT
+    int let, lee;
+#endif
+
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    if (!all && ((u->ut_type == EMPTY) || (u->ut_type == DEAD_PROCESS)))
+       return;
+#endif
+
+    lu = sizeof(u->ut_user);
+    ll = sizeof(u->ut_line);
+    printf("%-*.*s:", lu, lu, u->ut_name);
+    printf("%-*.*s:", ll, ll, u->ut_line);
+#ifdef HAVE_STRUCT_UTMP_UT_ID
+    lid = sizeof(u->ut_id);
+    printf("%-*.*s:", lid, lid, u->ut_id);
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+    lpid = S2D(u->ut_pid);
+    printf("%*ld", lpid, (long)u->ut_pid);
+#endif
+#ifdef PTY_UTMP_E_EXIT
+    let = S2D(u->ut_exit.PTY_UTMP_E_TERMINATION);
+    lee = S2D(u->ut_exit.PTY_UTMP_E_EXIT);
+    printf("(%*ld,", let, (long)u->ut_exit.PTY_UTMP_E_TERMINATION);
+    printf("%*ld)", lee, (long)u->ut_exit.PTY_UTMP_E_EXIT);
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    printf(" %-9s", ut_typename(u->ut_type));
+#endif
+    printf(" %s", ctime(&u->ut_time) + 4);
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    if (u->ut_host[0])
+       printf(" %s\n", u->ut_host);
+#endif
+
+    return;
+}
+
 #ifdef UTMPX
-    struct utmpx u;
-    while (1) {
-      int nread = read (f, &u, sizeof (u));
-      if (nread == 0) {
-       /* eof */
-       return 0;
-      } else if (nread == -1) {
-       /* error */
-       perror ("read");
-       return 1;
-      }
-      if ((u.ut_type == DEAD_PROCESS
-          || u.ut_type == EMPTY)
-         && !all)
-       continue;
-      strncpy (id, u.ut_id, 4);
-      printf ("%-8s:%-12s:%-4s", u.ut_user, u.ut_line, id);
-      printf (":%5d", u.ut_pid);
-      printf ("(%5d,%5d)", u.ut_exit.e_termination, u.ut_exit.e_exit);
-      printf (" %-9s %s", ut_typename (u.ut_type), ctime (&u.ut_xtime) + 4);
-      if (u.ut_syslen && u.ut_host[0])
-       printf (" %s\n", u.ut_host);
-    }
-    abort ();
+void
+print_utx(int all, const struct utmpx *u)
+{
+    int lu, ll, lid, lpid;
+#ifdef PTY_UTMPX_E_EXIT
+    int let, lee;
+#endif
+
+    if (!all && ((u->ut_type == EMPTY) || (u->ut_type == DEAD_PROCESS)))
+       return;
+
+    lu = sizeof(u->ut_user);
+    ll = sizeof(u->ut_line);
+    lid = sizeof(u->ut_id);
+    printf("%-*.*s:", lu, lu, u->ut_user);
+    printf("%-*.*s:", ll, ll, u->ut_line);
+    printf("%-*.*s", lid, lid, u->ut_id);
+    if (lu + ll + lid >= 60)
+       printf("\n");
+    else
+       printf(":");
+    lpid = S2D(u->ut_pid);
+    printf("%*ld", lpid, (long)u->ut_pid);
+#ifdef PTY_UTMPX_E_EXIT
+    let = S2D(u->ut_exit.PTY_UTMPX_E_TERMINATION);
+    lee = S2D(u->ut_exit.PTY_UTMPX_E_EXIT);
+    printf("(%*ld,", let, (long)u->ut_exit.PTY_UTMPX_E_TERMINATION);
+    printf("%*ld)", lee, (long)u->ut_exit.PTY_UTMPX_E_EXIT);
+#endif
+    printf(" %-9s", ut_typename(u->ut_type));
+    printf(" %s", ctime(&u->ut_tv.tv_sec) + 4);
+#ifdef HAVE_STRUCT_UTMPX_UT_HOST
+    if (u->ut_host[0])
+       printf(" %s\n", u->ut_host);
+#endif
+
+    return;
+}
+#endif
+
+#ifdef UTMPX
+#define OPTX "x"
 #else
-    fprintf (stderr, "utmpx support not compiled in\n");
-    return 1;
-#endif
-  }
-  /* else */
-  {
-    struct utmp u;
-    while (read (f, &u, sizeof (u)) == sizeof (u)) {
-#ifdef EMPTY
-      if ((u.ut_type == DEAD_PROCESS
-          || u.ut_type == EMPTY)
-         && !all)
-       continue;
+#define OPTX
 #endif
-#ifdef HAVE_STRUCT_UTMP_UT_PID
-      strncpy (id, u.ut_id, 4);
-      strncpy (user, u.ut_user, sizeof (u.ut_user));
-      user[sizeof(u.ut_user)] = 0;
-      printf ("%-8s:%-12s:%-4s", user, u.ut_line, id);
-      printf (":%5d", u.ut_pid);
+#ifdef UTN
+#define OPTG "g"
 #else
-      strncpy (user, u.ut_name, sizeof (u.ut_name));
-      user[sizeof(u.ut_name)] = 0;
-      printf ("%-8s:%-12s", user, u.ut_line);
+#define OPTG
 #endif
-#ifdef HAVE_STRUCT_UTMP_UT_HOST
-      {
-       char host[sizeof (u.ut_host) + 1];
-       strncpy (host, u.ut_host, sizeof(u.ut_host));
-       host[sizeof (u.ut_host)] = 0;
-       printf (":%-*s", sizeof (u.ut_host), host);
-      }
+#define OPTS "a" OPTX OPTG
+
+void
+usage(const char *prog)
+{
+    fprintf(stderr, "usage: %s [-" OPTS "] file\n", prog);
+    exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+    int c;
+    int all, is_utmpx, do_getut;
+    int f;
+    char *fn;
+    size_t recsize;
+    size_t nread;
+    union {
+       struct utmp ut;
+#ifdef UTMPX
+       struct utmpx utx;
 #endif
-#ifdef HAVE_STRUCT_UTMP_UT_EXIT
-      printf ("(%5d,%5d)", u.ut_exit.e_termination, u.ut_exit.e_exit);
+    } u;
+    struct utmp *utp;
+#ifdef UTMPX
+    struct utmpx *utxp;
 #endif
-#ifdef HAVE_STRUCT_UTMP_UT_TYPE
-      printf (" %-9s", ut_typename (u.ut_type));
+
+    all = is_utmpx = do_getut = 0;
+    recsize = sizeof(struct utmp);
+
+    while ((c = getopt(argc, argv, OPTS)) != EOF) {
+       switch (c) {
+       case 'a':
+           all = 1;
+           break;
+#ifdef UTMPX
+       case 'x':
+           is_utmpx = 1;
+           recsize = sizeof(struct utmpx);
+           break;
+#endif
+#ifdef UTN
+       case 'g':
+           do_getut = 1;
+           break;
 #endif
-      /* this ends with a newline */
-      printf (" %s", ctime (&u.ut_time) + 4);
+       default:
+           usage(argv[0]);
+       }
     }
-  }
-
-  return 0;
+    if (argc <= optind)
+       usage(argv[0]);
+    fn = argv[optind];
+    if (!do_getut) {
+       f = open(fn, O_RDONLY);
+       if (f == -1) {
+           perror(fn);
+           exit(1);
+       }
+       do {
+           nread = read(f, &u, recsize);
+           if (nread == -1) {
+               perror("read");
+               exit(1);
+           }
+           if (nread && nread < recsize) {
+               fprintf(stderr, "short read");
+               close(f);
+               exit(1);
+           }
+           if (is_utmpx) {
+#ifdef UTMPX
+               print_utx(all, &u.utx);
+#else
+               abort();
+#endif
+           } else {
+               print_ut(all, &u.ut);
+           }
+       } while (nread);
+       close(f);
+    } else {
+       if (is_utmpx) {
+#if defined(UTMPX) && defined(UTN)
+           utmpxname(fn);
+           setutxent();
+           while ((utxp = getutxent()) != NULL)
+               print_utx(all, utxp);
+#else
+           abort();
+#endif
+       } else {
+#ifdef HAVE_UTMPNAME
+           utmpname(fn);
+           setutxent();
+           while ((utp = getutent()) != NULL)
+               print_ut(all, utp);
+#else
+           abort();
+#endif
+       }
+    }
+    exit(0);    
 }
index 0274c98cdd9d1a9a25f233b79467bf9c4735217a..f567e78264061b03e3fe325a42b877b0ca8b6fca 100644 (file)
@@ -30,7 +30,6 @@
 /* flags to update_utmp*/
 #define PTY_TTYSLOT_USABLE (0x1)
 #define PTY_UTMP_USERNAME_VALID (0x2)
-#ifdef __STDC__ /* use prototypes */
 
 long pty_init(void);
 long pty_getpty ( int *fd, char *slave, int slavelength);
@@ -39,9 +38,10 @@ long pty_open_slave (const char *slave, int *fd);
 long pty_open_ctty (const char *slave, int *fd);
 
 long pty_initialize_slave ( int fd);
-long pty_update_utmp (int process_type,int pid,  char *user, char *line, char *host, int flags);
+long pty_update_utmp(int process_type, int pid, const char *user,
+                    const char *line, const char *host, int flags);
 
-long pty_logwtmp (char *tty, char * user, char *host);
+long pty_logwtmp(const char *tty, const char *user, const char *host);
 
 long pty_cleanup(char *slave, int pid, int update_utmp);
 
@@ -50,18 +50,5 @@ struct sockaddr;
 #endif
 
 long pty_make_sane_hostname(const struct sockaddr *, int, int, int, char **);
-#else /*__STDC__*/
-long pty_init();
-long pty_getpty();
-
-long pty_open_slave();
-long pty_open_ctty();
-long pty_initialize_slave();
-
-long pty_update_utmp();
-long pty_logwtmp();
-long pty_cleanup();
-long pty_make_sane_hostname();
-#endif /* __STDC__*/
 #define __LIBPTY_H__
 #endif
index e3611f6a915b840e4835bc95f791a2ca712743d7..684033ed28e60dede0758c065b7ae7109e1d4a57 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * pty_logwtmp: Implement the logwtmp function if not present.
  *
- * Copyright 1995 by the Massachusetts Institute of Technology.
- *
+ * Copyright 1995, 2001 by the Massachusetts Institute of Technology.
  * 
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
 #include "libpty.h"
 #include "pty-int.h"
 
+#if defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)
+#ifdef HAVE_SETUTXENT
+#define PTY_STRUCT_UTMPX struct utmpx
+#else
+#define PTY_STRUCT_UTMPX struct utmp
+#endif
+
+long
+pty_logwtmp(const char *tty, const char *user, const char *host)
+{
+    PTY_STRUCT_UTMPX utx;
+    int loggingin;
+    size_t len;
+    const char *cp;
+    char utmp_id[5];
+
+#ifdef HAVE_LOGWTMP
+    logwtmp(tty,user,host);
+    return 0;
+#else
+
+    loggingin = (user[0] == '\0');
+
+    memset(&utx, 0, sizeof(utx));
+    strncpy(utx.ut_line, tty, sizeof(utx.ut_line));
+    strncpy(utx.ut_user, user, sizeof(utx.ut_user));
+#if (defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMPX_UT_HOST))       \
+       || (!defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMP_UT_HOST))
+    strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+    utx.ut_host[sizeof(utx.ut_host) - 1] = '\0';
+#endif
+    utx.ut_pid = (loggingin ? getpid() : 0);
+    utx.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
+
+    len = strlen(tty);
+    if (len >= 2)
+       cp = tty + len - 2;
+    else
+       cp = tty;
+    sprintf(utmp_id, "kr%s", cp);
+    strncpy(utx.ut_id, utmp_id, sizeof(utx.ut_id));
+
+#ifdef HAVE_SETUTXENT
+    return ptyint_update_wtmpx(&utx);
+#else
+    return ptyint_update_wtmp(&utx);
+#endif
+
+#endif /* !HAVE_LOGWTMP */
+}
+
+#else  /* !(defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)) */
+
+long
+pty_logwtmp(const char *tty, const char *user, const char *host)
+{
+    struct utmp ut;
+
+#ifdef HAVE_LOGWTMP
+    logwtmp(tty,user,host);
+    return 0;
+#else
+
+    memset(&ut, 0, sizeof(ut));
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+    ut.ut_host[sizeof(ut.ut_host) - 1] = '\0';
+#endif
+    strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
+    strncpy(ut.ut_name, user, sizeof(ut.ut_name));
+    return ptyint_update_wtmp(&ut);
+
+#endif /* !HAVE_LOGWTMP */
+}
+
+#endif /* !(defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)) */
+
+#if 0
 long pty_logwtmp (tty, user, host )
     char *user, *tty, *host;
 {
@@ -62,4 +139,4 @@ long pty_logwtmp (tty, user, host )
     return ptyint_update_wtmp(&ut, host, user);
 #endif /*HAVE_LOGWTMP*/
 }
-
+#endif
index d183cf28fbc566ddc38c38ba557481d6ccc0ab0a..a955533dc444c4a8e0c419ec9d774c06650e3921 100644 (file)
@@ -95,18 +95,14 @@ extern void getutmpx (const struct utmp *, struct utmpx *);
 #endif
 
 /* Internal functions */
-#ifdef __STDC__
 long ptyint_void_association(void);
 long ptyint_open_ctty (char *slave, int *fd);
-long ptyint_update_wtmp (struct utmp *ut, char *host, char *user);
-
+#ifdef HAVE_SETUTXENT
+long ptyint_update_wtmpx(struct utmpx *utx);
+#else
+long ptyint_update_wtmp(struct utmp *ut);
+#endif
 void ptyint_vhangup(void);
-#else /*__STDC__*/
-
-long ptyint_void_association();
-void ptyint_vhangup();
-long ptyint_update_wtmp();
-#endif /* __STDC__*/
 
 #define __PTY_INT_H__
 #endif
index d7512fa55b1041b8eee6e755975aca69ece4861c..753683ccc8ed2dc7377684eda1df58ab50c1a377 100644 (file)
@@ -81,7 +81,7 @@ pty_make_sane_hostname(const struct sockaddr *addr, int maxlen,
 #else
     struct hostent *hp;
 #endif
-#ifndef NO_UT_HOST
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
     struct utmp ut;
 #else
     struct utmpx utx;
@@ -94,7 +94,7 @@ pty_make_sane_hostname(const struct sockaddr *addr, int maxlen,
     if (maxlen && maxlen < 16)
        /* assume they meant 16, otherwise IP addr won't fit */
        maxlen = 16;
-#ifndef NO_UT_HOST
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
     ut_host_len = sizeof (ut.ut_host);
 #else
     ut_host_len = sizeof (utx.ut_host);
index 173e3e2dd02261307671690b9c6b0677f5d4b738..fc5edfd72c59c5a0e769f1e3451f5ed591e80600 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * pty_update_utmp: Update or create a utmp entry
  * 
- * Copyright 1995 by the Massachusetts Institute of Technology.
- *
+ * Copyright 1995, 2001 by the Massachusetts Institute of Technology.
  * 
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
  * M.I.T. makes no representations about the suitability
  * of this software for any purpose.  It is provided "as is" without
  * express or implied warranty.
- * 
+ */
+
+/*
+ * Rant about the historical vagaries of utmp:
+ * -------------------------------------------
+ *
+ * There exist many subtly incompatible incarnations of utmp, ranging
+ * from BSD to System V to Unix98 and everywhere in between.  This
+ * rant attempts to collect in one place as much knowledge as possible
+ * about this portability nightmare.
+ *
+ * BSD:
+ * ----
+ *
+ * The simplest (and earliest?) case is 4.x BSD utmp/wtmp.  There are
+ * no auxiliary files.  There is only a struct utmp, declared in
+ * utmp.h.  Its contents usually include:
+ *
+ *     char ut_line[]
+ *     char ut_name[]
+ *     char ut_host[]
+ *     long ut_time
+ *
+ * The meanings of these fields follows their names reasonbly well.
+ * The ut_line field usually is the pathname of the tty device
+ * associated with the login, with the leading "/dev/" stripped off.
+ *
+ * It is believed that ut_host is nul-terminated, while the other
+ * strings are merely nul-padded.
+ *
+ * Generally, ut_name is an empty string for a logout record in both
+ * utmp and wtmp.  For entries made by the window system or other
+ * terminal emulation stuff, ut_host is an empty string (at least
+ * under SunOS 4.x, it seems).  The macro nonuser() is used to
+ * determine this if a utmp entry is made by the window system on at
+ * least SunOS 4.x.
+ *
+ * It is not know whether the login program or init is responsible for
+ * clearing the utmp entry, or for entering a logout record in wtmp.
+ * It is likely the case that init cleans up for processes that it is
+ * itself responsible for starting.
+ *
+ * Old (c. 1984) System V:
+ * -----------------------
+ *
+ * This is partially conjecture, based on some reading of
+ * /usr/xpg2include/utmp.h on a SunOS 4.x system.  There appears to
+ * only be a struct utmp, declared in utmp.h.  It is likely used for
+ * both utmp and wtmp files.  It is quite likely that the utmp is only
+ * supposed to be accessed via the getutline()/pututline() API.  The
+ * contents of struct utmp seem to include:
+ *
+ *     char    ut_user[]
+ *     char    ut_id[]
+ *     char    ut_line[]
+ *     short   ut_pid
+ *     short   ut_type
+ *     struct exit_status ut_exit
+ *     time_t  ut_time
+ *
+ * On these systems, ut_name is often #define'ed to be ut_user to be
+ * somewhat compatible with the BSD-style utmp.  Note that there is
+ * not necessarily a ut_host field in this utmp structure.
+ *
+ * The ut_id field bears some explanation.  The systems that use this
+ * style of utmp also use a sysV-ish init, which starts processes out
+ * of /etc/inittab rather than /etc/ttys, and has the concept of
+ * runlevels.  The first field in each line of /etc/inittab contains a
+ * unique ID field.  init probably gets really confused if there are
+ * conflicts here.  Every process that init starts gets its own entry
+ * written to utmp.
+ *
+ * It is possible for multiple entries to have the same ut_line but
+ * different ut_id values, since the sysadmin will be responsible for
+ * assigning values to ut_id.  Usually, ut_id is four characters,
+ * while the permissible unique ID values for entries in /etc/inittab
+ * are constrained to two characters, but this is not always the
+ * case.  In the case where we are emulating the vendor's login
+ * program and being run out of getty, we need to account for which
+ * value of ut_id was used by the getty, since pututline() will search
+ * based on ut_id and not ut_line for some reason.
+ *
+ * The ut_pid and ut_type fields are used for bookkeeping by init.
+ * The ut_type field gets the value INIT_PROCESS for processes started
+ * by init.  It gets the value LOGIN_PROCESS if it is a process that
+ * is prompting for a login name, and it gets the value USER_PROCESS
+ * for an actual valid login.  When the process dies, either init
+ * cleans up after it and records a DEAD_PROCESS entry in utmp, or the
+ * process itself does so.  It's not completely clear which actually
+ * happens, though it is quite possible that init only cleans up after
+ * processes that it starts itself.
+ *
+ * Other values of ut_type exist; they're largely internal bookkeeping
+ * for init's runlevels and such, and don't really interest this
+ * library at all.
+ *
+ * The ut_exit field contains the following members:
+ *
+ *     short   e_termination
+ *     short   e_exit
+ *
+ * It is not clear how these values are used; presumably they record
+ * the process termination status of dead processes.
+ *
+ * There is no uniform API for manipulating wtmp on systems that use
+ * this sort of utmp structure; it can be assumed that the structure
+ * can be directly written to the wtmp file.
+ *
+ * Unix98:
+ * -------
+ *
+ * This description also likely applies to later System V derivatives
+ * as well as systems conforming to earlier X/Open standards such as
+ * XPG4.  There is a new header, utmpx.h, which defines a struct utmpx
+ * and a new getutxline()/pututxline() API for accessing it.  Some
+ * systems actually have a utmpx file on disk; others use the utmpx
+ * API to access a file named utmp, just to further confuse matters.
+ *
+ * The utmpx structure is guaranteed (by Unix98) to contain at least
+ * the following:
+ *
+ *     char    ut_user[]
+ *     char    ut_line[]
+ *     char    ut_id[]
+ *     pid_t   ut_pid
+ *     short   ut_type
+ *     struct timeval ut_tv
+ *
+ * It is not guaranteed to contain, but often does contain, the
+ * following:
+ *
+ *     char    ut_host[]
+ *     int     ut_syslen
+ *     int     ut_session
+ *     struct exit_status ut_exit
+ *
+ * The ut_syslen field, on systems that contain it, contains the
+ * number of significant characters in ut_host, including the
+ * terminating nul character.
+ *
+ * The main difference between this struct utmpx and the struct utmp
+ * used by early sysV derivatives is the change from a time_t or long
+ * for ut_time to a struct timeval for ut_tv.
+ *
+ * Comments in various header files imply that ut_session is used for
+ * window systems, but it's not clear how.  Perhaps it contains the
+ * session ID of the session running the window system, e.g. the xdm
+ * or X server on an X11 system.
+ *
+ * Most of the description of the earlier sysV format probably applies
+ * here, with suitable changes of names.  On systems that maintain
+ * utmpx and utmp files in parallel, it is assumed that using the
+ * pututxline() API is sufficient to keep them in sync.  There are no
+ * known counterexamples to this.
+ *
+ * Nevertheless, there are, on some systems, API functions getutmp()
+ * and getutmpx() that appear to convert from struct utmpx to struct
+ * utmp and vice versa.  This could be useful when there is a wtmp
+ * file but not a corresponding wtmpx file.
+ *
+ * Incidentally, ut_exit is sometimes present in the struct utmp but
+ * not the struct utmpx for a given system.  Sometimes, it exists in
+ * both, but contains differently named members.  It's probably one of
+ * the least portable pieces in this whole mess.
+ *
+ * Known Quirks of Specific OSes:
+ * ------------------------------
+ *
+ * Solaris 2.x:
+ *
+ * Has utmpd, which will automatically clean up utmpx, utmp, wtmpx,
+ * wtmp after process termination, provided that pututxline() was
+ * used.
+ *
+ * Solaris 8 seems to have a bug in utmpname() that causes
+ * garbage filenames to be generated.  Solaris 7 (and possibly Solaris
+ * 8) have a bug in utmpxname() that prevents them from looking at
+ * anything other than /var/adm/utmpx, it seems.  For some reason,
+ * though, utmpname() goes and looks at the corresponding utmpx file.
+ *
+ * Solaris 7 (and may be 8 as well) has a bug in pututline() that
+ * interacts badly with prior invocation of getutline(): if
+ * getutline() finds an entry, calling pututline() without first
+ * calling setutent() will overwrite the record following the one that
+ * was intended.
+ *
+ * Also, ut_exit in utmpx contains ut_e_termination and
+ * ut_e_exit (otherwise it contains the expected e_termination and
+ * e_exit) only if _XPG4_2 is defined and __EXTENSIONS__ is not, which
+ * is not a compilation environment we're likely to encourage.  The
+ * ut_exit field of utmp contains the expected fields.
+ *
+ * If _XPG4_2 is not defined or __EXTENSIONS__ is defined, the
+ * functions getutmp(), getutmpx(), updwtmp(), and updwtmpx() are
+ * available, as well as the undocumented functions makeutx() and
+ * modutx().
+ *
+ * All the files utmp, utmpx, wtmp, and wtmpx exist.
+ *
+ * HP-UX 10.x:
+ *
+ * When init cleans up after processes it doesn't start, if the
+ * process being cleaned up after allocated a pty, ut_line gets a
+ * prefix of "pty/" for no readily apparent reason.  This causes
+ * ut_line of logout entries in wtmp to not match that of their login
+ * entries, confusing various utilities.
+ *
+ * Uses four-character unique IDs for /etc/inittab, which means that
+ * programs not running out of init should use two-character ut_id
+ * fields to avoid conflict.
+ *
+ * In utmpx, ut_exit contains __e_termination and __e_exit, while
+ * ut_exit in utmp contains the expected fields.
+ *
+ * There is no wtmpx file, despite there being utmp and utmpx files.
+ *
+ * Irix 6.x:
+ *
+ * In utmpx, ut_exit contains __e_termination and __e_exit, which get
+ * #define aliases e_termination and e_exit if _NO_XOPEN4 is true.
+ * Curiously enough, utmp.h declares ut_exit to have __e_termination
+ * and __e_exit as well, but does #define e_termination
+ * __e_termination, etc. if another header (utmpx.h) hasn't already
+ * declared struct __exit_status.  It seems that the default
+ * compilation environment has the effect of making _NO_XOPEN4 true
+ * though.
+ *
+ * If _NO_XOPEN4 is true, getutmp(), getutmpx(), updwtmp(), and
+ * updwtmpx() are available, as well as the undocumented functions
+ * makeutx() and modutx().
+ *
+ * All the files utmp, utmpx, wtmp, and wtmpx exist.
+ *
+ * Tru64 Unix 4.x:
+ *
+ * In utmpx, ut_exit contains ut_termination and ut_exit, while utmp
+ * contains the expected fields.  The files utmp and wtmp seem to
+ * exist, but not utmpx or wtmpx.
+ *
+ * AIX 4.3.x:
+ *
+ * The ut_exit field seems to exist in utmp, but not utmpx. The files
+ * utmp and wtmp seem to exist, but not utmpx, or wtmpx.
+ *
+ * libpty Implementation Decisions:
+ * --------------------------------
+ *
+ * We choose to use the pututxline() whenever possible, falling back
+ * to pututline() and calling write() to write out struct utmp if
+ * necessary.  The code to handle pututxline() and pututline() is
+ * rather similar, since the structure members are quite similar, and
+ * we make the assumption that it will never be necessary to call
+ * both.  This allows us to avoid duplicating lots of code, by means
+ * of some slightly demented macros.
+ *
+ * If neither pututxline() nor pututline() are available, we assume
+ * BSD-style utmp files and behave accordingly, writing the structure
+ * out to disk ourselves.
+ *
+ * On systems where updwtmpx() or updwtmp() are available, we use
+ * those to update the wtmpx or wtmp file.  When they're not
+ * available, we write the utmpx or utmp structure out to disk
+ * ourselves, though sometimes conversion from utmpx to utmp format is
+ * needed.
  */
 
 #include <com_err.h>
 #ifndef UTMP_FILE
 #define        UTMP_FILE       "/etc/utmp"
 #endif
-#ifndef NO_UT_PID
-#define WTMP_REQUIRES_USERNAME
-#endif
-long pty_update_utmp (process_type, pid, username, line, host, flags)
-    int process_type;
-    int pid;
-    char *username, *line, *host;
-    int flags;
-{
-    struct utmp ent, ut;
-#ifndef HAVE_SETUTENT
-    struct stat statb;
-    int tty, fd;
-#endif
+
+/*
+ * The following grossness exists to avoid duplicating lots of code
+ * between the cases where we have an old-style sysV utmp and where we
+ * have a modern (Unix98 or XPG4) utmpx.  See the above history rant
+ * for further explanation.
+ */
+#if defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)
 #ifdef HAVE_SETUTXENT
-    struct utmpx utx;
-#endif
-#ifndef NO_UT_PID
-    char *tmpx;
-    char utmp_id[5];
+#define PTY_STRUCT_UTMPX struct utmpx
+#define PTY_SETUTXENT setutxent
+#define PTY_GETUTXLINE getutxline
+#define PTY_PUTUTXLINE pututxline
+#define PTY_ENDUTXENT endutxent
+#else
+#define PTY_STRUCT_UTMPX struct utmp
+#define PTY_SETUTXENT setutent
+#define PTY_GETUTXLINE getutline
+#define PTY_PUTUTXLINE pututline
+#define PTY_ENDUTXENT endutent
 #endif
-    char userbuf[32];
 
-    strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
-    ent.ut_time = time(0);
-#ifdef NO_UT_PID
-    if (process_type == PTY_LOGIN_PROCESS)
+static int better(const PTY_STRUCT_UTMPX *, const PTY_STRUCT_UTMPX *,
+                 const PTY_STRUCT_UTMPX *);
+static PTY_STRUCT_UTMPX *best_utxline(const PTY_STRUCT_UTMPX *);
+
+/*
+ * Utility function to determine whether A is a better match for
+ * SEARCH than B.  Should only be called by best_utxline().
+ */
+static int
+better(const PTY_STRUCT_UTMPX *search,
+       const PTY_STRUCT_UTMPX *a, const PTY_STRUCT_UTMPX *b)
+{
+    if (strncmp(a->ut_id, b->ut_id, sizeof(b->ut_id))) {
+       /* different UT_IDs; find the right one */
+       if (a->ut_type == LOGIN_PROCESS) {
+           if (b->ut_type != LOGIN_PROCESS) {
+               /* prefer LOGIN_PROCESS */
+               return 1;
+           } else if (search->ut_pid == a->ut_pid
+                      && a->ut_pid != b->ut_pid) {
+               /*
+                * Prefer entry whose ut_pid matches that of SEARCH,
+                * if all else is the same.  Note that this will fail
+                * in the case of login.krb5 called from krlogind,
+                * etc., since the login.krb5 will have a different
+                * pid from its parent.  Consequently, we save this
+                * test for last, in order to catch the case of
+                * login.krb5 being called from getty.
+                */
+               return 1;
+           }
+       }
+       return 0;
+    } else {
+       /*
+        * Bad juju.  We shouldn't get two entries with identical
+        * ut_id fields for the same value of ut_line.  pututxline()
+        * will probably pick the first entry, in spite of the strange
+        * state of utmpx, if we rewind with setutxent() first.
+        *
+        * For now, return 0, to force the earlier entry to be used.
+        */
        return 0;
-#else /* NO_UT_PID */
-    ent.ut_pid = pid;
+    }
+}
+
+/*
+ * This expects to be called with SEARCH pointing to a struct utmpx
+ * with its ut_type equal to USER_PROCESS or DEAD_PROCESS, since if
+ * we're making a LOGIN_PROCESS entry, we presumably don't care about
+ * preserving existing state.  At the very least, the ut_pid, ut_line,
+ * and ut_type fields must be filled in by the caller.
+ */
+static PTY_STRUCT_UTMPX *
+best_utxline(const PTY_STRUCT_UTMPX *search)
+{
+    PTY_STRUCT_UTMPX utxtmp, *utxp;
+    int i, best;
+
+    i = best = 0;
+    memset(&utxtmp, 0, sizeof(utxtmp));
+
+    PTY_SETUTXENT();
+    utxp = PTY_GETUTXLINE(search);
+    if (utxp == NULL)
+       return NULL;
+    utxtmp = *utxp;
+
+    for (;;) {
+       memset(utxp, 0, sizeof(*utxp));
+       utxp = PTY_GETUTXLINE(search);
+       if (utxp == NULL)
+           break;
+       i++;
+       if (better(search, utxp, &utxtmp)) {
+           utxtmp = *utxp;
+           best = i;
+       }
+    }
+    PTY_SETUTXENT();
+    for (i = 0; i <= best; i++) {
+       if (utxp != NULL)
+           memset(utxp, 0, sizeof(*utxp));
+       utxp = PTY_GETUTXLINE(search);
+    }
+    PTY_ENDUTXENT();
+    return utxp;
+}
+
+long
+pty_update_utmp(int process_type, int pid, const char *username,
+                   const char *line, const char *host, int flags)
+{
+    PTY_STRUCT_UTMPX utx, *utxtmp;
+    const char *cp;
+    size_t len;
+    char utmp_id[5];
+
+    /*
+     * Zero things out in case there are fields we don't handle here.
+     * They tend to be non-portable anyway.
+     */
+    memset(&utx, 0, sizeof(utx));
+    utxtmp = NULL;
+    cp = line;
+    /*
+     * XXX For some reason HP-UX init uses a prefix of "pty/" when
+     * writing the process termination record to utmp and wtmp if the
+     * line is a pty.  Not sure why.  Native HP-UX telnetd appears to
+     * write its own process termination record without the "pty/"
+     * prefix, and init or whatever doesn't clean up after it.
+     */
+    if (strncmp(cp, "/dev/", sizeof("/dev/") - 1) == 0)
+       cp += sizeof("/dev/") - 1;
+    strncpy(utx.ut_line, cp, sizeof(utx.ut_line));
+    utx.ut_pid = pid;
     switch (process_type) {
     case PTY_LOGIN_PROCESS:
-       ent.ut_type = LOGIN_PROCESS;
+       utx.ut_type = LOGIN_PROCESS;
        break;
     case PTY_USER_PROCESS:
-       ent.ut_type = USER_PROCESS;
+       utx.ut_type = USER_PROCESS;
        break;
     case PTY_DEAD_PROCESS:
-       ent.ut_type = DEAD_PROCESS;
+       utx.ut_type = DEAD_PROCESS;
        break;
     default:
        return PTY_UPDATE_UTMP_PROCTYPE_INVALID;
     }
-#endif /*NO_UT_PID*/
+    /*
+     * Get existing utmpx entry for LINE, if any, so we can copy some
+     * stuff from it.  This is particularly important if we're running
+     * out of getty, since getty will have written the entry for the
+     * line with ut_type == LOGIN_PROCESS, and what it has recorded in
+     * ut_id may not be what we come up with, since that's up to the
+     * whim of the sysadmin who writes the inittab entry.
+     *
+     * We make the assumption that getty constructs ut_line the same
+     * way that we do, which may be unwarranted.
+     *
+     * It seems that getty will find its ut_id by means of searching
+     * for a utmpx entry of type INIT_PROCESS containing getty's pid
+     * in ut_pid, though that is largely conjecture at the moment.
+     * This should be irrelevant for this library, since none of its
+     * callers should attempt to be a replacement for getty.
+     */
+    if (process_type != PTY_LOGIN_PROCESS)
+       utxtmp = best_utxline(&utx);
 
-#ifndef NO_UT_HOST
-    if (host)
-       strncpy(ent.ut_host, host, sizeof(ent.ut_host));
+#ifdef HAVE_SETUTXENT
+    if (gettimeofday(&utx.ut_tv, NULL))
+       return errno;
+#else
+    (void)time(&utx.ut_time);
+#endif
+    /*
+     * On what system is there not ut_host?  Unix98 doesn't mandate
+     * this field, but we have yet to see a system that supports utmpx
+     * that doesn't have it.  For what it's worth, some ancient utmp
+     * headers on svr4 systems imply that there's no ut_host in struct
+     * utmp...
+     */
+#if (defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMPX_UT_HOST))    \
+       || (!defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMP_UT_HOST))
+    if (host) {
+       strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+       /* Unlike other things in utmpx, ut_host is nul-terminated? */
+       utx.ut_host[sizeof(utx.ut_host) - 1] = '\0';
+    } else
+       utx.ut_host[0] = '\0';
+#if (defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMPX_UT_SYSLEN))  \
+       || (!defined (HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMP_UT_SYSLEN))
+    if (host != NULL)
+       utx.ut_syslen = strlen(utx.ut_host) + 1;
     else
-       ent.ut_host[0] = '\0';
+       utx.ut_syslen = 0;
 #endif
-
-#ifndef NO_UT_PID
-    if (!strcmp (line, "/dev/console")) {
-#if (defined(sun) && defined(__SVR4))
-      strncpy (ent.ut_id, "co", 4);
-#else
-      strncpy (ent.ut_id, "cons", 4);
 #endif
-    } else {
-      tmpx = line + strlen(line)-1;
-      if (*(tmpx-1) != '/') tmpx--; /* last two characters, unless it's a / */
+
+    /* XXX deal with ut_addr? */
+
+    utx.ut_id[0] = '\0';
+
+    if (utxtmp != NULL) {
+       /*
+        * For entries not of type LOGIN_PROCESS, override some stuff
+        * with what was in the previous entry we found, if any.
+        */
+       strncpy(utx.ut_id, utxtmp->ut_id, sizeof(utx.ut_id));
+       utx.ut_pid = utxtmp->ut_pid;
+    }
+
+    if (utx.ut_id[0] == '\0') {
+       len = strlen(line);
+       if (len >= 2) {
+           cp = line + len - 1;
+           if (*(cp - 1) != '/')
+               cp--;           /* last two characters, unless it's a / */
+       } else
+           cp = line;
+       /*
+        * HP-UX has mostly 4-character inittab ids, while most other
+        * sysV variants use only 2-charcter inittab ids, so to avoid
+        * conflicts, we pick 2-character ut_ids for our own use.  We
+        * may want to feature-test for this, but it would be somewhat
+        * of a pain, and would eit cross-compiling.
+        */
 #ifdef __hpux
-      strcpy(utmp_id, tmpx);
+       strcpy(utmp_id, cp);
 #else
-      sprintf(utmp_id, "kl%s", tmpx);
+       sprintf(utmp_id, "kl%s", cp);
 #endif
-      strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
+       strncpy(utx.ut_id, utmp_id, sizeof(utx.ut_id));
     }
-    strncpy(ent.ut_user, username, sizeof(ent.ut_user));
-#else
-    strncpy(ent.ut_name, username, sizeof(ent.ut_name));
-#endif
-    if(username[0])
-       strncpy(userbuf, username, sizeof(userbuf));
-    else userbuf[0] = '\0';
-
-#ifdef HAVE_SETUTENT
-
-    utmpname(UTMP_FILE);
-    setutent();
-/* If we need to preserve the user name in the wtmp structure and
- * Our flags tell us we can obtain it from the utmp and we succeed in
- * obtaining it, we then save the utmp structure we obtain, write
- * out the utmp structure and change the username pointer so  it is used by
- * update_wtmp.*/
-#ifdef WTMP_REQUIRES_USERNAME
-    if (( !username[0]) && (flags&PTY_UTMP_USERNAME_VALID)
-       &&line)  
-       {
-         struct utmp *utptr;
-         strncpy(ut.ut_line, line, sizeof(ut.ut_line));
-         utptr = getutline(&ut);
-         if (utptr)
-           strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
-       }
-#endif
+    strncpy(utx.ut_user, username, sizeof(utx.ut_user));
+
+    PTY_SETUTXENT();
+    PTY_PUTUTXLINE(&utx);
+    PTY_ENDUTXENT();
+
+    /* Don't record LOGIN_PROCESS entries. */
+    if (process_type == PTY_LOGIN_PROCESS)
+       return 0;
+
+    if (username[0] == '\0'
+       && (flags & PTY_UTMP_USERNAME_VALID) && utxtmp != NULL)
+       /* Use the ut_user from the entry we looked up, if any. */
+       /* XXX Is this really necessary? */
+       strncpy(utx.ut_user, utxtmp->ut_user, sizeof(utx.ut_user));
 
-    pututline(&ent);
-    endutent();
-    
 #ifdef HAVE_SETUTXENT
-    setutxent();
-#ifdef HAVE_GETUTMPX
-    getutmpx(&ent, &utx);
-#else
-    /* For platforms like HPUX and Dec Unix which don't have getutmpx */
-    strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
-    strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
-    strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
-    utx.ut_pid = pid;          /* kludge for Irix, etc. to avoid trunc. */
-    utx.ut_type = ent.ut_type;
-#ifdef UT_EXIT_STRUCTURE_DIFFER
-    utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
+    return ptyint_update_wtmpx(&utx);
 #else
-/* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
-#ifdef __hpux  
-    utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
-    utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
-#else
-    /*xxx do nothing for now; we don't even know the structure member exists*/
-#endif
+    return ptyint_update_wtmp(&utx);
 #endif
-    utx.ut_tv.tv_sec = ent.ut_time;
-    utx.ut_tv.tv_usec = 0;
+}
+
+#else /* !(HAVE_SETUTXENT || HAVE_SETUTENT) */
+
+long
+pty_update_utmp(int process_type, int pid, const char *username,
+               const char *line, const char *host, int flags)
+{
+    struct utmp ent, ut;
+    int tty, lc, fd;
+    struct stat statb;
+
+    memset(&ent, 0, sizeof(ent));
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    strncpy(ent.ut_host, host, sizeof(ent.ut_host));
 #endif
-    if (host)
-      strncpy(utx.ut_host, host, sizeof(utx.ut_host));
-    else
-      utx.ut_host[0] = 0;
-    pututxline(&utx);
-    endutxent();
-#endif /* HAVE_SETUTXENT */
+    strncpy(ent.ut_name, username, sizeof(ent.ut_name));
+    strncpy(ent.ut_line, line, sizeof(ent.ut_line));
+    (void)time(&ent.ut_time);
 
-#else /* HAVE_SETUTENT */
-    if (flags&PTY_TTYSLOT_USABLE) 
+    if (flags & PTY_TTYSLOT_USABLE) 
        tty = ttyslot();
     else {
-      int lc;
-      tty = -1;
-      if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
-       return errno;
-      for (lc = 0;
-          lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
-          lc++) {
-       if (read(fd, (char *) &ut, sizeof(struct utmp)) != sizeof(struct utmp))
-         break;
-       if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
-         tty = lc;
-#ifdef WTMP_REQUIRES_USERNAME
-         if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
-           strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
-#endif
-         break;
+       tty = -1;
+       fd = open(UTMP_FILE, O_RDONLY);
+       if (fd == -1)
+           return errno;
+       for (lc = 0; ; lc++) {
+           if (lseek(fd, (off_t)(lc * sizeof(struct utmp)),
+                     SEEK_SET))
+               break;
+           if (read(fd, (char *) &ut, sizeof(struct utmp))
+               != sizeof(struct utmp))
+               break;
+           if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
+               tty = lc;
+               break;
+           }
        }
-      }
-      close(fd);
+       close(fd);
     }
-    
-    if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
-      (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
-      (void)write(fd, (char *)&ent, sizeof(struct utmp));
-      (void)close(fd);
+    if (tty > 0) {
+       fd = open(UTMP_FILE, OWRONLY);
+       if (fd == -1)
+           return 0;
+       if (fstat(fd, &statb)) {
+           close(fd);
+           return 0;
+       }
+       if (lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET)) {
+           close(fd);
+           return 0;
+       }
+       if (write(fd, (char *)&ent, sizeof(struct utmp))
+           != sizeof(struct utmp)) {
+           ftruncate(fd, statb.st_size);
+       }
+       close(fd);
     }
-
-
-#endif /* HAVE_SETUTENT */
-
     /* Don't record LOGIN_PROCESS entries. */
     if (process_type == PTY_LOGIN_PROCESS)
-      return 0;
+       return 0;
     else
-      return ptyint_update_wtmp(&ent, host, userbuf);
+       return ptyint_update_wtmp(&ent);
 }
+#endif
index cd714687c4fb73b4c44b4fae1d7b648d6f407b70..cb0129fd5c3f18e9b64fd70e5350694dfaf76870 100644 (file)
@@ -1,8 +1,7 @@
 /*
- * ptyint_update_utmp: Update or create a utmp entry
- *
- * Copyright 1995 by the Massachusetts Institute of Technology.
+ * ptyint_update_wtmp: Update wtmp.
  *
+ * Copyright 1995, 2001 by the Massachusetts Institute of Technology.
  * 
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -28,7 +27,7 @@
 #define WTMP_FILE _PATH_WTMP
 #endif
 
-#if !defined(WTMPX_FILE) && defined(_PATH_WTMPX) && defined(HAVE_UPDWTMPX)
+#if !defined(WTMPX_FILE) && defined(_PATH_WTMPX)
 #define WTMPX_FILE _PATH_WTMPX
 #endif
 
 #define        WTMP_FILE       "/usr/adm/wtmp"
 #endif
 
-#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-/* This is ugly, but the lack of standardization in the utmp/utmpx
- * space, and what glibc implements and doesn't make available, is
- * even worse.
- */
-#undef HAVE_UPDWTMPX           /* Don't use updwtmpx for glibc 2.1 */
-#endif
+#ifdef HAVE_SETUTXENT
 
-long ptyint_update_wtmp (ent , host, user)
-    struct utmp *ent;
-    char *host;
-    char *user;
+/*
+ * Welcome to conditional salad.
+ *
+ * This really wants to take a (const struct utmpx *) but updutmpx()
+ * on Solaris at least doesn't take a const argument.  *sigh*
+ */
+long
+ptyint_update_wtmpx(struct utmpx *ent)
 {
-#ifndef HAVE_UPDWTMP
-    int fd;
-    time_t uttime;
+#if !(defined(HAVE_UPDWTMPX) && defined(WTMPX_FILE))
     struct utmp ut;
-    struct stat statb;
 #endif
 
-#ifdef HAVE_UPDWTMPX
-    struct utmpx utx;
+#if defined(HAVE_UPDWTMPX) && defined(WTMPX_FILE)
+    updwtmpx(WTMPX_FILE, ent);
+    return 0;
+#else
 
-    getutmpx(ent, &utx);
-    if (host)
-      strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
-    else
-      utx.ut_host[0] = 0;
-    if (user)
-      strncpy(utx.ut_user, user, sizeof(utx.ut_user));
-    updwtmpx(WTMPX_FILE, &utx);
+#ifdef HAVE_GETUTMP
+    getutmp(ent, &ut);
+#else  /* Emulate getutmp().  Yuck. */
+    memset(&ut, 0, sizeof(ut));
+    strncpy(ut.ut_name, ent->ut_user, sizeof(ut.ut_name));
+    strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
+    ut.ut_time = ent->ut_tv.tv_sec;
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
+    ut.ut_host[sizeof(ut.ut_host) - 1] = '\0';
+#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
+    ut.ut_syslen = strlen(ut.ut_host) + 1;
 #endif
-
-#ifdef HAVE_UPDWTMP
-#ifndef HAVE_UPDWTMPX
-/* This is already performed by updwtmpx if present.*/
-    updwtmp(WTMP_FILE, ent);
-#endif /* HAVE_UPDWTMPX*/
-#else /* HAVE_UPDWTMP */
-
-    if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
-       if (!fstat(fd, &statb)) {
-         (void)memset((char *)&ut, 0, sizeof(ut));
-#ifdef __hpux
-         strncpy (ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
 #endif
-         (void)strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
-         (void)strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
-#ifndef NO_UT_HOST
-         (void)strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
+#ifdef HAVE_STRUCT_UTMP_UT_ID
+    strncpy(ut.ut_id, ent->ut_id, sizeof(ut.ut_id));
 #endif
-         (void)time(&uttime);
-         ut.ut_time = uttime;
-#if defined(HAVE_GETUTENT) && defined(USER_PROCESS)
-         if (ent->ut_name) {
-           if (!ut.ut_pid)
-             ut.ut_pid = getpid();
-#ifndef __hpux
-           ut.ut_type = USER_PROCESS;
-#else
-           ut.ut_type = ent->ut_type;
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+    ut.ut_pid = ent->ut_pid;
 #endif
-         } else {
-#ifdef EMPTY
-           ut.ut_type = EMPTY;
-#else
-           ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
-#endif     
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    ut.ut_type = ent->ut_type;
+#endif
+#if defined(PTY_UTMP_E_EXIT) && defined(PTY_UTMPX_E_EXIT)
+    ut.ut_exit.PTY_UTMP_E_EXIT = ent->ut_exit.PTY_UTMPX_E_EXIT;
+    ut.ut_exit.PTY_UTMP_E_TERMINATION =
+       ent->ut_exit.PTY_UTMPX_E_TERMINATION
+#endif
+#endif /* !HAVE_GETUTMP */
+
+    return ptyint_update_wtmp(&ut);
+#endif /* !(defined(WTMPX_FILE) && defined(HAVE_UPDWTMPX)) */
+}
 
-         }
+#else  /* !HAVE_SETUTXENT */
+
+long
+ptyint_update_wtmp(struct utmp *ent)
+{
+#ifndef HAVE_UPDWTMP
+    int fd;
+    struct stat statb;
 #endif
-           if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
-               sizeof(struct utmp))
-             (void)ftruncate(fd, statb.st_size);
-       }
+
+#ifdef HAVE_UPDWTMP
+    updwtmp(WTMP_FILE, ent);
+#else
+    fd = open(WTMP_FILE, O_WRONLY | O_APPEND, 0);
+    if (fd != -1 && !fstat(fd, &statb)) {
+       if (write(fd, (char *)ent, sizeof(struct utmp))
+           != sizeof(struct utmp))
+           (void)ftruncate(fd, statb.st_size);
        (void)close(fd);
     }
-#endif /* HAVE_UPDWTMP */
-    return 0; /* no current failure cases; file not found is not failure!*/
-    
+#endif
+    /*
+     * no current failure cases; file not found is not failure!
+     */
+    return 0;
 }
 
+#endif