注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

pgrep、pkill、killall,du及df  

2013-08-28 23:49:26|  分类: linux知识 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、通过进程名操作进程
1、pgrep及pkill
进程始终是linux下的一个关键问题,但是大部分功能都是来自对于proc文件系统的扫描。
对于进程的操作前三项可能会用到,其中比较有意思的是虽然pgrep和pkill是两个不同的应用,但是它们的二进制是一样的,他们使用相同的源代码编译生成相同的二进制,只是名字不同。如果看一下pkill所在的procps包的代码,你会发现,里面根本没有一个pkill源代码。
在pgrep内部,它通过自己的名字来区分自己将要实现的是grep还是kill功能,例如我的系统上的两个进程
[root@Harry ~]# md5sum  `which pkill pgrep`
277227a5273eaf0350291e5cbcb4e7cf  /usr/bin/pkill
277227a5273eaf0350291e5cbcb4e7cf  /usr/bin/pgrep
[root@Harry ~]# ll  `which pkill pgrep`
-rwxr-xr-x. 2 root root 16496 2009-07-28 13:19 /usr/bin/pgrep
-rwxr-xr-x. 2 root root 16496 2009-07-28 13:19 /usr/bin/pkill
[root@Harry ~]#
比较失败的地方是两个进程没有使用引用,而是自顾自的都占用了一个相同的二进制。
这里想看的是两者对于参数的处理,他们默认在匹配的时候读取的是进程的cmd字符串,默认情况下只是cmd中的命令部分,不包括参数部分,除非使用-f选项,匹配时使用正则表达式。
关键代码
if (opt_long || (match && opt_pattern)) {
            if (opt_full && task.cmdline) {
                int i = 0;
                int bytes = sizeof (cmd) - 1;

                /* make sure it is always NUL-terminated */
                cmd[bytes] = 0;
                /* make room for SPC in loop below */
                --bytes;

                strncpy (cmd, task.cmdline[i], bytes);
                bytes -= strlen (task.cmdline[i++]);
                while (task.cmdline[i] && bytes > 0) {
                    strncat (cmd, " ", bytes);
                    strncat (cmd, task.cmdline[i], bytes);
                    bytes -= strlen (task.cmdline[i++]) +
1; 将所有的命令行参数都作为匹配空间
                }
            } else {
                strcpy (cmd, task.cmd); 否则使用命令行的第一个字段,也就是进程名本身
            }
        }

        if (match && opt_pattern) {
            if (regexec (preg, cmd, 0, NULL, 0) != 0)
                match = 0;
        }

其中这个名字的由来,也就是进程的stat中显示的名字,内核中只保留了15个名称。
        cmd[16];    // stat,status     basename of executable file in call to exec(2)

例子
[root@Harry ~]# ln -s `which sleep` verylongnamesleeplink
[root@Harry ~]# ./verylongnamesleeplink 1111 &
[1] 19130
[root@Harry ~]# pgrep link
[root@Harry ~]# pgrep verylong
19130
[root@Harry ~]# cat /proc/self/stat
19137 (cat) R 12140 19137 12140 34818 19137 4194304 167 0 0 0 0 0 0 0 20 0 1 0 10418049 4059136 115 4294967295 134512640 134554840 3213844464 3213843816 16327716 0 0 0 0 0 0 0 17 0 0 0 0 0 0
[root@Harry ~]#
2、killall
这个工具并不在procps中中,而是在procmisc文件包中,里面还有fuser,及pidof等通过进程名查看文件的一些工具,但是总起来说数量不多。这个工具默认是完全名称匹配,而不是正则表达式匹配子串。
  /* mach by process name */
      for (j = 0; j < names; j++)
    {
      if (reg) 通过-r选项使能
        {
          if (regexec (&reglist[j], got_long ? command : comm, 0, NULL, 0) != 0)
              continue;
        }
      else /* non-regex */
        {
           if (!sts[j].st_dev)
            {
              if (length != COMM_LEN - 1 || name_len[j] < COMM_LEN - 1)
              {
              if (ignore_case == 1)
                {
                  if (strcasecmp (namelist[j], comm))
                     continue;
                }
              else
                {
                  if (strcmp(namelist[j], comm))
                     continue;
                }
            }
              else if (got_long ? strcmp (namelist[j], command) :
                              strncmp (namelist[j], comm, COMM_LEN - 1))
            continue;
            }
其中的comm定义
  char *path, comm[COMM_LEN];

#if 0                /* broken in 1.3.xx */
#include <linux/sched.h>
#define COMM_LEN sizeof(dummy.comm)
extern struct task_struct dummy;
#else
#define COMM_LEN 16        /* synchronize with size of comm in struct task_struct in
                   /usr/include/linux/sched.h */
#endif
从这个定义就可以看出是和之前的pgrep一样,读取的是stat文件的命令字符串。
二、du和df显示文件大小不一致
如果一个文件被删除,但是它被其它文件使用,例如一个可执行文件或者一个日志文件。如果它们比较大,那么此时使用df和du看到的空间和使用率会有较大差别。
随便使用strace看一下或者想一下就可以想明白:df是通过文件系统的控制结构来确定文件系统的空间使用量,它不依赖文件的结构,这些信息存储在一个文件系统的元数据中,通过stat就可以知道;而du则是递归遍历所有文件夹获得文件的大小,然后累加,后者操作依赖于对readdir系统调用,这个实现和ls一样,所以被删除但是还被占用的文件此时其dentry可能已经从系统中删除,此时readdir无法看到,但是由于inode还没有释放,所以此时通过文件系统的元数据看到的依然是释放前的文件大小。
df的系统调用
statfs64("/boot", 84, {f_type="EXT2_SUPER_MAGIC", f_bsize=1024, f_blocks=198337, f_bfree=176274, f_bavail=166034, f_files=51200, f_ffree=51164, f_fsid={-1911903919, 1956074336}, f_namelen=255, f_frsize=1024}) = 0
write(1, "/dev/sda1               198337  "..., 62/dev/sda1               198337     22063    166034  12% /boot
) = 62
du系统调用
[root@Harry ~]# strace du  2>&1 | grep den | more
getdents64(3, /* 66 entries */, 32768)  = 2200
getdents64(3, /* 0 entries */, 32768)   = 0
getdents64(3, /* 8 entries */, 32768)   = 264
getdents64(3, /* 0 entries */, 32768)   = 0
getdents64(3, /* 3 entries */, 32768)   = 88

这个问题本身不难理解,只是这个现象比较有意思。
  评论这张
 
阅读(708)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017