Stat(Status)

statコマンド.
システムコールの[stat]でファイルのステータスを呼び出す.
呼び出したステータスを分類して表示する. 時間はローカルタイムに変換し, パーミッションは8進数に変換後に文字列として出力する.

パーミッションを表示する際にかなり面倒な操作を行っている...
ファイルの扱える種類も少ない. いろいろと改善と自分のテクニックを磨いていきたい.

125行と長々しく書いたが, 必要最低限の情報が必要なら50行くらいのプログラムに収まると思う.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<time.h>
#include<pwd.h>

static void do_stat(const char *path);
char *do_type(const int mode, const long int size);
void result(const unsigned int mode, int *mo, char *mode_p);
void type_file(const unsigned int mode, char *mode_p, char *mode_n);
void mode_cat(char *in, char *src, char *ret);

int main(int argc, char **argv)
{
    if(argc < 2) {
        fprintf(stderr, "usage: %s [Filenames]...\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int i;
    for(i = 1; i < argc; i++)
        do_stat(argv[i]);

    return 0;
}

static void do_stat(const char *path) {
    struct stat file;
    if(stat(path, &file) == EOF) {
        perror("stat");
        exit(EXIT_FAILURE);
    }
    /* struct tm *localtime(const time_t *timep) */
    else {
        /* parmition */
        int mode_n[3];
        char mode_p[12];
        char mode_t[13];
        result(file.st_mode, mode_n, mode_p);
        type_file(file.st_mode, mode_p, mode_t);
        struct tm *f_time = localtime(&(file.st_atime));
        struct tm *m_time = localtime(&(file.st_mtime));
        struct tm *c_time = localtime(&(file.st_ctime));
        struct passwd *me = getpwuid(file.st_uid);
        printf("  File: `%s`\n", path);
        printf("  Size: %lu \t Blocks: %ld \t IO Block: %ld \t %s\n", file.st_size, file.st_blocks, file.st_blksize, do_type(file.st_mode, file.st_size));
        printf("Device: %u %u \t Inode: %d \t Links: %ld\n", major(file.st_dev), minor(file.st_dev), (int)file.st_ino, (long int)file.st_nlink);
        printf("Access: (%04o/%s) \t Uid: (%ld / %s) \t Gid: (%ld / %s)\n", file.st_mode & ~S_IFMT, mode_t, (long int)file.st_uid, me->pw_name, (long int)file.st_gid, me->pw_name);
        printf("Access: %d年%d月%d日 %d時%02d分%02d秒\n", f_time->tm_year + 1900, f_time->tm_mon + 1, f_time->tm_mday, f_time->tm_hour, f_time->tm_min, f_time->tm_sec);
        printf("Modify: %d年%d月%d日 %d時%02d分%02d秒\n", m_time->tm_year + 1900, m_time->tm_mon + 1, m_time->tm_mday, m_time->tm_hour, m_time->tm_min, m_time->tm_sec);
        printf("Change: %d年%d月%d日 %d時%02d分%02d秒\n", c_time->tm_year + 1900, c_time->tm_mon + 1, c_time->tm_mday, c_time->tm_hour, c_time->tm_min, c_time->tm_sec);
    }

}

char *do_type(const int mode, const long int size) {
    if(S_ISREG(mode)) {
        if(size == 0)
            return "空の通常ファイル";
        else
            return "通常のファイル";
    }
    if(S_ISDIR(mode)) return "ディレクトリ";
    if(S_ISCHR(mode)) return "キャラクタデバイス";
    if(S_ISBLK(mode)) return "ブロックデバイス";
    if(S_ISFIFO(mode)) return "パイプ";
}

void result(const unsigned int mode, int *mo, char *mode_p) {
    int i, con;
    char mode_s[3];
    char bu[512];
    char *a;
    sprintf(mode_s, "%o", mode);
    con = atoi(mode_s);
    for(i = 2; i >= 0; i--) {
        mo[i] = con % 10;
        con /= 10;
    }
    for(i = 0; i < 3; i++) {
        if(mo[i] == 7) a = "rwx";
        else if(mo[i] == 6) a = "rw-";
        else if(mo[i] == 5) a = "r-w";
        else if(mo[i] == 4) a = "r--";
        else if(mo[i] == 3) a = "-wx";
        else if(mo[i] == 2) a = "-w-";
        else if(mo[i] == 1) a = "--x";
        else if(mo[i] == 0) a = "---";
        if(i == 0) strcpy(bu, a);
        else strcat(bu, a);
    }
    strcpy(mode_p, bu);
}

void type_file(const unsigned int mode, char *mode_p, char *mode_n) {
    if(S_ISREG(mode)) {
        char mo[32] = "-";
        mode_cat(mo, mode_p, mode_n);
    }
    else if(S_ISDIR(mode)) {
        char mo[32] = "d";
        mode_cat(mo, mode_p, mode_n);
    }
    else if(S_ISFIFO(mode)) {
        char mo[32] = "p";
        mode_cat(mo, mode_p, mode_n);
    }
    else if(S_ISLNK(mode)) {
        char mo[32] = "l";
        mode_cat(mo, mode_p, mode_n);
    }
    else if(S_ISSOCK(mode)) {
        char mo[32] = "s";
        mode_cat(mo, mode_p, mode_n);
    }
}

void mode_cat(char *in, char *src, char *ret) {
    strcat(in, src);
    strcpy(ret, in);
}
                        

実行例:

$ ./stat
File: `/home/jin/C/and/w7/stat`
Size: 11982   Blocks: 24    IO Block: 4096   通常のファイル
Device: 8 1     Inode: 1461281    Links: 1
Access: (0775/-rwxrwxr-w)   Uid: (1000 / jin)   Gid: (1000 / jin)
Access: 2013年1月6日 16時21分03秒
Modify: 2013年1月6日 16時21分03秒
Change: 2013年1月6日 16時21分03秒