[hackers] [utmp] Fix portability problems || Roberto E. Vargas Caballero

From: <git_AT_suckless.org>
Date: Sat, 17 Aug 2013 19:04:43 +0200

commit f7dcd4d7f36a82128f339f6446e87a7520e252cc
Author: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
Date: Wed Aug 14 16:36:08 2013 +0200

    Fix portability problems
    
    utmp interface is a very system dependet part in Unix. There are
    three different interfaces: SystemV, POSIX and BSD, and they are
    incompatibles between them. Utmp was using POSIX interface, but
    not all the systems implement it (for examle OpenBSD doesn't it),
    so it is desirable add the code for the three interfaces. This
    patch adds this new code without using a ifdef hell.

diff --git a/Makefile b/Makefile
index 8c36390..a7c37ad 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -3,37 +3,39 @@
 
 include config.mk
 
-SRC = utmp.c
-OBJ = ${SRC:.c=.o}
+DIST = LICENSE Makefile config.mk utmp.1 utmp.c bsd.c posix.c
+VERSION = 0.2
 
-all: options utmp
+all: options utmp
 
 options:
         _AT_echo utmp build options:
         _AT_echo "CFLAGS = ${CFLAGS}"
+ _AT_echo "CPPFLAGS = ${CPPFLAGS}"
         _AT_echo "LDFLAGS = ${LDFLAGS}"
+ _AT_echo "LDLIBS = ${LDLIBS}"
         _AT_echo "CC = ${CC}"
 
 .c.o:
         _AT_echo CC $<
- _AT_${CC} -c ${CFLAGS} $<
+ _AT_${CC} $(CFLAGS) $(CPPFLAGS) -c $<
 
-${OBJ}: config.mk
-
-utmp: ${OBJ}
+utmp: $(OBJS)
         _AT_echo CC -o $@
- _AT_${CC} -o $@ ${OBJ} ${LDFLAGS}
+ _AT_$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
 
+distclean: clean
+ _AT_echo cleaning for distribution
+ _AT_rm config.mk
 clean:
         _AT_echo cleaning
- _AT_rm -f utmp ${OBJ} utmp-${VERSION}.tar.gz
+ _AT_rm -f utmp utmp-${VERSION}.tar.gz *.o
 
 dist: clean
         _AT_echo creating dist tarball
         _AT_mkdir -p utmp-${VERSION}
- _AT_cp -R LICENSE Makefile config.mk utmp.1 ${SRC} utmp-${VERSION}
- _AT_tar -cf utmp-${VERSION}.tar utmp-${VERSION}
- _AT_gzip utmp-${VERSION}.tar
+ _AT_cp -R $(DIST) utmp-${VERSION}
+ _AT_tar -cf - utmp-${VERSION} | gzip > utmp-${VERSION}.tar.gz
         _AT_rm -rf utmp-${VERSION}
 
 install: all
_AT_@ -43,7 +45,7 @@ install: all
         _AT_chmod 755 ${DESTDIR}${PREFIX}/bin/utmp
         _AT_chgrp ${GROUP} ${DESTDIR}${PREFIX}/bin/utmp
         _AT_chmod g+s ${DESTDIR}${PREFIX}/bin/utmp
- _AT_echo installing manual page to ${DESTDIR}${PREFIX}/man1
+ _AT_echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
         _AT_mkdir -p ${DESTDIR}${MANPREFIX}/man1
         _AT_sed "s/VERSION/${VERSION}/g" < utmp.1 > ${DESTDIR}${MANPREFIX}/man1/utmp.1
         _AT_chmod 644 ${DESTDIR}${MANPREFIX}/man1/utmp.1
_AT_@ -54,4 +56,4 @@ uninstall:
         _AT_echo removing manual page from ${DESTDIR}${PREFIX}/man1
         _AT_rm -f ${DESTDIR}${MANPREFIX}/man1/utmp.1
 
-.PHONY: all options clean dist install uninstall
+.PHONY: options clean dist install uninstall
diff --git a/README b/README
new file mode 100644
index 0000000..f578223
--- /dev/null
+++ b/README
_AT_@ -0,0 +1,22 @@
+
+utmp is a small program which update the utmp record of the
+current tty. It is designed for helping in some terminal emulators
+or session manager which lack support for it.
+
+Compile:
+-------
+
+There are three different interfaces to utmp; SystemV, BSD and POSIX.
+SystemV and POSIX are basically the same interface (POSIX has
+better definitons for utmp fields, like for example ut_pid which
+in some system was a short instead of a pid_t), but BSD is very
+different. utmp has implemented the three interfaces, and
+it supplies three different config files, so the user only has
+to rename the proper one to config.mk. It is also added a
+basic configure, which selects POSIX interface for all plataforms
+except for OpenBSD.
+
+ $ ./configure
+ $ make
+ # make install
+
diff --git a/bsd.c b/bsd.c
new file mode 100644
index 0000000..2c2a293
--- /dev/null
+++ b/bsd.c
_AT_@ -0,0 +1,61 @@
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <util.h>
+#include <grp.h>
+#include <utmp.h>
+#include <pwd.h>
+
+#include "utmp.h"
+
+extern void die(const char *fmt, ...);
+extern struct passwd *pass;
+extern gid_t egid, gid;
+static struct utmp utmp;
+
+void
+addutmp(void)
+{
+ unsigned ptyid;
+ char *pts, *cp, *host;
+
+
+ if (!(host = getenv("DISPLAY")))
+ host = "-";
+
+ if (strlen(pass->pw_name) > sizeof(utmp.ut_name))
+ die("incorrect username %s", pass->pw_name);
+
+ if ((pts = ttyname(STDIN_FILENO)) == NULL)
+ die("error getting pty name:%s", strerror(errno));
+
+ for (cp = pts + strlen(pts) - 1; isdigit(*cp); --cp)
+ /* nothing */;
+
+ ptyid = atoi(++cp);
+ if (ptyid > 999 || strlen(pts + 5) > sizeof(utmp.ut_line))
+ die("Incorrect pts name %s
", pts);
+
+ /* remove /dev/ from pts */
+ strncpy(utmp.ut_line, pts + 5, sizeof(utmp.ut_line));
+ strncpy(utmp.ut_name, pass->pw_name, sizeof(utmp.ut_name));
+ strncpy(utmp.ut_host, host, sizeof(utmp.ut_host));
+ time(&utmp.ut_time);
+
+ setgid(egid);
+ login(&utmp);
+ setgid(gid);
+}
+
+void
+delutmp(void)
+{
+ setgid(egid);
+ logout(utmp.ut_line);
+ setgid(gid);
+}
+
diff --git a/config.bsd b/config.bsd
new file mode 100644
index 0000000..86a49c0
--- /dev/null
+++ b/config.bsd
_AT_@ -0,0 +1,16 @@
+
+# Customize below to fit your system.
+GROUP = utmp
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+# flags
+CPPFLAGS += -DVERSION=\"${VERSION}\"
+LDLIBS += -lutil
+
+# Objects
+
+OBJS = utmp.o bsd.o
+
diff --git a/config.mk b/config.mk
deleted file mode 100644
index 08aa8b3..0000000
--- a/config.mk
+++ /dev/null
_AT_@ -1,23 +0,0 @@
-# utmp version
-VERSION = 0.1
-
-# Customize below to fit your system.
-
-GROUP = utmp
-
-# paths
-PREFIX = /usr/local
-MANPREFIX = ${PREFIX}/share/man
-
-# includes and libs
-INCS = -I. -I/usr/include
-LIBS = -L/usr/lib -lc
-
-# flags
-CPPFLAGS = -DVERSION=\"${VERSION}\"
-CFLAGS += -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
-LDFLAGS += -s ${LIBS}
-
-# compiler and linker
-CC ?= cc
-
diff --git a/config.posix b/config.posix
new file mode 100644
index 0000000..8d8c8c1
--- /dev/null
+++ b/config.posix
_AT_@ -0,0 +1,15 @@
+
+# Customize below to fit your system.
+GROUP = utmp
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+# flags
+CPPFLAGS += -DVERSION=\"${VERSION}\"
+
+# Objects
+
+OBJS = utmp.o posix.o
+
diff --git a/config.sysv b/config.sysv
new file mode 100644
index 0000000..9820595
--- /dev/null
+++ b/config.sysv
_AT_@ -0,0 +1,15 @@
+
+# Customize below to fit your system.
+GROUP = utmp
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+# flags
+CPPFLAGS += -DUTMP_SYSTEMV -DVERSION=\"${VERSION}\"
+
+# Objects
+
+OBJS = utmp.o posix.o
+
diff --git a/configure b/configure
new file mode 100755
index 0000000..8ea80ba
--- /dev/null
+++ b/configure
_AT_@ -0,0 +1,10 @@
+#!/bin/sh
+
+case `uname` in
+OpenBSD)
+ ln config.bsd config.mk
+ ;;
+*)
+ ln config.posix config.mk
+ ;;
+esac
diff --git a/posix.c b/posix.c
new file mode 100644
index 0000000..df70929
--- /dev/null
+++ b/posix.c
_AT_@ -0,0 +1,124 @@
+
+#define _POSIX_C_SOURCE 200112L
+
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef UTMP_SYSTEMV
+#include <utmp.h>
+#define getutxent getutent
+#define getutxid getutid
+#define getutxline getutline
+#define pututxline pututline
+#define setutxent setutent
+#define endutxent endutent
+#define utmpx utmp
+#else
+#include <utmpx.h>
+#endif
+
+extern void die(const char *fmt, ...);
+static struct utmpx utmp;
+extern struct passwd *pass;
+extern gid_t egid, gid;
+
+
+/*
+ * From utmp(5)
+ * xterm and other terminal emulators directly create a USER_PROCESS
+ * record and generate the ut_id by using the string that suffix part of
+ * the terminal name (the characters following /dev/[pt]ty). If they find
+ * a DEAD_PROCESS for this ID, they recycle it, otherwise they create a new
+ * entry. If they can, they will mark it as DEAD_PROCESS on exiting and it
+ * is advised that they null ut_line, ut_time, ut_user, and ut_host as well.
+ */
+
+struct utmpx *
+findutmp(int type)
+{
+ struct utmpx *r;
+
+ utmp.ut_type = type;
+ setutxent();
+ for(;;) {
+ /*
+ * we can not use getutxline because we can search in
+ * DEAD_PROCESS to
+ */
+ if(!(r = getutxid(&utmp)))
+ break;
+ if(!strcmp(r->ut_line, utmp.ut_line))
+ break;
+ memset(r, 0, sizeof(*r)); /* for Solaris, IRIX64 and HPUX */
+ }
+ return r;
+}
+
+void
+addutmp(void)
+{
+ unsigned ptyid;
+ char *pts, *cp, buf[5] = {'x'};
+
+ if (strlen(pass->pw_name) > sizeof(utmp.ut_user))
+ die("incorrect username %s", pass->pw_name);
+
+ if ((pts = ttyname(STDIN_FILENO)) == NULL)
+ die("error getting pty name
");
+
+ for (cp = pts + strlen(pts) - 1; isdigit(*cp); --cp)
+ /* nothing */;
+
+ ptyid = atoi(++cp);
+ if (ptyid > 999 || strlen(pts + 5) > sizeof(utmp.ut_line))
+ die("Incorrect pts name %s
", pts);
+ sprintf(buf + 1, "%03d", ptyid);
+ strncpy(utmp.ut_id, buf, 4);
+
+ /* remove /dev/ part of the string */
+ strncpy(utmp.ut_line, pts + 5, sizeof(utmp.ut_line));
+
+ if(!findutmp(DEAD_PROCESS))
+ findutmp(USER_PROCESS);
+
+ utmp.ut_type = USER_PROCESS;
+ strncpy(utmp.ut_user, pass->pw_name, sizeof(utmp.ut_user));
+ utmp.ut_pid = getpid();
+ utmp.ut_tv.tv_sec = time(NULL);
+ utmp.ut_tv.tv_usec = 0;
+ /* don't use no standard fields host and session */
+
+ setgid(egid);
+ if(!pututxline(&utmp))
+ die("error adding utmp entry:%s", strerror(errno));
+ setgid(gid);
+ endutxent();
+}
+
+void
+delutmp(void)
+{
+ struct utmpx *r;
+
+ setutxent();
+ if((r = getutxline(&utmp)) != NULL) {
+ r->ut_type = DEAD_PROCESS;
+ r->ut_tv.tv_usec = r->ut_tv.tv_sec = 0;
+ setgid(egid);
+ if (!pututxline(r))
+ die("error removing utmp entry:%s", strerror(errno));
+ setgid(gid);
+ }
+ endutxent();
+}
+
diff --git a/utmp.1 b/utmp.1
index 7df9cf2..ec2409d 100644
--- a/utmp.1
+++ b/utmp.1
_AT_@ -20,8 +20,3 @@ are passed to the child shell.
 Written by Roberto E. Vargas Caballero
 .SH LICENSE
 See the LICENSE file for the terms of distribution.
-.SH BUGS
-utmp uses the posix interface defined in POSIX.1-2001. OpenBSD
-and others BSD system don't implement these standard functions, so
-this code could not be portable to them.
-
diff --git a/utmp.c b/utmp.c
index 013f020..6ab5289 100644
--- a/utmp.c
+++ b/utmp.c
_AT_@ -1,5 +1,4 @@
-/* See LICENSE for license details. */
-#define _POSIX_C_SOURCE 200112L
+
 
 #include <errno.h>
 #include <ctype.h>
_AT_@ -7,18 +6,21 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <time.h>
 
 #include <sys/types.h>
 #include <unistd.h>
-#include <utmpx.h>
 #include <pwd.h>
 #include <grp.h>
 #include <sys/wait.h>
 
-static struct utmpx utmp;
-static struct passwd *pass;
-static gid_t egid, gid;
+
+#ifndef _POSIX_SAVED_IDS
+#error "This program needs saved id behaviour"
+#endif
+
+
+struct passwd *pass;
+gid_t egid, gid;
 
 
 void
_AT_@ -27,110 +29,25 @@ die(const char *fmt, ...)
         va_list va;
         va_start(va, fmt);
         vfprintf(stderr, fmt, va);
+ putc('
', stderr);
         va_end(va);
         exit(EXIT_FAILURE);
 }
 
-/*
- * From utmp(5)
- * xterm and other terminal emulators directly create a USER_PROCESS
- * record and generate the ut_id by using the string that suffix part of
- * the terminal name (the characters following /dev/[pt]ty). If they find
- * a DEAD_PROCESS for this ID, they recycle it, otherwise they create a new
- * entry. If they can, they will mark it as DEAD_PROCESS on exiting and it
- * is advised that they null ut_line, ut_time, ut_user, and ut_host as well.
- */
-
-struct utmpx *
-findutmp(int type)
-{
- struct utmpx *r;
-
- utmp.ut_type = type;
- setutxent();
- for(;;) {
- /*
- * we can not use getutxline because we can search in
- * DEAD_PROCESS to
- */
- if(!(r = getutxid(&utmp)))
- break;
- if(!strcmp(r->ut_line, utmp.ut_line))
- break;
- memset(r, 0, sizeof(*r)); /* for Solaris, IRIX64 and HPUX */
- }
- return r;
-}
-
-void
-addutmp(int fd)
-{
- unsigned ptyid;
- char *pts, *cp, buf[5] = {'x'};
-
- if ((pts = ttyname(fd)) == NULL)
- die("error getting pty name
");
-
- for (cp = pts + strlen(pts) - 1; isdigit(*cp); --cp)
- /* nothing */;
-
- ptyid = atoi(++cp);
- if (ptyid > 999 || strlen(pts + 5) > sizeof(utmp.ut_line))
- die("Incorrect pts name %s
", pts);
- sprintf(buf + 1, "%03d", ptyid);
- strncpy(utmp.ut_id, buf, 4);
-
- /* remove /dev/ part of the string */
- strcpy(utmp.ut_line, pts + 5);
-
- if(!findutmp(DEAD_PROCESS))
- findutmp(USER_PROCESS);
-
- utmp.ut_type = USER_PROCESS;
- strcpy(utmp.ut_user, pass->pw_name);
- utmp.ut_pid = getpid();
- utmp.ut_tv.tv_sec = time(NULL);
- utmp.ut_tv.tv_usec = 0;
- /* don't use no standard fields host and session */
-
- setgid(egid);
- if(!pututxline(&utmp))
- perror("add utmp entry");
- setgid(gid);
- endutxent();
-}
-
-void
-delutmp(void)
-{
- struct utmpx *r;
-
- setutxent();
- if((r = getutxline(&utmp)) != NULL) {
- r->ut_type = DEAD_PROCESS;
- r->ut_tv.tv_usec = r->ut_tv.tv_sec = 0;
- setgid(egid);
- pututxline(r);
- setgid(gid);
- }
- endutxent();
-}
-
 int
 main(int argc, char *argv[])
 {
         int status;
         uid_t uid;
+ extern void addutmp(void), delutmp(void);
 
         egid = getegid();
         gid = getgid();
         setgid(gid);
 
         pass = getpwuid(uid = getuid());
- if(!pass || !pass->pw_name ||
- strlen(pass->pw_name) + 1 > sizeof(utmp.ut_user)) {
- die("Process is running with an incorrect uid %d
", uid);
- }
+ if (!pass || !pass->pw_name)
+ die("Process is running with an incorrect uid %d", uid);
 
         setenv("LOGNAME", pass->pw_name, 1);
         setenv("USER", pass->pw_name, 1);
_AT_@ -140,11 +57,11 @@ main(int argc, char *argv[])
         switch (fork()) {
         case 0:
                 execv(getenv("SHELL"), ++argv);
- die("error executing shell:%s
", strerror(errno));
+ die("error executing shell:%s", strerror(errno));
         case -1:
- die("error spawning child:%s
", strerror(errno));
+ die("error spawning child:%s", strerror(errno));
         default:
- addutmp(STDIN_FILENO);
+ addutmp();
                 if (wait(&status) == -1) {
                         fprintf(stderr, "error waiting child:%s
",
                                 strerror(errno));
_AT_@ -153,4 +70,3 @@ main(int argc, char *argv[])
         }
         return 0;
 }
-
Received on Sat Aug 17 2013 - 19:04:43 CEST

This archive was generated by hypermail 2.3.0 : Sat Aug 17 2013 - 19:12:09 CEST