unix命令也是程序,把程序的可执行文件放在以下任意目录中:/bin、/usr/bin、/usr/local/bin,unix系统就可以增加一个新命令。
1.who命令用于显示当前系统中已经登入的用户信息
Linux 查找帮助 man -k key | grep key
2.who的工作原理
通过阅读who和utmp的联机帮助,可知道who的工作原理,who通过读utmp文件来获得需要的信息,每个登入用户在utmp文件中所有对应的记录。
utmp的数据结构
struct utmp {
short ut_type; /* Type of record */
pid_t ut_pid; /* PID of login process */
char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */
char ut_id[4]; /* Terminal name suffix,
or inittab(5) ID */
char ut_user[UT_NAMESIZE]; /* Username */
char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or
kernel version for run-level
messages */
struct exit_status ut_exit; /* Exit status of a process
marked as DEAD_PROCESS; not
used by Linux init(8) */
/* The ut_session and ut_tv fields must be the same size when
compiled 32- and 64-bit. This allows data files and shared
memory to be shared between 32- and 64-bit applications. */
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
int32_t ut_session; /* Session ID (getsid(2)),
used for windowing */
struct {
int32_t tv_sec; /* Seconds */
int32_t tv_usec; /* Microseconds */
} ut_tv; /* Time entry was made */
#else
long ut_session; /* Session ID */
struct timeval ut_tv; /* Time entry was made */
#endif
int32_t ut_addr_v6[4]; /* Internet address of remote
host; IPv4 address uses
just ut_addr_v6[0] */
char __unused[20]; /* Reserved for future use */
};
3.编写who
(1)读取文件中的数据结构
使用open, read 和close
(2)第一个who程序
/* who1.c - a first version of the who program
* open, read UTMP file, and show results
*/
#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#define SHOWHOST /* include remote machine on output */
int main()
{
struct utmp current_record; /* read info into here */
int utmpfd; /* read from this descriptor */
int reclen = sizeof(current_record);
if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
perror( UTMP_FILE ); /* UTMP_FILE is in utmp.h */
exit(1);
}
while ( read(utmpfd, ¤t_record, reclen) == reclen )
show_info(¤t_record);
close(utmpfd);
return 0; /* went ok */
}
/*
* show info()
* displays contents of the utmp struct in human readable form
* *note* these sizes should not be hardwired
*/
show_info( struct utmp *utbufp )
{
printf("%-8.8s ", utbufp->ut_user); /* the logname */
printf("%-8.8s ", utbufp->ut_line); /* the tty */
printf("%10d ", utbufp->ut_time); /* login time */
#ifdef SHOWHOST
printf("(%s)\n", utbufp->ut_host); /* the host */
#endif
}
(3)第二版who程序编写
上一个程序存在两个问题,一是空白记录,二是时间显示不对
/* who2.c - read /etc/utmp and list info therein
* - suppresses empty records
* - formats time nicely
*/
#include<stdio.h>
#include<unistd.h>
#include<utmp.h>
#include<fcntl.h>
#include<time.h>
#include<stdlib.h>
#define SHOWHOST
void showtime(time_t);
void show_info(struct utmp *);
int main()
{
struct utmp utbuf; /* read info into here */
int utmpfd; /* read from this descriptor */
if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
perror(UTMP_FILE);
exit(1);
}
while( read(utmpfd, &utbuf, sizeof(utbuf)) == sizeof(utbuf) )
show_info( &utbuf );
close(utmpfd);
return 0;
}
/*
* show info()
* displays the contents of the utmp struct
* in human readable form
* * displays nothing if record has no user name
*/
void show_info( struct utmp *utbufp )
{
if ( utbufp->ut_type != USER_PROCESS )
return;
printf("%-8.8s", utbufp->ut_user); /* the logname */
printf(" "); /* a space */
printf("%-8.8s", utbufp->ut_line); /* the tty */
printf(" "); /* a space */
showtime( utbufp->ut_time ); /* display time */
#ifdef SHOWHOST
if ( utbufp->ut_host[0] != '\0' )
printf(" (%s)", utbufp->ut_host);/* the host */
#endif
printf("\n"); /* newline */
}
void showtime( time_t timeval )
/*
* displays time in a format fit for human consumption
* uses ctime to build a string then picks parts out of it
* Note: %12.12s prints a string 12 chars wide and LIMITS
* it to 12chars.
*/
{
char *cp; /* to hold address of time */
cp = ctime(&timeval); /* convert time to string */
/* string looks like */
/* Mon Feb 4 00:46:40 EST 1991 */
/* 0123456789012345. */
printf("%12.12s", cp+4 ); /* pick 12 chars from pos 4 */
}
4.编写cp(读和写)
creat和write函数
cp程序流程
/** cp1.c
* version 1 of cp - uses read and write with tunable buffer size
*
* usage: cp1 src dest
*/
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#define BUFFERSIZE 4096
#define COPYMODE 0644
void oops(char *, char *);
main(int ac, char *av[])
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
/* check args */
if ( ac != 3 ){
fprintf( stderr, "usage: %s source destination\n", *av);
exit(1);
}
/* open files */
if ( (in_fd=open(av[1], O_RDONLY)) == -1 )
oops("Cannot open ", av[1]);
if ( (out_fd=creat( av[2], COPYMODE)) == -1 )
oops( "Cannot creat", av[2]);
/* copy files */
while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", av[2]);
if ( n_chars == -1 )
oops("Read error from ", av[1]);
/* close files */
if ( close(in_fd) == -1 || close(out_fd) == -1 )
oops("Error closing files","");
}
void oops(char *s1, char *s2)
{
fprintf(stderr,"Error: %s ", s1);
perror(s2);
exit(1);
}
5.提高文件I/O效率的方法:使用缓冲
用户模式不能访问设备,只能访问特定内存空间,访问磁盘等设备要通过系统调用,系统调用切换需要时间。缓冲大可以减少系统调用,进而减少时间开销。
在who2.c中运用缓冲技术
/* utmplib.c - functions to buffer reads from utmp file
*
* functions are
* utmp_open( filename ) - open file
* returns -1 on error
* utmp_next( ) - return pointer to next struct
* returns NULL on eof
* utmp_close() - close file
*
* reads NRECS per read and then doles them out from the buffer
*/
#include<stdio.h>
#include<fcntl.h>
#include<sys/types.h>
#include<utmp.h>
#define NRECS 16
#define NULLUT ((struct utmp *)NULL)
#define UTSIZE (sizeof(struct utmp))
static char utmpbuf[NRECS * UTSIZE]; /* storage */
static int num_recs; /* num stored */
static int cur_rec; /* next to go */
static int fd_utmp = -1; /* read from */
int utmp_open( char *filename )
{
fd_utmp = open( filename, O_RDONLY ); /* open it */
cur_rec = num_recs = 0; /* no recs yet */
return fd_utmp; /* report */
}
struct utmp *utmp_next()
{
struct utmp *recp;
if ( fd_utmp == -1 ) /* error ? */
return NULLUT;
if ( cur_rec==num_recs && utmp_reload()==0 ) /* any more ? */
return NULLUT;
/* get address of next record */
recp = ( struct utmp *) &utmpbuf[cur_rec * UTSIZE];
cur_rec++;
return recp;
}
int utmp_reload()
/*
* read next bunch of records into buffer
*/
{
int amt_read;
/* read them in */
amt_read = read( fd_utmp , utmpbuf, NRECS * UTSIZE );
/* how many did we get? */
num_recs = amt_read/UTSIZE;
/* reset pointer */
cur_rec = 0;
return num_recs;
}
void utmp_close()
{
if ( fd_utmp != -1 ) /* don't close if not */
close( fd_utmp ); /* open */
}
/* who3.c - who with buffered reads
* - surpresses empty records
* - formats time nicely
* - buffers input (using utmplib)
*/
#include<stdio.h>
#include<sys/types.h>
#include<utmp.h>
#include<fcntl.h>
#include<time.h>
#include<stdlib.h>
#define SHOWHOST
void show_info(struct utmp *);
void showtime(time_t);
int main()
{
struct utmp *utbufp, /* holds pointer to next rec */
*utmp_next(); /* returns pointer to next */
if ( utmp_open( UTMP_FILE ) == -1 ){
perror(UTMP_FILE);
exit(1);
}
while ( ( utbufp = utmp_next() ) != ((struct utmp *) NULL) )
show_info( utbufp );
utmp_close( );
return 0;
}
/*
* show info()
* displays the contents of the utmp struct
* in human readable form
* * displays nothing if record has no user name
*/
void show_info( struct utmp *utbufp )
{
if ( utbufp->ut_type != USER_PROCESS )
return;
printf("%-8.8s", utbufp->ut_name); /* the logname */
printf(" "); /* a space */
printf("%-8.8s", utbufp->ut_line); /* the tty */
printf(" "); /* a space */
showtime( utbufp->ut_time ); /* display time */
#ifdef SHOWHOST
if ( utbufp->ut_host[0] != '\0' )
printf(" (%s)", utbufp->ut_host); /* the host */
#endif
printf("\n"); /* newline */
}
void showtime( time_t timeval )
/*
* displays time in a format fit for human consumption
* uses ctime to build a string then picks parts out of it
* Note: %12.12s prints a string 12 chars wide and LIMITS
* it to 12chars.
*/
{
char *cp; /* to hold address of time */
cp = ctime( &timeval ); /* convert time to string */
/* string looks like */
/* Mon Feb 4 00:46:40 EST 1991 */
/* 0123456789012345. */
printf("%12.12s", cp+4 ); /* pick 12 chars from pos 4 */
}
内核也使用缓冲技术来提高对磁盘的访问速度,read把数据从内核缓冲区复制到进程缓冲区,write把数据从进程缓冲区复制到内核缓冲区。
应用内核缓冲区技术导致的结果:提高磁盘I/O的效率;优化磁盘的写操作;需要及时地将缓冲数据写入磁盘,不然断电会使缓冲数据丢失。
6.改变文件的当前位置
lseek函数
7.处理系统中的错误
内核通过全局变量errno来指明错误的类型,每个程序都可以访问者个变量
显示错误信息使用perror函数