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

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

从shell执行文件到ps显示  

2010-11-24 21:15:10|  分类: Linux内核 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

当我们从shell中执行一个命令的时候,shell将会从PATH中找到这个制定的文件,然后使用这个完整路径作为exeve的第一个参数,然后把你的输入作为完整的argv(这里就包含了你输入的最为原始的整个字符串,包括用来表示可执行文件名称的字符串)。对应的代码及简单执行流程在bash3.0中为:

execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
        async, fds_to_close, cmdflags)

  pathname = words->word->word;
  command = search_for_command (pathname);

/* Look for PATHNAME in $PATH.  Returns either the hashed command
   corresponding to PATHNAME or the first instance of PATHNAME found
   in $PATH.  Returns a newly-allocated string. */
char *
search_for_command (pathname)
     const char *pathname;
{
  char *hashed_file, *command;
  int temp_path, st;
  SHELL_VAR *path;

  hashed_file = command = (char *)NULL;

  /* If PATH is in the temporary environment for this command, don't use the
     hash table to search for the full pathname. */
  path = find_variable_internal ("PATH", 1);
  temp_path = path && tempvar_p (path);
  if (temp_path == 0 && path)
    path = (SHELL_VAR *)NULL;

  /* Don't waste time trying to find hashed data for a pathname
     that is already completely specified or if we're using a command-
     specific value for PATH. */
  if (path == 0 && absolute_program (pathname) == 0)
    hashed_file = phash_search (pathname);

  /* If a command found in the hash table no longer exists, we need to
     look for it in $PATH.  Thank you Posix.2.  This forces us to stat
     every command found in the hash table. */

  if (hashed_file && (posixly_correct || check_hashed_filenames))
    {
      st = file_status (hashed_file);
      if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0)
 {
   phash_remove (pathname);
   free (hashed_file);
   hashed_file = (char *)NULL;
 }
    }

  if (hashed_file)
    command = hashed_file;
  else if (absolute_program (pathname))
    /* A command containing a slash is not looked up in PATH or saved in
       the hash table. */
    command = savestring (pathname);
  else
    {
      /* If $PATH is in the temporary environment, we've already retrieved
  it, so don't bother trying again. */
      if (temp_path)
 {
   command = find_user_command_in_path (pathname, value_cell (path),
            FS_EXEC_PREFERRED|FS_NODIRS);
 }
      else
 command = find_user_command (pathname);
      if (command && hashing_enabled && temp_path == 0)
 phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
    }
  return (command);
}


这里也比较有意思,就是判断一个路径是否是绝对路径的方法就是判断指定的字符串之间是否有一个路径分隔符

/* Return 1 if STRING is an absolute program name; it is absolute if it
   contains any slashes.  This is used to decide whether or not to look
   up through $PATH. */
int
absolute_program (string)
     const char *string;
{
  return ((char *)xstrchr (string, '/') != (char *)NULL);
}

不管怎样,操作之后command将指向系统的可执行文件的绝对路径:

      /* Execve expects the command name to be in args[0].  So we
  leave it there, in the same format that the user used to
  type it in.
*/
      args = strvec_from_word_list (words, 0, 0, (int *)NULL);这里将所有用户输入的内容作为路径传递给可执行文件,作为argv[0], argv[1]等,从而原封不动的保存了用户在shell中输入的内容,也让用户知道自己的名字
      exit (shell_execve (command, args, export_env));

然后进入内核:

/*
 * sys_execve() executes a new program.
 */
int do_execve(char * filename,
 char __user *__user *argv,
 char __user *__user *envp,
 struct pt_regs * regs)

 

 retval = copy_strings_kernel(1, &bprm->filename, bprm); 在用户堆栈的最顶端(这里的说法并不准去,因为在更上面可能还有为ld.so准备的加载信息)放置的是可执行文件的绝对路径
 if (retval < 0)
  goto out;

 bprm->exec = bprm->p;
 retval = copy_strings(bprm->envc, envp, bprm); 然后是存放环境变了数组
 if (retval < 0)
  goto out;

 retval = copy_strings(bprm->argc, argv, bprm);然后是argc的内容
 if (retval < 0)
  goto out;

void setup_new_exec(struct linux_binprm * bprm)
name = bprm->filename;

 /* Copies the binary name from after last slash */
 for (i=0; (ch = *(name++)) != '\0';) {
  if (ch == '/')
   i = 0; /* overwrite what we wrote */
  else
   if (i < (sizeof(tcomm) - 1))
    tcomm[i++] = ch;
 }
 tcomm[i] = '\0';
 set_task_comm(current, tcomm);

内核将会从可执行文件的绝对路径中最后一个分号之后的内容作为可执行文件的绝对路径

 

当执行ps时,ps将会从 /proc/task/cmdlines中读取可执行文件的绝对路径即参数,这个内容同样是在内核中实现:

static int proc_pid_cmdline(struct task_struct *task, char * buffer)
{
 int res = 0;
 unsigned int len;
 struct mm_struct *mm = get_task_mm(task);
 if (!mm)
  goto out;
 if (!mm->arg_end)
  goto out_mm; /* Shh! No looking before we're done */

  len = mm->arg_end - mm->arg_start;
 
 if (len > PAGE_SIZE)
  len = PAGE_SIZE;
 
 res = access_process_vm(task, mm->arg_start, buffer, len, 0);

 // If the nul at the end of args has been overwritten, then
 // assume application is using setproctitle(3).
 if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
  len = strnlen(buffer, res);
  if (len < res) {
      res = len;
  } else {
   len = mm->env_end - mm->env_start;
   if (len > PAGE_SIZE - res)
    len = PAGE_SIZE - res;
   res += access_process_vm(task, mm->env_start, buffer+res, len, 0);
   res = strnlen(buffer, res);
  }
 }
out_mm:
 mmput(mm);
out:
 return res;
}

create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
  unsigned long load_addr, unsigned long interp_load_addr)

/* Populate argv and envp */
 p = current->mm->arg_end = current->mm->arg_start;
 while (argc-- > 0) {
  size_t len;
  if (__put_user((elf_addr_t)p, argv++))
   return -EFAULT;
  len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
  if (!len || len > MAX_ARG_STRLEN)
   return -EINVAL;
  p += len;
 }
 if (__put_user(0, argv))
  return -EFAULT;
 current->mm->arg_end = current->mm->env_start = p;

  评论这张
 
阅读(820)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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