Linux gcc:”現在ログインしているユーザとその端末に関する情報”、”ログアウトやシステムの再起動に関する記録”の取得ガイド

Linux gcc/g++

Linux システムにおいて”現在ログインしているユーザとその端末に関する情報”、”ログアウトやシステムの再起動に関する記録”を取得し、その結果を標準出力するCプログラムの作成とコンパイル手順について詳しく説明します。

前提 基礎知識

utmp ファイル

Linux システムにおいて現在ログインしているユーザやその端末に関する情報を記録するためのファイルです。

ファイル格納場所:/var/run/utmp

wtmp ファイル

ログアウトやシステムの再起動に関する記録するためのファイルです。

ファイルの格納場所:/var/log/wtmp

使用コマンド

  • who
    utmp ファイルを参照し、ログインしているユーザの情報を表示します。
  • w
    より詳細な情報を表示し、どのユーザが何をしているかを表示します。
  • last
    utmp ファイルを参照し、過去にログインしたユーザのログイン履歴を表示します。なお、wtmp ファイルも参照し、ログアウトやシステム再起動の履歴を表示します

tty, ptsデバイス

tty1, tty2 などのデバイスは、伝統的には物理コンソールまたは仮想コンソールに対応しています。

pts/0, pts/1, pts/2 などのデバイスは、「擬似端末スレーブ (pseudo-terminal slave)」を指します。これらは通常、リモートセッションや特定のアプリケーションによって使用される仮想的な端末デバイスです。擬似端末は、物理的な端末デバイスの振る舞いを模倣し、リモートやローカルのプロセス間通信に利用されます。

ソース作成

#include <stdio.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <arpa/inet.h>
#include <string.h>

void show_utmp(struct utmp *u);

int main() {
    struct utmp utmp_rec;
    int utmpfd;
    int reclen = sizeof(utmp_rec);

    if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1) {
        perror(UTMP_FILE);
        return 1;
    }

    while (read(utmpfd, &utmp_rec, reclen) == reclen) {
        show_utmp(&utmp_rec);
    }

    close(utmpfd);
    return 0;
}

void show_utmp(struct utmp *u) {
   if (u->ut_type != USER_PROCESS) {
      return;
   }
    printf("ut_type: %d\n", u->ut_type);
    printf("ut_pid: %d\n", u->ut_pid);
    printf("ut_line: %.*s\n", (int)(sizeof u->ut_line), u->ut_line);
    printf("ut_id: %.*s\n", (int)(sizeof u->ut_id), u->ut_id);
    printf("ut_user: %.*s\n", (int)(sizeof u->ut_user),  u->ut_user);
    printf("ut_host: %.*s\n", (int)(sizeof u->ut_host), u->ut_host);
    printf("ut_session: %d\n", u->ut_session);
    printf("ut_tv.tv_sec: %d\n", u->ut_tv.tv_sec);
    printf("ut_tv.tv_usec: %d\n", u->ut_tv.tv_usec);

    // Corrected type casting for ctime
    time_t tv_sec = (time_t)u->ut_tv.tv_sec;
    char *time_string = ctime(&tv_sec);
    printf("DateTime: %.*s\n", (int)strlen(time_string)-1,time_string);

    // IPアドレス表示 (IPv4とIPv6の両方に対応)
    char ip[INET6_ADDRSTRLEN];
    if (u->ut_addr_v6[0] || u->ut_addr_v6[1] || u->ut_addr_v6[2] || u->ut_addr_v6[3]) {
        if (u->ut_addr_v6[1] == 0 && u->ut_addr_v6[2] == 0 && u->ut_addr_v6[3] == 0) {
            // IPv4アドレスとして表示
            struct in_addr in;
            in.s_addr = u->ut_addr_v6[0];
            inet_ntop(AF_INET, &in, ip, sizeof(ip));
            printf("IP Address (IPv4): %s\n", ip);
        } else {
            // IPv6アドレスとして表示
            struct in6_addr in6;
            memcpy(&in6.s6_addr, u->ut_addr_v6, sizeof(in6.s6_addr));
            inet_ntop(AF_INET6, &in6, ip, sizeof(ip));
            printf("IP Address (IPv6): %s\n", ip);
        }
    } else {
        printf("IP Address: None\n");
    }
    printf("\n");
}

コンパイル

次のコマンドを順序に実行し、実行モジュール iptestを生成します。

$ rm -f show_utmp show_utmp.o *~
$ gcc -c -std=gnu99 -Wall -Wextra -g -finput-charset=UTF-8 -O2 -o show_utmp.o show_utmp.c
$ gcc -o show_utmp show_utmp.o

コマンドの詳細は以下ののコンパイル編を参照ください。

実行結果

モジュールを実行し、想定とおりの結果であることを確認します。

$ ./show_utmp
ut_type: 7
ut_pid: 4654
ut_line: tty1
ut_id: tty1
ut_user: srcuser
ut_host:
ut_session: 4654
ut_tv.tv_sec: 1715759177
ut_tv.tv_usec: 814413
DateTime: Wed May 15 16:46:17 2024
IP Address: None

ut_type: 7
ut_pid: 5919
ut_line: pts/0
ut_id: ts/0
ut_user: srcuser
ut_host: 192.168.21.81
ut_session: 0
ut_tv.tv_sec: 1715745121
ut_tv.tv_usec: 31841
DateTime: Wed May 15 12:52:01 2024
IP Address (IPv4): 192.168.1.11

まとめ

Linuxシステム上で現在ログインしているユーザやその端末、ログアウトやシステムの再起動に関する情報を取得する方法について解説されています。主にutmpとwtmpファイルを利用して、ユーザのセッション情報を把握し、C言語でプログラムを作成し、コンパイルして実行するプロセスが紹介されています。具体的には、who、w、lastコマンドの使用方法、そしてCプログラムを通じてこれらのファイルから情報を読み取り、標準出力する方法が説明されています。プログラムはIPアドレスの表示もサポートしており、IPv4およびIPv6の両方に対応しています。

コメント

タイトルとURLをコピーしました