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秒