stat(1)
stat [選項] 文件
null
:顯示詳細信息-l
:連接-f
:不顯示文件的信息,而顯示其所在文件系統的信息-t
:顯示簡潔的信息-c
:以指定格式輸出man 1 stat
查看stat
命令stat
命令man -k stat | grep 2
函數找到以下man 2 stat
查看使用stat()
函數會得到stat結構體html
struct stat { dev_t st_dev; /* ID of device containing file -文件所在設備的ID*/ ino_t st_ino; /* inode number -inode節點號*/ mode_t st_mode; /* 文件的類型和存取的權限*/ nlink_t st_nlink; /* number of hard links -鏈向此文件的鏈接數(硬鏈接)*/ uid_t st_uid; /* user ID of owner -user id*/ gid_t st_gid; /* group ID of owner - group id*/ dev_t st_rdev; /* device ID (if special file) -設備號,針對設備文件*/ off_t st_size; /* total size, in bytes -文件大小,字節爲單位*/ blksize_t st_blksize; /* blocksize for filesystem I/O -系統塊的大小*/ blkcnt_t st_blocks; /* number of blocks allocated -文件所佔塊數*/ time_t st_atime; /* time of last access -最近存取時間*/ time_t st_mtime; /* time of last modification -最近修改時間*/ time_t st_ctime; /* time of last status change - */ };
其中,比較特殊的是st_mode
,st_mode是用特徵位來表示文件類型的,特徵位的定義以下:node
S_IFMT 0170000 文件類型的位遮罩 S_IFSOCK 0140000 socket S_IFLNK 0120000 符號連接(symbolic link) S_IFREG 0100000 通常文件 S_IFBLK 0060000 區塊裝置(block device) S_IFDIR 0040000 目錄 S_IFCHR 0020000 字符裝置(character device) S_IFIFO 0010000 先進先出(fifo) S_ISUID 0004000 文件的(set user-id on execution)位 S_ISGID 0002000 文件的(set group-id on execution)位 S_ISVTX 0001000 文件的sticky位 S_IRWXU 00700 文件全部者的遮罩值(即全部權限值) S_IRUSR 00400 文件全部者具可讀取權限 S_IWUSR 00200 文件全部者具可寫入權限 S_IXUSR 00100 文件全部者具可執行權限 S_IRWXG 00070 用戶組的遮罩值(即全部權限值) S_IRGRP 00040 用戶組具可讀取權限 S_IWGRP 00020 用戶組具可寫入權限 S_IXGRP 00010 用戶組具可執行權限 S_IRWXO 00007 其餘用戶的遮罩值(即全部權限值) S_IROTH 00004 其餘用戶具可讀取權限 S_IWOTH 00002 其餘用戶具可寫入權限 S_IXOTH 00001 其餘用戶具可執行權限
判斷文件類型時,用對文件的st_mode的值與文件類型的位遮罩相與,再比較。linux
stat結構體中不少變量的類型都是不經常使用的,不能直接輸出該類型,因此使用grep -r *
查找同名變量的類型。以存儲大小的變量st_size
爲例,發現不少使用的long long
類型git
僞代碼程序員
input path; struct state; stat(path,state); print(state);
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <time.h> void main(int argc, char *argv[]) { struct stat state; stat(argv[1], &state); printf(" 文件:‘%s'\n", argv[1]); printf(" 大小:%lld\t", (long long)state.st_size); printf("塊:%lld\t", (long long)state.st_blocks); printf("IO塊:%ld\t", (long)state.st_blksize); switch(state.st_mode & S_IFMT) { case S_IFBLK: printf("塊設備文件"); break; case S_IFCHR: printf("字符設備文件"); break; case S_IFDIR: printf("目錄"); break; case S_IFIFO: printf("管道文件"); break; case S_IFLNK: printf("符號連接文件"); break; case S_IFREG: printf("普通文件"); break; case S_IFSOCK: printf("套接字文件"); break; default: break; } printf("\n"); printf("設備:%xh/%ldd\t", (long)state.st_dev, (long)state.st_dev); printf("Inode:%ld\t", (long)state.st_ino); printf("硬連接:%ld\n", (long)state.st_nlink); printf("權限:(%o)\t", (unsigned int)(state.st_mode & ~S_IFMT)); printf("Uid:(%ld)\t", (long)state.st_uid); printf("Gid:(%ld)\n", (long)state.st_gid); printf("最近訪問:%s", ctime(&state.st_atim)); printf("最近更改:%s", ctime(&state.st_ctim)); printf("最近改動:%s", ctime(&state.st_mtim)); printf("建立時間:-"); printf("\n"); }
進程間通訊(IPC,Inter-Process Communication)指至少兩個進程或線程間傳送數據或信號的一些技術或方法。shell
共享內存容許兩個或多個進程共享必定的存儲區,由於不須要拷貝數據,因此這是最快的一種IPC。編程
原理:安全
共享內存是在多個進程之間共享內存區域的一種進程間的通訊方式,由IPC爲進程建立的一個特殊地址範圍,它將出如今該進程的地址空間中。其餘進程能夠將同一段共享內存鏈接到本身的地址空間中。全部進程均可以訪問共享內存中的地址,就好像它們是malloc分配的同樣。若是一個進程向共享內存中寫入了數據,所作的改動將馬上被其餘進程看到。#include <sys/types.h> #include <sys/stat.h> #include <sys/shm.h>
strcut shmid_ds{ struct ipc_perm shm_perm; size_t shm_segsz; time_t shm_atime; time_t shm_dtime; ...... }
int shmget(key_t key,size_t size,int shmflg); //shmget函數用來建立一個新的共享內存段, 或者訪問一個現有的共享內存段(不一樣進程只要key值相同便可訪問同一共享內存段)。第一個參數key是ftok生成的鍵值,第二個參數size爲共享內存的大小,第三個參數sem_flags是打開共享內存的方式 eg.int shmid = shmget(key, 1024, IPC_CREATE | IPC_EXCL | 0666);//第三個參數參考消息隊列int msgget(key_t key,int msgflag); void *shmat(int shm_id,const void *shm_addr,int shmflg); //shmat函數經過shm_id將共享內存鏈接到進程的地址空間中。第二個參數能夠由用戶指定共享內存映射到進程空間的地址,shm_addr若是爲0,則由內核試着查找一個未映射的區域。返回值爲共享內存映射的地址 eg.char *shms = (char *)shmat(shmid, 0, 0);//shmid由shmget得到 int shmdt(const void *shm_addr) //shmdt函數將共享內存從當前進程中分離。 參數爲共享內存映射的地址。 eg.shmdt(shms) int shmctl(int shm_id,int cmd,struct shmid_ds *buf);//shmctl函數是控制函數,使用方法和消息隊列msgctl()函數調用徹底相似。參數一shm_id是共享內存的句柄,cmd是向共享內存發送的命令,最後一個參數buf是向共享內存發送命令的參數。
#include <stdlib.h> #include <stdio.h> #include <sys/shm.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <errno.h> #define BUF_SIZE 4096 int main() { void *shm_addr = NULL; char buffer[BUF_SIZE]; int shmid; // 使用約定的鍵值建立共享內存 shmid = shmget((key_t) 1234, BUF_SIZE, 0666 | IPC_CREAT); printf("shmid : %u\n", shmid); if (shmid < 0) { perror("shmget error!"); exit(1); } // 將共享內存附加到本進程 shm_addr = shmat(shmid, NULL, 0); if (shm_addr == (void *) -1) { perror("shmat error!"); exit(1); } // 寫入數據 bzero(buffer, BUF_SIZE); sprintf(buffer, "Hello, My PID is %u\n", (unsigned int) getpid()); printf("send data: %s\n", buffer); memcpy(shm_addr, buffer, strlen(buffer)); sleep(5); // 分離 if (shmdt(shm_addr) == -1) { printf("shmdt error!\n"); exit(1); } }
ipcs -m
命令查看系統中的確存在標識符爲15466507的共享內存區域。寫進程已經跟共享內存分離,因此狀態鏈接數爲0#include <stdio.h> #include <stdlib.h> #include <sys/shm.h> #include <sys/ipc.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <errno.h> #define BUF_SIZE 4096 int main() { void *shm_addr = NULL; int shmid; // 使用約定的鍵值打開共享內存 shmid = shmget((key_t) 1234, BUF_SIZE, IPC_CREAT); printf("shmid : %u\n", shmid); if (shmid == -1) { perror("shmget error!"); exit(1); } // 將共享內存附加到本進程 shm_addr = shmat(shmid, NULL, 0); if (shm_addr == (void *) -1) { perror("shmat error!"); exit(1); } // 讀取數據 char tmp[BUF_SIZE]; bzero(tmp, BUF_SIZE); memcpy(tmp, shm_addr, BUF_SIZE); printf("read from shared memory: %s\n", tmp); sleep(5); // 分離 if (shmdt(shm_addr) == -1) { printf("shmdt error!\n"); exit(1); } // 刪除共享內存 if (shmctl(shmid, IPC_RMID, 0) == -1) { printf("shmctl error!\n"); exit(1); } }
ipcs -m
查看,沒有15466507的進程,由於讀進程執行完畢後刪除了共享內存區域在Linux系統中,咱們常常經過符號「|」來使用管道,用以鏈接兩個或多個命令。實際上,管道是進程與進程間的數據流通道,它使得數據能夠以一種「流」的形式在進程間流動。管道也是Unix/Linux系統中一種最多見的進程間通訊方式,它在兩個通訊進程之間實現一個數據流的通道從而進行信息傳遞。異步
在兩個程序之間傳遞數據的最簡單的方法是使用popen()和pclose()函數socket
#include <stdio.h> FILE *popen(const char *command, const char *open_mode); int pclose(FILE *stream);popen()函數首先調用一個shell,而後把command做爲參數傳遞給shell。這樣每次調用popen()函數都須要啓動兩個進程;可是因爲在Linux中,所(parameter expansion)都是由shell執行的,這樣command中包含的全部參數擴展均可以在command程序啓動以前完成。
pipe()函數
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *fifo_name, mode_t mode);popen()函數只能返回一個管道描述符,而且返回的是文件流(file stream),可使用函數fread()和fwrite()來訪問。pipe()函數能夠返回兩個管道描述符:pipefd[0]和pipefd[1],任何寫入pipefd[1]的數據均可pipefd[0]讀回;pipe()函數返回的是文件描述符(file descriptor),所以只能使用底層的read()和write()系統調用來訪問。pipe()函數一般用來實現父子進程之間的通訊。
代碼
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #define BUF_SIZE 256 int main() { int fd[2]; char data[] = "Hello, I am parent!"; char buf[BUF_SIZE]; pid_t pid; if (pipe(fd) < 0) { printf("pipe error!\n"); exit(1); } pid = fork(); if (pid < 0) { printf("pipe error!\n"); exit(1); } else if (pid == 0) { close(fd[1]); int len = read(fd[0], buf, sizeof(buf)); printf("child: %s\n", buf); } else { close(fd[0]); write(fd[1], data, strlen(data)); printf("parent: %s\n", data); sleep(1); } }
利用管道在父進程到子進程的通訊,而管道在兄弟進程間通訊則須要在父進程調用兩次fork函數建立兩個子進程,在兩個兄弟子進程中維護通訊管道
管道應用的一個重大限制是它沒有名字,所以,只能用於具備親緣關係的進程間通訊,在有名管道(named pipe或FIFO)提出後,該限制獲得了克服。
原理
FIFO不一樣於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即便與FIFO的建立進程不存在親緣關係的進程,只要能夠訪問該路徑,就可以彼此經過FIFO相互通訊(可以訪問該路徑的進程以及FIFO的建立進程之間),所以,經過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀老是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操做。有名管道的建立
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char * pathname, mode_t mode)
具體操做方法只要建立了一個命名管道而後就可使用open、read、write等系統調用來操做。建立能夠手工建立或者程序中建立
int mknod(const char *path, mode_t mode, dev_t dev); //第一個參數表示你要建立的文件的名稱,第二個參數表示文件類型,第三個參數表示該文件對應的設備文件的設備號。只有當文件類型爲 S_IFCHR 或 S_IFBLK 的時候該文件纔有設備號,建立普通文件時傳入0便可
代碼
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> int main() { char *pathname = "myfifo"; if (mkfifo(pathname, 0666) < 0) { perror("mkfifo error\n"); exit(1); } else { printf("create a FIFO(name : %s)\n", pathname); } }
使用ls -l
命令查看
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define BUF_SIZE 256 int main() { char buf[BUF_SIZE]; int fd; int i; fd = open("myfifo", O_WRONLY); if (fd < 0) { perror("open error!"); exit(1); } printf("open success\n"); for (i = 0; i < 10; i++) { bzero(buf, BUF_SIZE); int len = sprintf(buf, "write process: this is %dth message!", i); if (write(fd, buf, len) < 0) { perror("write error!"); close(fd); exit(1); } printf("write to fifo: %s\n", buf); sleep(2);// 休眠2秒便於觀察 } close(fd); }
代碼
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define BUF_SIZE 512 int main() { char buf[BUF_SIZE]; int fd; int len; fd = open("myfifo", O_RDONLY); if (fd < 0) { perror("open error!"); exit(1); } printf("open success\n"); bzero(buf, BUF_SIZE); while ((len = read(fd, buf, BUF_SIZE)) > 0) { printf("read from fifo: %s\n", buf); } close(fd); }
信號機制是unix系統中最爲古老的進程之間的通訊機制,用於一個或幾個進程之間傳遞異步信號。信號能夠有各類異步事件產生,好比鍵盤中斷等。shell也可使用信號將做業控制命令傳遞給它的子進程。
註冊信號處理函數
#include <signal.h> /*typedef void (*sighandler_t)(int); sighandler_t signal(int signum,sighandler_t handler);*/ * void (*signal(int signum, void (*handler)(int)))(int); //SIG_IGN && SIG_DFL * int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
發送信號
#include <signal.h> * int kill(pid_t pid,int sig); //#include <sys/types.h> * int raise(int sig); //kill(getpid(),sig); * unsigned int alarm(unsigned int seconds); //(#include <unistd.h>) seconds秒後,向進程自己發送SIGALRM信號。
信號集
typedef struct {unsigned long sig[_NSIG_WORDS];} sigset_t; * int sigaddset(sigset_t *set,int sig); * int sigemptyset(sigset_t *set);
代碼
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <errno.h> #include <sys/file.h> #include <sys/wait.h> #include <sys/stat.h> #include <cutils/xlog.h> #include <sys/types.h> static int debug_on = 0; #define TM_LOG_TAG "thermald" #define TM_DBG_LOG(_fmt_, args...) \ do { \ if (1 == debug_on) { \ sxlog_printf(ANDROID_LOG_INFO, TM_LOG_TAG, _fmt_, ##args); \ } \ } while(0) #define TM_INFO_LOG(_fmt_, args...) \ do { sxlog_printf(ANDROID_LOG_INFO, TM_LOG_TAG, _fmt_, ##args); } while(0) #define PROCFS_MTK_CL_SD_PID "/proc/driver/mtk_cl_sd_pid" static void signal_handler(int signo, siginfo_t *si, void *uc) { switch(si->si_signo) { // Add more signo or code to expand thermald case SIGIO: if(1 == si->si_code) { //待收到高溫警告後,啓動提示對話框 system("am start com.mediatek.thermalmanager/.ShutDownAlertDialogActivity"); TM_INFO_LOG("thermal shutdown signal received, si_signo=%d, si_code=%d\n", si->si_signo, si->si_code); } break; default: TM_INFO_LOG("what!!!\n"); break; } } int main(int argc, char *argv[]) { int fd = open(PROCFS_MTK_CL_SD_PID, O_RDWR); int pid = getpid(); int ret = 0; char pid_string[32] = {0}; struct sigaction act; TM_INFO_LOG("START+++++++++ %d", getpid()); /* Create signal handler */ memset(&act, 0, sizeof(act)); act.sa_flags = SA_SIGINFO;//發送額外的信息給signal_handler //act.sa_handler = signal_handler; act.sa_sigaction = signal_handler; sigemptyset(&act.sa_mask); sigaction(SIGIO, &act, NULL); /* Write pid to procfs */ sprintf(pid_string, "%d", pid); ret = write(fd, pid_string, sizeof(char) * strlen(pid_string)); //將當前的進程pid寫入proc文件系統,供內核使用 if (ret <= 0) { TM_INFO_LOG("Fail to write %d to %s %x\n", pid, PROCFS_MTK_CL_SD_PID, ret); } else { TM_INFO_LOG("Success to write %d to %s\n", pid, PROCFS_MTK_CL_SD_PID); } close(fd); TM_INFO_LOG("Enter infinite loop"); while(1) { sleep(100); } TM_INFO_LOG("END-----------"); return 0; }
消息隊列是由內核維護的一種鏈式結構。鏈表中每個記錄又稱做消息,消息具備特定的格式和優先級別
原理
各個進程經過消息隊列標識符來引用消息隊列,這樣,寫進程就能夠按照必定的規則添加新的消息,讀進程能夠按必定的規則取走消息(具體按什麼規則咱們稍後討論)。和前面介紹的共享內存和信號量同樣,消息隊列是隨內核持續的,也就是說咱們使用完畢後須要顯式刪除消息隊列。每個消息隊列都一個msqid_ds結構與之關聯。用戶可使用該結構來設置或獲取消息隊列的相關信息
struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue,unused */ struct msg *msg_last; /* last message in queue,unused */ __kernel_time_t msg_stime; /* last msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ unsigned long msg_lqbytes; /* ditto */ unsigned short msg_cbytes; /* current number of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ };
使用msgget函數來建立或打開一個消息隊列
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);
消息隊列的寫操做就是往消息隊列中發送數據(消息),主要經過msgsnd函數來執行寫操做
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
消息隊列的讀操做是指從消息隊列中讀取消息。讀操做的通常過程是:首先聲明一個msgbuf類型的消息,而後調用msgrcv函數把消息讀入該緩衝區
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
咱們可使用smgctl函數來得到或設置消息隊列的屬性
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);
#include <unistd.h> #include <sys/msg.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <string.h> #define MSG_SIZE 512 struct msgbuf { long msgtype; char msgtext[MSG_SIZE]; }; int main() { int msgid; // 建立或打開消息隊列 msgid = msgget((key_t) 2345, IPC_CREAT | 666); if (msgid == -1) { perror("msgget errno!"); exit(1); } // 發送消息 struct msgbuf data; data.msgtype = 1; bzero(&data.msgtext, MSG_SIZE); sprintf(data.msgtext, "Hello, I am msg_send.c, my pid is %u\n", getpid()); if (msgsnd(msgid, (void *) &data, MSG_SIZE, 0) == -1) { perror("msgsnd error!"); exit(1); } printf("send msg: %s\n", data.msgtext); sleep(5); }
#include <unistd.h> #include <sys/msg.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define MSG_SIZE 512 struct msgbuf { long msgtype; char msgtext[MSG_SIZE]; }; int main() { int msgid; // 建立或打開消息隊列 msgid = msgget((key_t) 2345, IPC_CREAT | 666); if (msgid == -1) { perror("msgget error!"); exit(1); } // 讀取消息 struct msgbuf data; bzero(data.msgtext, MSG_SIZE); long type = 0; if (msgrcv(msgid, (void *) &data, MSG_SIZE, type, 0) == -1) { perror("msgrcv error!"); exit(1); } printf("msg_rend.c read from msg queue: %s\n", data.msgtext); sleep(5); // 刪除消息隊列 if (msgctl(msgid, IPC_RMID, 0) == -1) { perror("msgctl error!"); exit(1); } };