URI:
       Initial commit of utmp(1). - utmp - simple login manager  
  HTML git clone git://git.suckless.org/utmp
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 014564adfe81bca6e03036ee6bc16ec6ab6029d1
  HTML Author: Christoph Lohmann <20h@r-36.net>
       Date:   Tue, 30 Oct 2012 06:37:48 +0100
       
       Initial commit of utmp(1).
       Diffstat:
         A LICENSE                             |      24 ++++++++++++++++++++++++
         A Makefile                            |      57 +++++++++++++++++++++++++++++++
         A config.mk                           |      23 +++++++++++++++++++++++
         A utmp.1                              |      27 +++++++++++++++++++++++++++
         A utmp.c                              |     156 +++++++++++++++++++++++++++++++
       
       5 files changed, 287 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/LICENSE b/LICENSE
       @@ -0,0 +1,24 @@
       +Copyright (c) 2012, Roberto E. Vargas Caballero <k0ga@shike2.com>
       +
       +Redistribution and use in source and binary forms, with or without
       +modification, are permitted provided that the following conditions are met:
       +    * Redistributions of source code must retain the above copyright
       +      notice, this list of conditions and the following disclaimer.
       +    * Redistributions in binary form must reproduce the above copyright
       +      notice, this list of conditions and the following disclaimer in the
       +      documentation and/or other materials provided with the distribution.
       +    * Neither the name of the copyright holder nor the names of its
       +      contributors may be used to endorse or promote products derived
       +      from this software without specific prior written permission.
       +
       +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   DIR diff --git a/Makefile b/Makefile
       @@ -0,0 +1,57 @@
       +# utmp - simple login
       +# See LICENSE file for copyright and license details.
       +
       +include config.mk
       +
       +SRC = utmp.c
       +OBJ = ${SRC:.c=.o}
       +
       +all: options utmp 
       +
       +options:
       +        @echo utmp build options:
       +        @echo "CFLAGS   = ${CFLAGS}"
       +        @echo "LDFLAGS  = ${LDFLAGS}"
       +        @echo "CC       = ${CC}"
       +
       +.c.o:
       +        @echo CC $<
       +        @${CC} -c ${CFLAGS} $<
       +
       +${OBJ}: config.mk
       +
       +utmp: ${OBJ}
       +        @echo CC -o $@
       +        @${CC} -o $@ ${OBJ} ${LDFLAGS}
       +
       +clean:
       +        @echo cleaning
       +        @rm -f utmp ${OBJ} utmp-${VERSION}.tar.gz
       +
       +dist: clean
       +        @echo creating dist tarball
       +        @mkdir -p utmp-${VERSION}
       +        @cp -R LICENSE Makefile config.mk utmp.1 ${SRC} st-${VERSION}
       +        @tar -cf utmp-${VERSION}.tar st-${VERSION}
       +        @gzip utmp-${VERSION}.tar
       +        @rm -rf utmp-${VERSION}
       +
       +install: all
       +        @echo installing executable file to ${DESTDIR}${PREFIX}/bin
       +        @mkdir -p ${DESTDIR}${PREFIX}/bin
       +        @cp -f utmp ${DESTDIR}${PREFIX}/bin
       +        @chmod 755 ${DESTDIR}${PREFIX}/bin/utmp
       +        @chmod g+s ${DESTDIR}${PREFIX}/bin/utmp
       +        @chgrp ${GROUP} ${DESTDIR}${PREFIX}/bin/utmp
       +        @echo installing manual page to ${DESTDIR}${PREFIX}/man1
       +        @mkdir -p ${DESTDIR}${MANPREFIX}/man1
       +        @sed "s/VERSION/${VERSION}/g" < utmp.1 > ${DESTDIR}${MANPREFIX}/man1/utmp.1
       +        @chmod 644 ${DESTDIR}${MANPREFIX}/man1/utmp.1
       +
       +uninstall:
       +        @echo removing executable file from ${DESTDIR}${PREFIX}/bin
       +        @rm -f ${DESTDIR}${PREFIX}/bin/utmp
       +        @echo removing manual page from ${DESTDIR}${PREFIX}/man1
       +        @rm -f ${DESTDIR}${MANPREFIX}/man1/utmp.1
       +
       +.PHONY: all options clean dist install uninstall
   DIR diff --git a/config.mk b/config.mk
       @@ -0,0 +1,23 @@
       +# 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
       +
   DIR diff --git a/utmp.1 b/utmp.1
       @@ -0,0 +1,27 @@
       +.TH UTMP 1 utmp\-VERSION
       +.SH NAME
       +utmp \- manage utmp entry for a session
       +.SH SYPNOSIS
       +.B utmp
       +.RB [
       +.IR shell\ arguments
       +.RB ]
       +.SH DESCRIPTION
       +.B utmp
       +adds an entry to utmp for a shell. It trusts the
       +.I SHELL
       +environment variable, and in case this one is not set, it gets the
       +user defined shell from the
       +.I /etc/passwd
       +file. All the arguments passed to
       +.B utmp
       +are passed to the child shell.
       +.SH AUTHORS
       +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.
       +
   DIR diff --git a/utmp.c b/utmp.c
       @@ -0,0 +1,156 @@
       +/* See LICENSE for license details. */
       +#define _POSIX_C_SOURCE        200112L
       +
       +#include <errno.h>
       +#include <ctype.h>
       +#include <stdarg.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>
       +#include <sys/wait.h>
       +
       +static struct utmpx utmp;
       +static struct passwd *pass;
       +static gid_t egid, gid;
       +
       +
       +void
       +die(const char *fmt, ...)
       +{
       +        va_list va;
       +        va_start(va, fmt);
       +        vfprintf(stderr, fmt, va);
       +        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\n");
       +
       +        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\n", 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;
       +
       +        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\n", uid);
       +        }
       +
       +        setenv("LOGNAME", pass->pw_name, 1);
       +        setenv("USER", pass->pw_name, 1);
       +        setenv("SHELL", pass->pw_shell, 0);
       +        setenv("HOME", pass->pw_dir, 0);
       +
       +        switch (fork()) {
       +        case 0:
       +                execv(getenv("SHELL"), ++argv);
       +                die("error executing shell:%s\n", strerror(errno));
       +        case -1:
       +                die("error spawning child:%s\n", strerror(errno));
       +        default:
       +                addutmp(STDIN_FILENO);
       +                if (wait(&status) == -1) {
       +                        fprintf(stderr, "error waiting child:%s\n",
       +                                strerror(errno));
       +                }
       +                delutmp();
       +        }
       +        return 0;
       +}
       +