环境:OS X10.12.4
书中关于who程序的实现在我的OS X上好像跑不起来,首先看一下man who.
- WHO(1) BSD General Commands Manual WHO(1)
- NAME
- who -- display who is logged in
- SYNOPSIS
- who [-abdHlmpqrsTtu] [file]
- who am i
- DESCRIPTION
- The who utility displays a list of all users currently logged on,showing for each user the login name,tty name,the date and time
- of login,and hostname if not local.
- Available options:
- -a Same as -bdlprTtu.
- -b Time of last system boot.
- -d Print dead processes.
- -H Write column headings above the regular output.
- -l Print system login processes (unsupported).
- -m Only print information about the current terminal. This is
- the POSIX way of saying who am i.
- -p Print active processes spawned by launchd(8) (unsupported).
- -q ``Quick mode'': List only the names and the number of users
- currently logged on. When this option is used,all other
- options are ignored.
- -r Print the current runlevel. This is meaningless on Mac OS X.
- -s List only the name,line and time fields. This is the
- default.
- -T Print a character after the user name indicating the state of
- the terminal line: `+' if the terminal is writable; `-' if it
- is not; and `?' if a bad line is encountered.
- -t Print last system clock change (unsupported).
- -u Print the idle time for each user,and the associated process
- ID.
- am I Returns the invoker's real user name.
- file By default,who gathers information from the file
- /var/run/utmpx. An alternative file may be specified.
- FILES
- /var/run/utmpx
- SEE ALSO
- last(1),mesg(1),users(1),getuid(2),utmpx(5)
- STANDARDS
- The who utility conforms to IEEE Std 1003.1-2001 (``POSIX.1'').
- HISTORY
- A who utility appeared in Version 6 AT&T UNIX.
- BSD January 17,2007 BSD
从这里可以看出OS X 使用的是utmpx,而不是utmp。而utmpx是utmp的扩展。
如果装了X Code之后,可以尝试找utmp.h这个头文件。
- find / -name "utmp.h"
理论上书上的代码是可以正确执行的,但是/var/run/utmp 这个文件好像并不存在,我手动创建了一个,但系统并没有更新这个文件,当有新用户登入时。
后来我在man utmp的时候发现这么一段。
- DESCRIPTION
- The interfaces in file are all DEPRECATED and are only
- provided for compatibility with prevIoUs releases of Mac OS X. See
- pututxline(3) and utmpx(5) for the supported interfaces.
- ...
- FILES
- (These files no longer exist in 10.5 or later.)
- /var/run/utmp The utmp file.
- /var/log/wtmp The wtmp file.
- /var/log/lastlog The lastlog file.
也就是说Apple不建议使用utmp了,而且几个文件在10.5之后不再存在,手动创建也不会更新。
其实在man who的时候会发现SEE ALSO里有这么一个玩意儿,utmpx(5)。
好的,那我们就man 进去, man 5 utmpx。
man进入之后,里面的DESCRIPTION有这么一段话。
- The interface to the utmpx file is described in
- endutxent(3).
也就是系统直接提供了接口供我们使用,而不需要直接读文件。(直接读文件其实并不行)
好的,继续 man 3 endutxent。
- ENDUTXENT(3) BSD Library Functions Manual ENDUTXENT(3)
- NAME
- endutxent,getutxent,getutxid,getutxline,pututxline,setutxent
- -- user accounting database functions
- LIBRARY
- Standard C Library (libc,-lc)
- SYNOPSIS
- #include
- void
- endutxent(void);
- struct utmpx *
- getutxent(void);
- struct utmpx *
- getutxid(const struct utmpx *id);
- struct utmpx *
- getutxline(const struct utmpx *line);
- struct utmpx *
- pututxline(const struct utmpx *utx);
- void
- setutxent(void);
- DESCRIPTION
- These functions provide access to the utmpx(5) user accounting
- database.
- getutxent() reads the next entry from the database; if the database
- was not yet open,it also opens it. setutxent() resets the data-
- base,so that the next getutxent() call will get the first entry.
- endutxent() closes the database.
- getutxid() returns the next entry of the type specified in its
- argument's ut_type field,or NULL if none is found. getutxline()
- returns the next LOGIN_PROCESS or USER_PROCESS entry which has the
- same name as specified in the ut_line field,or NULL if no match is
- found.
- pututxline() adds the argument utmpx(5) entry line to the account-
- ing database,replacing a prevIoUs entry for the same user if it
- exists. Only the superuser may write to the accounting database.
- The utmpx structure
- The utmpx structure has the following definition:
- struct utmpx {
- char ut_user[_UTX_USERSIZE]; /* login name */
- char ut_id[_UTX_IDSIZE]; /* id */
- char ut_line[_UTX_LINESIZE]; /* tty name */
- pid_t ut_pid; /* process id creating the entry */
- short ut_type; /* type of this entry */
- struct timeval ut_tv; /* time entry was created */
- char ut_host[_UTX_HOSTSIZE]; /* host name */
- __uint32_t ut_pad[16]; /* reserved for future use */
- };
- Valid entries for ut_type are:
- BOOT_TIME Time of a system boot.
- DEAD_PROCESS A session leader exited.
- EMPTY No valid user accounting information.
- INIT_PROCESS A process spawned by init(8).
- LOGIN_PROCESS The session leader of a logged-in user.
- NEW_TIME Time after system clock change.
- OLD_TIME Time before system clock change.
- RUN_LVL Run level. Provided for compatibility,not
- used.
- USER_PROCESS A user process.
- SHUTDOWN_TIME Time of system shutdown (extension to the
- standards).
- For each value of ut_type,the other fields with meaningful values
- are as follows:
- BOOT_TIME ut_tv
- DEAD_PROCESS ut_id,ut_pid,ut_tv
- EMPTY (no others)
- INIT_PROCESS ut_id,ut_tv
- LOGIN_PROCESS ut_id,ut_user (implementation-defined name
- of the login process),ut_tv
- NEW_TIME ut_tv
- OLD_TIME ut_tv
- RUN_LVL (no used)
- USER_PROCESS ut_id,ut_user (login name of the user),ut_line,ut_host (hostname of remote
- user) ut_tv
- SHUTDOWN_TIME ut_tv
- Other extensions to the standards
- The ut_type value may also be OR-ed with the following masks:
- UTMPX_AUTOFILL_MASK
- Depending on the main part of ut_type value,other
- fields are automatically filled in (as specified in the
- meaningful fields table above). In particular,the
- ut_id field will be set using the convention of the
- last four characters of the ut_line field (itself
- filled in automatically from the tty name of the device
- connected to the standard input,output or error,whichever is available). Note that it is more effi-
- cient to fill in as many values as are already avail-
- able beforehand,rather than have then automatically
- filled in.
- UTMPX_DEAD_IF_CORRESPONDING_MASK
- When ut_type value is DEAD_PROCESS,a call to
- pututxline() will succeed only if a corresponding entry
- already exists with a ut_type value of USER_PROCESS.
- Note that the above mask values do not show up in any file format,or in any subsequent reads of the data.
- To support wtmpx and lastlogx equivalent capability,pututxline()
- automatically writes to the appropriate files. Additional APIs to
- read these files is available in endutxent_wtmp(3) and
- getlastlogx(3).
- Backward compatibility
- Successful calls to pututxline() will automatically write equiva-
- lent entries into the utmp,wtmp and lastlog files. Programs that
- read these old files should work as expected. However,directly
- writing to these files does not make corresponding entries in utmpx
- and the wtmpx and lastlogx equivalent files,so such write-access
- is deprecated.
- RETURN VALUES
- getutxent() returns the next entry,or NULL on failure (end of
- database or problems reading from the database). getutxid() and
- getutxline() return the matching structure on success,or NULL if
- no match was found.
- pututxline() returns the structure that was successfully written,or NULL is returned and the global variable errno is set to indi-
- cate the error.
- ERRORS
- No errors are defined for the endutxent(),getutxent(),getutxid(),getutxline(),and setutxent() functions.
- The pututxline() function may fail if:
- [EPERM] The process does not have appropriate privi-
- leges.
- [EINVAL] The UTMPX_DEAD_IF_CORRESPONDING_MASK flags was
- specified along with DEAD_PROCESS,but no corre-
- sponding entry with USER_PROCESS was found.
- Other errors may be returned if UTMPX_AUTOFILL_MASK was specified,and a field could not be auto-filled.
- SEE ALSO
- endutxent_wtmp(3),getlastlogx(3),utmpx(5)
- STANDARDS
- The endutxent(),pututxline(),setutxent() all conform to IEEE Std 1003.1-2001
- (``POSIX.1'') (XSI extension),and prevIoUsly to X/Open Portability
- Guide Issue 4,Version 2 (``XPG4.2''). The fields ut_user,ut_id,ut_type,and ut_tv conform to IEEE Std 1003.1-2001
- (``POSIX.1'') (XSI extension),Version 2 (``XPG4.2'').
- BSD June 29,2006 BSD
里面讲述了几个函数的作用,还有utmpx的结构,还有ut_type的常见取值,还有一些其它的东西。
其实只使用getutxent()这个函数就够用了,如果没有打开数据库的话,这个函数会自动打开。
关闭的话,我省略了,最好应该有。
以下就是我的实现:
效果:
a.out是我的实现,下面的who是系统提供的。
代码:
- #include <stdio.h>
- #include <utmpx.h>
- int main(void)
- {
- struct utmpx *tmp;
- while(tmp = getutxent())
- {
- /* format time */
- time_t t = tmp->ut_tv.tv_sec;
- struct tm *p = localtime(&t);
- char buf[55];
- strftime(buf,sizeof buf,"%b %d %H:%M",p);
- if(tmp->ut_type == USER_PROCESS)
- printf("%s %s %s %s\n",tmp->ut_user,tmp->ut_line,buf,tmp->ut_host);
- // printf("%d\n",tmp->ut_type);
- }
- return 0;
- }