linux编程-编写who指令

86 阅读2分钟

编写一个who命令

who命令工作原理

who通过读取/usr/include/utmp.h文件获取文本信息并显示当前用户/进程登录到系统的信息,这个文件可以在#include <utmp.h>中找到,该文件的信息定义为结构体utmp,路径定义为UTMP_FILE,因此只需要通过读取已定义好的文件,将信息读进utmp并显示即可。

image.png

文件读取基本API

打开文件open

系统调用在进程和文件之间建立一条连接,这个连接被称为文件描述符

#include<fcntl.h>
int fd = open(char * name, int how)
  • name 文件名
  • how O_RDONLY、O_WRONLY、O_RDWR

要打开一个文件,必须指定文件名和打开模式,有3种打开模式:只读、只写、可读可写, 分别对应于 O_RDONLY、O_WRONLY、O_RDWR

打开文件是内核提供的服务,如果在打开过程中内核检测到任何错误,这个系统调用就会返回-1。

错误类型是各种各样的,如:要打开的文件不存在。即使文件存在,也可能因为权限不够而无法打开,或者是无权访问文件所在的目录。

打开文件会建立进程和文件之间的连接,文件描述符就是用来惟一标识这个连接的, 如果同时打开好几个文件,它们所对应的文件描述符是不同的,如果将一个文件打开多次, 对应的文件描述符也不相同。

读取数据read

#include<unistd.h>
ssize_t numread = read(int fd, void * buf, size_t qty)

read这个系统调用请求内核从fd所指定的文件中读取qty字节的数据,存放到buf 所指定的内存空间中,内核如果成功地读取了数据,就返回所读取的字节数目,否则返回-1

关闭文件close

#include<unistd.h>
int result = close(int fd)

close这个系统调用会关闭进程和文件fd之间的连接

时间转换API

时间转换ctime

定义在头文件#include <time.h>中,用于将1970依赖的时间秒数转换为时间戳

const char *convert_time(long time_val)
{
    const char *cp = ctime(&time_val); //ctime将1970标准时间转成字符串
    return cp;
}

代码

建立cmake工程

image.png

who.h

#ifndef _2_WHO_
#define _2_WHO_
//----------------------------------------------------------------
void who();
void show_info(const struct utmp *utmp_fp);
const char *convert_time(long time_val);
#endif

who.cpp

#include <utmp.h> //who 读取utmp文件定义结构体
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <time.h>
#include "../include/2_who.h"
using namespace std;
​
void who()
{
    struct utmp current_record;          //who 读取utmp文件定义结构体
    int utmp_fd;                         //utmp文件描述符
    int reclen = sizeof(current_record); // 记录长度
​
    if ((utmp_fd = open(UTMP_FILE, O_RDONLY)) == -1)
    {
        perror(UTMP_FILE); //读取文件失败
        cout << "Error opening utmp file" << endl;
        return;
    }
    //读取文件描述符
    while (read(utmp_fd, &current_record, reclen) == reclen)
    {
        show_info(&current_record);
    }
​
    close(utmp_fd);
}
void show_info(const struct utmp *utmp_fp)
{
    //只打印用户进程
    if (utmp_fp->ut_type != USER_PROCESS)
    {
        return;
    }
    cout << utmp_fp->ut_name << " "
         << utmp_fp->ut_line << " "
         << convert_time(utmp_fp->ut_time) << endl;
}
​
const char *convert_time(long time_val)
{
    const char *cp = ctime(&time_val); //ctime将1970标准时间转成字符串
    return cp;
}

main.cpp


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <time.h>
#include "./include/2_who.h"
using namespace std;
void show_help();
int main(int argc, char **argv)
{
​
    for (int i = 1; i < argc; i++)
    {
        string instruction(argv[i]);
        if (instruction == "-who")
        {
            who();
        }
        else if (instruction == "-help")
        {
            show_help();
        }
        else
        {
            cout << instruction << " maybe error, enter -help show all instructions" << endl;
            show_help();
        }
    }
    return 0;
}
void show_help()
{
    cout << "LSL --help" << endl
         << "-who" << endl;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
project(linux_c_programming VERSION 0.1.0)
​
include(CTest)
enable_testing()
​
set(SOURCES
main.cpp
src/2_who.cpp
)
​
​
add_executable(lsl ${SOURCES})
​
target_include_directories(lsl
PRIVATE
${PROJECT_SOURCE_DIR}/include)
​
​
​
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
​

image.png

参考来源

  1. Unix/Linux编程实践教程
  2. github.com/LSLWind/lin…