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); } };