home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / utmp / utmp.c < prev   
Encoding:
C/C++ Source or Header  |  1992-01-09  |  19.0 KB  |  882 lines

  1. /*
  2.  * $RCSfile: utmp.c,v $$Revision: 1.2 $$Date: 1991/12/21 22:02:57 $
  3.  *
  4.  * utmp - translate between binary and textual utmp files.
  5.  * 
  6.  * This is useful for fixing a corrupted /etc/utmp.  Use utmp to obtain
  7.  * a printable representation of the file.  Edit it, and then use
  8.  * utmp again to translate it back into binary form.
  9.  * 
  10.  * usage: utmp [-v] [infile]
  11.  * 
  12.  * utmp reads from the given file, or stdin if none is given (/etc/utmp
  13.  * if stdin is a tty), and writes to stdout.  It detects which
  14.  * transformation it is to apply automatically.
  15.  * 
  16.  * The flag -v indicates that times are to be printed in a
  17.  * human-comprehensible form.  Note that this output format is not
  18.  * currently inverted, so it is not useful for making repairs.
  19.  */
  20. /**
  21.  * If utmp is working correctly then
  22.  *
  23.  *    $ utmp
  24.  * and
  25.  *    $ utmp | utmp | utmp
  26.  *
  27.  * should produce the same output.  Ideally
  28.  *
  29.  *    $ utmp | utmp | cmp - /etc/utmp
  30.  *
  31.  * should produce no output, but some systems don't fill the entire
  32.  * unused part of the character fields with NULs.
  33.  */
  34. /**
  35.  * The device used to detect what sort of struct utmp we have is
  36.  * to see whether USER_PROCESS (a value for ut_type) is defined by
  37.  * the include files.  If it is, then struct utmp probably looks
  38.  * like this:
  39.  *
  40.  *    struct utmp
  41.  *    {
  42.  *        char    ut_user[8];    User login name
  43.  *        char    ut_id[4];    /etc/inittab id
  44.  *        char    ut_line[12];    device name (console, lnxx)
  45.  *        short    ut_pid;        process id
  46.  *        short    ut_type;    type of entry
  47.  *        struct    exit_status
  48.  *        {
  49.  *        short    e_termination;    Process termination status
  50.  *        short    e_exit;        Process exit status
  51.  *        }    ut_exit;    The exit status of a process
  52.  *                    marked as DEAD_PROCESS.
  53.  *        time_t    ut_time;    time entry was made
  54.  *    };
  55.  *
  56.  * AIX 3 systems have utmp entries like this:
  57.  *
  58.  *    struct utmp
  59.  *    {
  60.  *        char    ut_user[8];    User login name
  61.  *        char    ut_id[14];    /etc/inittab id
  62.  *        char    ut_line[12];    device name (console, lnxx)
  63.  *        short    ut_type;    type of entry
  64.  *        pid_t    ut_pid;        process id
  65.  *        struct exit_status
  66.  *        {
  67.  *        short    e_termination;    Process termination status
  68.  *        short    e_exit;        Process exit status
  69.  *        }    ut_exit;    The exit status of a process
  70.  *                    marked as DEAD_PROCESS.
  71.  *        time_t    ut_time;    time entry was made
  72.  *        char    ut_host[16];    host name
  73.  *    };
  74.  *
  75.  * To use abbreviations of the symbolic ut_type names, compile with
  76.  * SHORT_TYPES defined.
  77.  *
  78.  * If USER_PROCESS is not defined, I assume an archaic struct utmp
  79.  * like this:
  80.  *
  81.  *    struct utmp
  82.  *    {
  83.  *        char    ut_line[8];        tty name
  84.  *        char    ut_name[8];        user id
  85.  *        char    ut_host[16];        host name, if remote
  86.  *        long    ut_time;        time on
  87.  *    };
  88.  *
  89.  * $Log: utmp.c,v $
  90.  * Revision 1.2  1991/12/21  22:02:57  dws
  91.  * Improved the comments.
  92.  *
  93.  * Revision 1.1  1991/12/21  21:44:04  dws
  94.  * Initial revision
  95.  *
  96.  */
  97.  
  98. #include <sys/types.h>
  99. #include <assert.h>
  100. #include <ctype.h>
  101. #include <time.h>
  102. #include <stdio.h>
  103. #include <string.h>
  104. #include <utmp.h>
  105.  
  106. extern void exit();
  107.  
  108. /*
  109.  * Configuration Section
  110.  * 
  111.  * Configuration is done on a field-by-field basis, for the greatest
  112.  * flexibility (who knows what those vendors will think up next?).
  113.  * 
  114.  * If the symbolic ut_type names are available, assume a SysV-like set
  115.  * of fields.  Otherwise, assume BSD fields.
  116.  * 
  117.  * On some systems, utmp has no ut_id field, and ut_id is #defined to
  118.  * ut_line.
  119.  * 
  120.  * AIX3 systems have the ut_host field.
  121.  */
  122.  
  123. #ifdef    USER_PROCESS
  124. # define    HAVE_ut_user
  125. # ifndef ut_id
  126. #  define    HAVE_ut_id
  127. # endif
  128. # define    HAVE_ut_line
  129. # define    HAVE_ut_pid
  130. # define    HAVE_ut_type
  131. # define    HAVE_ut_exit
  132. # define    HAVE_ut_time
  133. # ifdef    _AIX
  134. #  define    HAVE_ut_host
  135. # endif
  136. #else
  137. # define    HAVE_ut_line
  138. # define    HAVE_ut_name
  139. # define    HAVE_ut_host
  140. # define    HAVE_ut_time
  141. #endif
  142.  
  143. #ifndef    UTMP_FILE
  144. #define    UTMP_FILE    "/etc/utmp"
  145. #endif
  146.  
  147. /*
  148.  * getopt() Section
  149.  *
  150.  * The usage() function uses write() instead of printf() so that
  151.  * programs using this template will not necessarily have to use stdio.
  152.  */
  153.  
  154. extern int write();
  155.  
  156. /*
  157.  * swrite() - write() a "string variable" (char *)
  158.  */
  159.  
  160. #define    swrite(fd, s)    (void) write((fd), (s), strlen(s))
  161.  
  162. /*
  163.  * lwrite() - write() a "string literal" (char [])
  164.  */
  165.  
  166. #define    lwrite(fd, lit)    (void) write((fd), (lit), sizeof(lit)-1)
  167.  
  168. /*
  169.  * basename(s) - assumes the string does not end in '/'
  170.  *
  171.  * This used to be
  172.  *
  173.  * #define basename(s)    (strrchr((s),'/') ? strrchr((s),'/')+1 : (s))
  174.  *
  175.  * but some systems don't have strrchr() and I didn't want to mess
  176.  * with switching between strrchr() and rindex().
  177.  */
  178.  
  179. static char *
  180. basename(s)
  181. char *s;
  182. {
  183.     char *p;
  184.  
  185.     if (!s || !*s)
  186.         return s;
  187.     
  188.     for(p = s; *s; s++)
  189.         if(*s == '/')
  190.             p = s+1;
  191.     return p;
  192. }
  193.  
  194. static char cmdopt[] = "v";
  195. static char cmdusg[] = " [-v] [filename]\n";
  196.  
  197. static int flag_v = 0;
  198.  
  199. static void
  200. usage(cmd)
  201. char *cmd;
  202. {
  203.     static char prefix[] = "usage: ";
  204.     char *p = cmd ? basename(cmd) : "a.out";
  205.     int fd = 2;
  206.  
  207.     lwrite(fd, prefix);
  208.     swrite(fd, p);
  209.     lwrite(fd, cmdusg);
  210. }
  211.  
  212. /*
  213.  * cmdline() - return the index of the first non-option argument
  214.  */
  215. static int
  216. cmdline(argc, argv)
  217. int argc;
  218. char **argv;
  219. {
  220.     extern void     exit();
  221.     extern char    *optarg; /* points to the option argument */
  222.     extern int      opterr;    /* when 0, getopt is silent on errors */
  223.     extern int      optind;    /* argv[optind] is the next argument */
  224.     extern int      optopt;    /* current option letter */
  225.  
  226.     int errflag = 0;    /* usage error flag */
  227.     int errcode = 1;    /* usage error exit code */
  228.     int c;
  229.  
  230.     while((c = getopt(argc, argv, cmdopt)) != -1)
  231.         switch(c)
  232.         {
  233.         case 'v':
  234.             flag_v = 1;
  235.             break;
  236.         case '?':
  237.             errflag = 1;
  238.             if(optopt == '?')
  239.                 errcode = 0;
  240.             break;
  241.         }
  242.  
  243.     if(errflag)
  244.     {
  245.         usage(argv[0]);
  246.         exit(errcode);
  247.     }
  248.  
  249.     return optind;
  250. }
  251.  
  252. extern struct utmp *ud;    /* dummy declaration so I can use sizeof() */
  253.  
  254. /*
  255.  * LINSIZ is the number of bytes per line of the text representation
  256.  * of a utmp file (including the newline).  The size of such a text
  257.  * file had better be a multiple of LINSIZ.
  258.  */
  259. static int LINSIZ = 1        /* 1 for the newline */
  260.  
  261. #ifdef    HAVE_ut_user
  262. # define nut_user    (sizeof(ud->ut_user)/sizeof(ud->ut_user[0]))
  263. +            1+nut_user
  264. #endif
  265.  
  266. #ifdef    HAVE_ut_id
  267. # define nut_id        (sizeof(ud->ut_id  )/sizeof(ud->ut_id  [0]))
  268. +            1+nut_id
  269. #endif
  270.  
  271. #ifdef    HAVE_ut_line
  272. # define nut_line    (sizeof(ud->ut_line)/sizeof(ud->ut_line[0]))
  273. +            1+nut_line
  274. #endif
  275.  
  276. #ifdef    HAVE_ut_pid
  277. # define nut_pid    5
  278. +            1+nut_pid
  279. #endif
  280.  
  281. #ifdef    HAVE_ut_type
  282. # if defined(SHORT_TYPES)
  283. #  define nut_type    4
  284. # else
  285. #  define nut_type    10
  286. # endif
  287. +            1+nut_type
  288. #endif
  289.  
  290. #ifdef    HAVE_ut_exit
  291. # define nut_exit    17
  292. +            1+nut_exit
  293. #endif
  294.  
  295. #ifdef    HAVE_ut_name
  296. # define nut_name    (sizeof(ud->ut_name)/sizeof(ud->ut_name[0]))
  297. +            1+nut_name
  298. #endif
  299.  
  300. #ifdef    HAVE_ut_host
  301. # define nut_host    (sizeof(ud->ut_host)/sizeof(ud->ut_host[0]))
  302. +            1+nut_host
  303. #endif
  304.  
  305. #ifdef    HAVE_ut_time
  306. # define nut_time    10
  307. +            nut_time
  308. #endif
  309. ;            /* End of LINSIZ initialization */
  310.  
  311. /*
  312.  * VIS_SPC - visible printing character used to represent a space
  313.  * 
  314.  * VIS_TAB - visible printing character used to represent a tab
  315.  * 
  316.  * VIS_NUL - visible printing character used to represent a NUL
  317.  * 
  318.  * The way the i/o translation works, the representation of each field
  319.  * must have no white space.  These visible characters are used to
  320.  * represent the invisible characters.  (Note the inverse mapping
  321.  * will be wrong if the utmp file actually contains any of these
  322.  * characters.)
  323.  * 
  324.  * These characters are not just an artifact of using scanf() to read in
  325.  * each field.  I used visible characters so that the extents and
  326.  * boundaries of the array fields would be clear.
  327.  * 
  328.  * ENVIS() and DEVIS() perform the translations on the given character
  329.  * array.
  330.  */
  331.  
  332. #define VIS_NUL    '_'
  333. #define VIS_TAB    '^'
  334. #define VIS_SPC    '~'
  335. #define CHR_NUL    0
  336. #define CHR_TAB    9
  337. #define CHR_SPC    32
  338.  
  339. #define ENVIS(str)                        \
  340.         {                        \
  341.             int i;                    \
  342.                                 \
  343.             for(i=0; i<sizeof(str)-1; i++)        \
  344.             switch((str)[i])            \
  345.             {                    \
  346.             case CHR_NUL: (str)[i]=VIS_NUL; break;    \
  347.             case CHR_TAB: (str)[i]=VIS_TAB; break;    \
  348.             case CHR_SPC: (str)[i]=VIS_SPC; break;    \
  349.             }                    \
  350.         }
  351.  
  352. #define DEVIS(str)                        \
  353.         {                        \
  354.             int i;                    \
  355.                                 \
  356.             for(i=0; i<sizeof(str)-1; i++)        \
  357.             switch((str)[i])            \
  358.             {                    \
  359.             case VIS_NUL: (str)[i]=CHR_NUL; break;    \
  360.             case VIS_TAB: (str)[i]=CHR_TAB; break;    \
  361.             case VIS_SPC: (str)[i]=CHR_SPC; break;    \
  362.             }                    \
  363.         }
  364.  
  365. /*
  366.  * These macros convert the given character args to an integer. (I
  367.  * assume ints are at least 4 bytes long...)
  368.  * 
  369.  * They serve as hash functions, with the useful property that they can
  370.  * be used in case labels when given constants as arguments.
  371.  */
  372.  
  373. #define char1int(a)        ((unsigned)(a))
  374. #define char2int(a,b)        ((char1int(a)    <<8) + (char1int(b)))
  375. #define char3int(a,b,c)        ((char2int(a,b)  <<8) + (char1int(c)))
  376. #define char4int(a,b,c,d)    ((char3int(a,b,c)<<8) + (char1int(d)))
  377.  
  378. #ifdef    HAVE_ut_time
  379. /*
  380.  * cvt_pb_pm() - convert Abbreviated Month name (cftime(3C) field
  381.  * descriptor %b) to Month Number (01 - 12) (cftime(3C) field
  382.  * descriptor %m).
  383.  */
  384.  
  385. char           *
  386. cvt_pb_pm(pb)
  387.     char           *pb;
  388. {
  389.     char           *pm = "??";
  390.  
  391.     switch(char3int(pb[0],pb[1],pb[2]))
  392.     {
  393.     case char3int('J','a','n'): pm = "01"; break;
  394.     case char3int('F','e','b'): pm = "02"; break;
  395.     case char3int('M','a','r'): pm = "03"; break;
  396.     case char3int('A','p','r'): pm = "04"; break;
  397.     case char3int('M','a','y'): pm = "05"; break;
  398.     case char3int('J','u','n'): pm = "06"; break;
  399.     case char3int('J','u','l'): pm = "07"; break;
  400.     case char3int('A','u','g'): pm = "08"; break;
  401.     case char3int('S','e','p'): pm = "09"; break;
  402.     case char3int('O','c','t'): pm = "10"; break;
  403.     case char3int('N','o','v'): pm = "11"; break;
  404.     case char3int('D','e','c'): pm = "12"; break;
  405.     }
  406.     return (pm);
  407. }
  408.  
  409. /*
  410.  * utgets_time() - set the ut_time field from the given file
  411.  */
  412. utgets_time(f, ut)
  413.     FILE           *f;
  414.     struct utmp    *ut;    /* utmp structure to print */
  415. {
  416.     (void)fscanf(f,"%ld",        &ut->ut_time);
  417. }
  418.  
  419. /*
  420.  * utputs_time() - print the ut_time field to the given file
  421.  *
  422.  * Note that if flag_v is set the output will not be invertible by
  423.  * utgets().
  424.  */
  425. utputs_time(f, ut)
  426.     FILE           *f;
  427.     struct utmp    *ut;    /* utmp structure to print */
  428. {
  429.     char  time[BUFSIZ];
  430.     int   ntime;
  431.     char *ptime;
  432.  
  433.     if(!flag_v)
  434.     {
  435.         (void)fprintf(f,"%*ld",    nut_time,    ut->ut_time);
  436.         return;
  437.     }
  438.  
  439.     /* make sure time[] starts out null */
  440.     for(ptime = time; ptime < time + sizeof time; ptime++)
  441.         *ptime = '\0';
  442. #if 0
  443.     (void)memset(time,0,sizeof(time)/sizeof(time[0]));
  444. #endif
  445.  
  446.     /*
  447.      * Format the time field in a compact, sortable form
  448.      *
  449.          * ctime returns a pointer to a 26-character string in the
  450.      * following form:
  451.      *
  452.      *    Sun Sep 16 01:03:52 1973\n\0
  453.      *    012345678901234567890123 4 5
  454.      *
  455.      * I want the time displayed as
  456.      *
  457.      *    yy/mm/dd hh:mm:ss
  458.      *      01234567890123456
  459.      *
  460.      * Since cftime is not available everywhere, I will construct
  461.      * the time myself using the result of ctime().
  462.      */
  463. #if 0
  464.     /* This is how simple it is with cftime() */
  465.     ntime =    cftime(time, "%y/%m/%d %T", &(ut->ut_time));
  466. #endif
  467.  
  468.     ntime = 0;
  469.     ptime = ctime(&(ut->ut_time));
  470.  
  471.     strncat(time, ptime + 22, 2); ntime += 2;        /* yy */
  472.     time[ntime++] = '/';
  473.     strncat(time, cvt_pb_pm(ptime + 4), 2); ntime += 2;    /* mm */
  474.     time[ntime++] = '/';
  475.  
  476.     strncat(time, ptime +  8, 2); ntime += 2;        /* dd */
  477.     if(time[ntime-2] == ' ')        /* add leading '0' */
  478.         time[ntime-2] = '0';
  479.  
  480.     time[ntime++] = ' ';
  481.     strncat(time, ptime + 11, 8); ntime += 8;      /* hh:mm:ss */
  482.  
  483.     time[ntime] = '\0';        /* just to be paranoid */
  484.  
  485.     assert(ntime < (sizeof(time)/sizeof(time[0])) - 1);
  486.  
  487.     (void)fprintf(f, "%*s",    ntime,        time);
  488. }
  489. #endif
  490.  
  491. /*
  492.  * utgets() - translate a text line from the given file into a struct
  493.  * utmp
  494.  */
  495. struct utmp    *
  496. utgets(f)
  497.     FILE           *f;
  498. {
  499.     static struct utmp utb;
  500.     static struct utmp *ut = &utb;
  501.  
  502.     if (!f || feof(f))
  503.         return (struct utmp *) 0;
  504.  
  505.     /*
  506.      * Read in the fields
  507.      */
  508. #ifdef    HAVE_ut_user
  509.     {
  510.         char            user[nut_user + 1];
  511.  
  512.         (void) fscanf(f, "%s", user);
  513.         user[nut_user] = '\0';
  514.         DEVIS(user);
  515.         (void) strncpy(ut->ut_user, user, nut_user);
  516.     }
  517. #endif
  518. #ifdef    HAVE_ut_id
  519.     {
  520.         char            id[nut_id + 1];
  521.  
  522.         (void) fscanf(f, "%s", id);
  523.         id[nut_id] = '\0';
  524.         DEVIS(id);
  525.         (void) strncpy(ut->ut_id, id, nut_id);
  526.     }
  527. #endif
  528. #ifdef    HAVE_ut_line
  529.     {
  530.         char            line[nut_line + 1];
  531.  
  532.         (void) fscanf(f, "%s", line);
  533.         line[nut_line] = '\0';
  534.         DEVIS(line);
  535.         (void) strncpy(ut->ut_line, line, nut_line);
  536.     }
  537. #endif
  538. #ifdef    HAVE_ut_pid
  539.     {
  540.         long    pid;
  541.     /* (void)fscanf(f,"%hd",        &ut->ut_pid); */
  542.  
  543.         (void)fscanf(f,"%ld",        &pid);
  544.         ut->ut_pid = pid;
  545.     }
  546. #endif
  547. #ifdef    HAVE_ut_type
  548.     {
  549.     char type[20];
  550.     short btype = 999;
  551.  
  552.     (void)fscanf(f,"%s",    type);
  553.     /* decode the type */
  554. # if defined(SHORT_TYPES)
  555.     switch(char4int(type[0],type[1],type[2],type[3]))
  556.     {
  557.     case char4int('N','U','L','L'): btype = EMPTY;        break;
  558.     case char4int('R','L','V','L'): btype = RUN_LVL;    break;
  559.     case char4int('B','O','O','T'): btype = BOOT_TIME;    break;
  560.     case char4int('O','L','D','T'): btype = OLD_TIME;    break;
  561.     case char4int('N','E','W','T'): btype = NEW_TIME;    break;
  562.     case char4int('I','N','I','P'): btype = INIT_PROCESS;    break;
  563.     case char4int('L','O','G','P'): btype = LOGIN_PROCESS;    break;
  564.     case char4int('U','S','R','P'): btype = USER_PROCESS;    break;
  565.     case char4int('D','E','D','P'): btype = DEAD_PROCESS;    break;
  566.     case char4int('A','C','C','T'): btype = ACCOUNTING;    break;
  567.     default:
  568.         fprintf(stderr, "bad type: %s\n", type);
  569.     }
  570. # else
  571.     switch(char4int(type[0],type[1],type[2],type[3]))
  572.     {
  573.     case char4int('E','M','P','T'): btype = EMPTY;        break;
  574.     case char4int('R','U','N','_'): btype = RUN_LVL;    break;
  575.     case char4int('B','O','O','T'): btype = BOOT_TIME;    break;
  576.     case char4int('O','L','D','_'): btype = OLD_TIME;    break;
  577.     case char4int('N','E','W','_'): btype = NEW_TIME;    break;
  578.     case char4int('I','N','I','T'): btype = INIT_PROCESS;    break;
  579.     case char4int('L','O','G','I'): btype = LOGIN_PROCESS;    break;
  580.     case char4int('U','S','E','R'): btype = USER_PROCESS;    break;
  581.     case char4int('D','E','A','D'): btype = DEAD_PROCESS;    break;
  582.     case char4int('A','C','C','O'): btype = ACCOUNTING;    break;
  583.     default:
  584.         fprintf(stderr, "bad type: %s\n", type);
  585.     }
  586. # endif
  587.     ut->ut_type = btype;
  588.     }
  589. #endif
  590. #ifdef    HAVE_ut_exit
  591.     (void)fscanf(f," term=%hd",    &ut->ut_exit.e_termination);
  592.     (void)fscanf(f," exit=%hd",    &ut->ut_exit.e_exit);
  593. #endif
  594. #ifdef    HAVE_ut_name
  595.     {
  596.         char            name[nut_name + 1];
  597.  
  598.         (void) fscanf(f, "%s", name);
  599.         name[nut_name] = '\0';
  600.         DEVIS(name);
  601.         (void) strncpy(ut->ut_name, name, nut_name);
  602.     }
  603. #endif
  604. #ifdef    HAVE_ut_host
  605.     {
  606.         char            host[nut_host + 1];
  607.  
  608.         (void) fscanf(f, "%s", host);
  609.         host[nut_host] = '\0';
  610.         DEVIS(host);
  611.         (void) strncpy(ut->ut_host, host, nut_host);
  612.     }
  613. #endif
  614. #ifdef    HAVE_ut_time
  615.     utgets_time(f, ut);
  616. #endif
  617.  
  618.     (void) fscanf(f, "\n");
  619.  
  620.     return ut;
  621. }
  622.  
  623. /*
  624.  * utputs() - translate from a struct utmp to a text line in the given
  625.  * file
  626.  */
  627. utputs(f, ut)
  628.     FILE           *f;
  629.     struct utmp    *ut;    /* utmp structure to print */
  630. {
  631.     if (!ut || !f)
  632.         return 0;
  633.  
  634.     /*
  635.      * Print out the fields
  636.      */
  637.  
  638. #ifdef    HAVE_ut_user
  639.     {
  640.         char            user[nut_user + 1];
  641.  
  642.         (void) strncpy(user, ut->ut_user, nut_user);
  643.         user[nut_user] = '\0';
  644.         ENVIS(user);
  645.         (void) fprintf(f, "%*s ", nut_user, user);
  646.     }
  647. #endif
  648. #ifdef    HAVE_ut_id
  649.     {
  650.         char            id[nut_id + 1];
  651.  
  652.         (void) strncpy(id, ut->ut_id, nut_id);
  653.         id[nut_id] = '\0';
  654.         ENVIS(id);
  655.         (void) fprintf(f, "%*s ", nut_id, id);
  656.     }
  657. #endif
  658. #ifdef    HAVE_ut_line
  659.     {
  660.         char            line[nut_line + 1];
  661.  
  662.         (void) strncpy(line, ut->ut_line, nut_line);
  663.         line[nut_line] = '\0';
  664.         ENVIS(line);
  665.         (void) fprintf(f, "%*s ", nut_line, line);
  666.     }
  667. #endif
  668. #ifdef    HAVE_ut_pid
  669.     (void)fprintf(f,"%*d ",    nut_pid,    ut->ut_pid);
  670. #endif
  671. #ifdef    HAVE_ut_type
  672.     {
  673.     char *type;
  674.  
  675. # if defined(SHORT_TYPES)
  676.     switch(ut->ut_type)
  677.     {
  678.     case EMPTY:        type = "NULL";    break;
  679.     case RUN_LVL:        type = "RLVL";    break;
  680.     case BOOT_TIME:        type = "BOOT";    break;
  681.     case OLD_TIME:        type = "OLDT";    break;
  682.     case NEW_TIME:        type = "NEWT";    break;
  683.     case INIT_PROCESS:    type = "INIP";    break;
  684.     case LOGIN_PROCESS:    type = "LOGP";    break;
  685.     case USER_PROCESS:    type = "USRP";    break;
  686.     case DEAD_PROCESS:    type = "DEDP";    break;
  687.     case ACCOUNTING:    type = "ACCT";    break;
  688.     default:        type = "unk!";    break;
  689.     }
  690.     (void)fprintf(f,"%*s ",    nut_type,    type); /* 5 bytes */
  691. # else
  692.     switch(ut->ut_type)
  693.     {
  694.     case EMPTY:        type = "EMPTY";        break;
  695.     case RUN_LVL:        type = "RUN_LVL";    break;
  696.     case BOOT_TIME:        type = "BOOT_TIME";    break;
  697.     case OLD_TIME:        type = "OLD_TIME";    break;
  698.     case NEW_TIME:        type = "NEW_TIME";    break;
  699.     case INIT_PROCESS:    type = "INIT_PROC";    break;
  700.     case LOGIN_PROCESS:    type = "LOGIN_PROC";    break;
  701.     case USER_PROCESS:    type = "USER_PROC";    break;
  702.     case DEAD_PROCESS:    type = "DEAD_PROC";    break;
  703.     case ACCOUNTING:    type = "ACCOUNTING";    break;
  704.     default:        type = "unknown!";    break;
  705.     }
  706.     (void)fprintf(f,"%-*s ", nut_type,    type); /* 11 bytes */
  707. # endif
  708.     }
  709. #endif
  710. #ifdef    HAVE_ut_exit
  711.     (void)fprintf(f,"term=%*d exit=%*d ",
  712.         3,
  713.         ut->ut_exit.e_termination,
  714.         3,
  715.         ut->ut_exit.e_exit
  716.     );
  717. #endif
  718. #ifdef    HAVE_ut_name
  719.     {
  720.         char            name[nut_name + 1];
  721.  
  722.         (void) strncpy(name, ut->ut_name, nut_name);
  723.         name[nut_name] = '\0';
  724.         ENVIS(name);
  725.         (void) fprintf(f, "%*s ", nut_name, name);
  726.     }
  727. #endif
  728. #ifdef    HAVE_ut_host
  729.     {
  730.         char            host[nut_host + 1];
  731.  
  732.         (void) strncpy(host, ut->ut_host, nut_host);
  733.         host[nut_host] = '\0';
  734.         ENVIS(host);
  735.         (void) fprintf(f, "%*s ", nut_host, host);
  736.     }
  737. #endif
  738. #ifdef    HAVE_ut_time
  739.     utputs_time(f, ut);
  740. #endif
  741.  
  742.     (void) putc('\n', f);
  743.  
  744.     return 1;
  745. }
  746.  
  747. /*
  748.  * utget() - read a struct utmp from the given file
  749.  */
  750. struct utmp    *
  751. utget(f)
  752.     FILE           *f;
  753. {
  754.     static struct utmp utb;
  755.     static struct utmp *ut = &utb;
  756.  
  757.     if (fread((char *) ut, sizeof(*ut), 1, f) != 1)
  758.         return (struct utmp *) 0;
  759.  
  760.     return ut;
  761. }
  762.  
  763. /*
  764.  * utput() - write a struct utmp to the given file
  765.  */
  766. utput(f, ut)
  767.     FILE           *f;
  768.     struct utmp    *ut;
  769. {
  770.     if (!ut || !f)
  771.         return 0;
  772.  
  773.     return fwrite((char *) ut, sizeof(*ut), 1, f);
  774. }
  775.  
  776. /*
  777.  * docopy() - copy from i to o, translating as appropriate
  778.  */
  779. docopy(i, o)
  780.     FILE           *i;
  781.     FILE           *o;
  782. {
  783.     FILE           *tmp = tmpfile();
  784.     int             ilen = 0;    /* size of i file */
  785.     int             binary = 0;    /* 1 if i file is binary */
  786.     int             c;
  787.  
  788.     /*
  789.      * The textual representation may contain only printing
  790.      * characters - only the visible characters and space.
  791.      * 
  792.      * If there is any character which is not ascii or is not
  793.      * printable, then treat the file as binary.
  794.      */
  795.  
  796.     while ((c = getc(i)) != EOF)
  797.     {
  798.         ilen++;
  799.  
  800.         if (!isascii(c) || !(isprint(c) || c == '\n'))
  801.         {
  802.             binary = 1;
  803.         }
  804.  
  805.         (void) putc(c, tmp);
  806.     }
  807.     if(ilen == 0)
  808.         return;
  809.  
  810.     rewind(tmp);
  811.  
  812.     if (binary)
  813.     {
  814. #if 0
  815.         (void) fprintf(stderr, "Input is Binary\n");
  816. #endif
  817.         if (ilen % sizeof(struct utmp))
  818.         {
  819.             (void) fprintf(stderr, "Binary wrong size!\n");
  820.         }
  821.         while (utputs(o, utget(tmp)))
  822.             continue;
  823.     }
  824.     else
  825.     {
  826. #if 0
  827.         (void) fprintf(stderr, "Input is Text\n");
  828. #endif
  829.         if (ilen % LINSIZ)
  830.         {
  831.             (void) fprintf(stderr, "Text wrong size!\n");
  832.         }
  833.         while (utput(o, utgets(tmp)))
  834.             continue;
  835.     }
  836. }
  837.  
  838. main(ac, av)
  839.     int             ac;
  840.     char          **av;
  841. {
  842.     FILE           *in = stdin;
  843.     FILE           *out = stdout;
  844.     int             optc = cmdline(ac, av);
  845.  
  846.     ac -= optc;
  847.     av += optc;
  848.  
  849.     switch (ac)
  850.     {
  851. #if 0
  852.     case 2:
  853.         if ((out = fopen(av[1], "w")) == (FILE *) 0)
  854.         {
  855.             exit(1);
  856.         }
  857.         /* PASSTHROUGH */
  858. #endif
  859.     case 1:
  860.         if ((in = fopen(av[0], "r")) == (FILE *) 0)
  861.         {
  862.             exit(1);
  863.         }
  864.         break;
  865.     case 0:
  866.         if (isatty(0))
  867.         {
  868.             if ((in = fopen(UTMP_FILE, "r")) == (FILE *) 0)
  869.             {
  870.                 exit(1);
  871.             }
  872.         }
  873.         break;
  874.     default:
  875.         exit(1);
  876.     }
  877.  
  878.     docopy(in, out);
  879.  
  880.     return 0;
  881. }
  882.