linux 程式引數檔案 /proc/pid/cmdline 簡介

whatday發表於2020-10-01
在proc根目錄下,以數字命名的目錄表示當前一個執行的程式,目錄名為程式的pid。其內的目錄和檔案給出了一些關於程式的資訊。
ywx@ywx:/proc/1500$ ls
ls: cannot read symbolic link cwd: Permission denied
ls: cannot read symbolic link root: Permission denied
ls: cannot read symbolic link exe: Permission denied
attr    cpuset  latency   mountstats   sched      status
auxv    cwd          limits    net          schedstat  syscall
cgroup    environ       loginuid  oom_adj      sessionid  task
clear_refs              exe       maps         oom_score  smaps      wchan
cmdline   fd            mem       pagemap      stack
comm      fdinfo        mountinfo personality  stat
coredump_filter         io        mounts       root       statm

我們可以看到該目錄下有這麼些檔案。其中attr、fd、fdinfo、task為目錄,cwd、root為指向目錄的連結,exe為指向檔案的連結,其餘為一般檔案。對於一些檔案或目錄的許可權(檢視或者修改的許可權)是該程式的建立者才有,例如auxv等檔案或目錄只有建立該程式的使用者才有檢視或修改的許可權,而其他一些檔案則對所有使用者可讀許可權。關於這些檔案或目錄的許可權,我們可以在核心中找到(fs/proc/base.c, tid_base_stuff陣列)。

在2.6.35原始碼fs/proc/base.c中;http://lxr.linux.no/linux+v2.6.35/fs/proc/base.c
static const struct    pid_entry    tid_base_stuff[] = {
    DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
    DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
    REG("environ", S_IRUSR, proc_environ_operations),
    INF("auxv", S_IRUSR, proc_pid_auxv),
    ONE("status", S_IRUGO, proc_pid_status),
    ONE("personality", S_IRUSR, proc_pid_personality),
    INF("limits", S_IRUSR, proc_pid_limits),
#ifdef    CONFIG_SCHED_DEBUG
    REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
    REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
#ifdef    CONFIG_HAVE_ARCH_TRACEHOOK
    INF("syscall", S_IRUSR, proc_pid_syscall),
#endif
    INF("cmdline", S_IRUGO, proc_pid_cmdline),
    ONE("stat", S_IRUGO, proc_tid_stat),
    ONE("statm", S_IRUGO, proc_pid_statm),
    REG("maps", S_IRUGO, proc_maps_operations),
#ifdef    CONFIG_NUMA
    REG("numa_maps", S_IRUGO, proc_numa_maps_operations),
#endif
    REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
    LNK("cwd", proc_cwd_link),
    LNK("root", proc_root_link),
    LNK("exe", proc_exe_link),
    REG("mounts", S_IRUGO, proc_mounts_operations),
    REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
#ifdef    CONFIG_PROC_PAGE_MONITOR
    REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
    REG("smaps", S_IRUGO, proc_smaps_operations),
    REG("pagemap", S_IRUSR, proc_pagemap_operations),
#endif
#ifdef    CONFIG_SECURITY
    DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
#endif
#ifdef    CONFIG_KALLSYMS
    INF("wchan", S_IRUGO, proc_pid_wchan),
#endif
#ifdef    CONFIG_STACKTRACE
    ONE("stack", S_IRUSR, proc_pid_stack),
#endif
#ifdef    CONFIG_SCHEDSTATS
    INF("schedstat", S_IRUGO, proc_pid_schedstat),
#endif
#ifdef    CONFIG_LATENCYTOP
    REG("latency", S_IRUGO, proc_lstats_operations),
#endif
#ifdef    CONFIG_PROC_PID_CPUSET
    REG("cpuset", S_IRUGO, proc_cpuset_operations),
#endif
#ifdef    CONFIG_CGROUPS
    REG("cgroup", S_IRUGO, proc_cgroup_operations),
#endif
    INF("oom_score", S_IRUGO, proc_oom_score),
    REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
#ifdef    CONFIG_AUDITSYSCALL
    REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
    REG("sessionid", S_IRUSR, proc_sessionid_operations),
#endif
#ifdef    CONFIG_FAULT_INJECTION
    REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
#endif
#ifdef    CONFIG_TASK_IO_ACCOUNTING
    INF("io", S_IRUGO, proc_tid_io_accounting),
#endif
};

下面來詳細每一個檔案和目錄的作用。

1.cmdline檔案
該檔案包含的是該程式的命令列引數,包括程式的啟動路徑(argv[0])。也就是說例如你在命令列上執行一個hello程式:

開啟一個終端:

ywx@ywx:~/desktop$ cat hello.c
#include <stdio.h>
#include <wait.h>

int main()
{
    int i=0;
    for(i=0;i<100;i++)
    {
        printf("hello world\n");
        sleep(2);
    }
    return 0;
}
ywx@ywx:~/desktop$ gcc hello.c -o hello
ywx@ywx:~/desktop$ ./hello one two
hello world
hello world
開啟另一個終端,檢視當前程式的程式號:得知程式號為
ywx@ywx:~/Desktop$ ps -A | grep hello
 2752 pts/0    00:00:00 hello

然後進入/proc/2752程式下面:

ywx@ywx:~/Desktop$ cd /proc/2752
ywx@ywx:/proc/2752$ cat cmdline
./helloonetwoywx@ywx:/proc/2752$

可以看到cmdline裡的內容為 “./helloonetwo”,正是命令列的引數。可能你會疑問為什麼引數沒有分開??那是因為cat欺騙了你。我們可以將cmdline複製到desktop下,然後用vim檢視發現是這樣的:

./hello^@one^@two^@

也就是說,實際上每個引數之間是有東西隔開的,只不過cat將其忽略而已,而vim可以給你標識出東西,但vim本身不顯示罷了。我們可以通過程式設計讀取該檔案。下面給出程式。

 
我們一個字元一個字元的讀取檔案內容直到檔案結束,在讀取每一個字元的時候,列印其字元和對應的數值。
// ywx@ywx:~/desktop$ cat readcmd.c
#include <stdio.h>// std io fopen() snprintf() feof() perrof()
int main(int argc,char *argv[])
{
    FILE *fp;
    char path[80];
    unsigned char ch;
    snprintf(path,80,"/home/ywx/desktop/cmdline");//將cmdline中內容寫入path陣列中,並在path的結尾添 加字元結束符"\0"
    if((fp=fopen(path,"r")) == NULL)
    {
        perror("fopen");
        return 0;
    }
    while(!feof(fp)) //判斷當前操作位置是否為檔案的末尾,如果是,返回一個非零值
    {
        ch=fgetc(fp);//從stream流中讀取一個字元,操作位置向下移動一個
        printf("%c %d\n",ch,ch);
    }
    fclose(fp);
    return 0;
}
ywx@ywx:~/Desktop$ gcc readcmd.c -o readcmd
ywx@ywx:~/Desktop$ ./readcmd 
. 46
/ 47
h 104
e 101
l 108
l 108
o 111
 0
o 111
n 110
e 101
 0
t 116
w 119
o 111
 0
� 255

由此我們可以看到並非是每個引數之間沒有間隔,而是以字元"\0"作為間隔。所以如果我們在某一個程式中想讀取程式的命令列引數,我們只需要知道該程式的pid,然後進入proc檔案系統的該pid對應的目錄下,程式設計讀寫讀取cmdline檔案就可以了。

 

 

相關文章