LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1196|回复: 6

关于execl:为什么参数要两个ls ?

[复制链接]
发表于 2004-1-4 17:02:44 | 显示全部楼层 |阅读模式
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
  pid_t pid;
  if((pid=fork())<0) {
    printf("fork error\n");
    exit (0);
  }
  if (pid ==0) {
   execl("/bin/ls","ls","-F",(char *) 0);
   exit (0);
  }
exit (0);
}
不明白为什么要两个ls ?:help :help
 楼主| 发表于 2004-1-4 21:21:42 | 显示全部楼层
看了http://chinaunix.net/jh/23/227365.html不太明白。
请问这些话都对吗?

我看到的源代码OS版本是
!uname -a
Linux db4.localdomain 2.4.20-8smp #1 SMP &#200;& 7&#212;&#194; 23 8:58:25 CST 2003 i686 i686 i386 GNU/Linux

和exec相关的有两大块,一是arch下面,主要是控制不同体系结构上的差异。另外一个是fs目录,主要是exec.c。

函数do_execve是执行exec系列函数的入口,这个函数代码比较少,可以看看。

[code:1:c10dec9753]
int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
{
struct linux_binprm bprm;
struct file *file;
int retval;
int i;

file = open_exec(filename);

retval = PTR_ERR(file);
if (IS_ERR(file))
return retval;

bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));

bprm.file = file;
bprm.filename = filename;
bprm.sh_bang = 0;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
allow_write_access(file);
fput(file);
return bprm.argc;
}

if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
allow_write_access(file);
fput(file);
return bprm.envc;
}

retval = prepare_binprm(&bprm);
if (retval < 0)
goto out;

retval = copy_strings_kernel(1, &bprm.filename, &bprm);
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);
if (retval < 0)
goto out;

retval = search_binary_handler(&bprm,regs);
if (retval >= 0)
/* execve success */
return retval;

out:
/* Something went wrong, return the inode and free the argument pages*/
allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);

for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
struct page * page = bprm.page;
if (page)
__free_page(page);
}

return retval;
}
[/code:1:c10dec9753]
这个函数相关两个重要的数据结构,一个是第一局定义
struct linux_binprm bprm;
结构linux_binprm可以参看头文件,主要保存运行程序的参数和框架。
还有一个是pt_regs ,主要存储调用时候的寄存器信息。

这个函数大体上完成了如下功能:
1、open_exec初始化文件。
2、检查和设置参数,并且清除页表
3、调用prepare_binprm检查文件类型。文件全县还有文件状态(例如是否处于修改状态),设置uid和gid等
4、调用copy_strings(),这个是我们分析的重点。
5、调用search_binary_handler,这函数负责查找可执行文件的格式

同一个文件中copy_strings()
while(1)中
[code:1:c10dec9753]
int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
{
        struct page *kmapped_page = NULL;
        char *kaddr = NULL;
        int ret;

        while (argc-- > 0) {
                char *str;
                int len;
                unsigned long pos;

                if (get_user(str, argv+argc) ||
                                !(len = strnlen_user(str, bprm->p))) {
                        ret = -EFAULT;
                        goto out;
                }

[/code:1:c10dec9753]
从如上的代码get_user处可以看出来,的确copy了argv的最后一个符号到str,后面的代码北配好空间后
     err = ll_copy_from_user(kaddr+offset, str, bytes_to_copy
这时候执行的用户空间串便是str。

看看楼主的问题,最后copy到核心的是多了一个'/'. (/bin/more//more)


如有错误,请各位指正。


的确如此,execl ("/bin/maor", "/more" ...); 中,第二个 "/more" 被原封不动地传给了内核。

execl (path_name, argv[0], argv[1], .....);

其中 path_name 是一个绝对路径, argv[?] 是传给新进程的参数, 很有意思的是 argv[0] 不必是正确的文件名, 实际上可以是任何字符串。(见前面约翰牛的贴子)

在/test 目录下

1.c : --> 生成 b.out

int
main (int argc, char **argv)
{
printf ("%s\n", argv[0]);
exit (0);
}

2.c: --> 生成 a.out
int
main (int argc, char **argv)
{
execl ("/test/b.out", "fake file name", NULL);
exit (0);
}

执行 /test/a.out 得到

"fake file name"

argv[0] 的值是给新进程使用的,内核应该只起到了传递的作用,是否真实,内核并不关心。


:help
发表于 2004-1-5 00:18:31 | 显示全部楼层

回复: 关于execl:为什么参数要两个ls ?

最初由 home 发表
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
  pid_t pid;
  if((pid=fork())<0) {
    printf("fork error\n");
    exit (0);
  }
  if (pid ==0) {
   execl("/bin/ls","ls","-F",(char *) 0);
   exit (0);
  }
exit (0);
}
不明白为什么要两个ls ?:help :help


man一下就知道了吧!

int execle (conts char *pathname ,const char *arg0 ,.../*(char *)0, char *const envp []*/);
 楼主| 发表于 2004-1-5 16:59:55 | 显示全部楼层

回复: 回复: 关于execl:为什么参数要两个ls ?

最初由 flavor 发表
man一下就知道了吧!

int execle (conts char *pathname ,const char *arg0 ,.../*(char *)0, char *const envp []*/);

E文不好,还有基础差,有了函数原型有时也不懂得怎么用
发表于 2004-1-5 17:12:13 | 显示全部楼层
execl的第一个参数是可执行文件的路径,第二个参数是传给可执行文件的第一个参数,
int main(int argc, char *argv[])
一般argv[0]就是文件名,实际上这个就是execle的第二个参数

execl("/bin/ls","ls","-F",(char *) 0);
"/bin/ls"是可执行文件
"ls"是执行的文件的argv[0]
"-F"是执行的文件的argv[1]
 楼主| 发表于 2004-1-5 20:01:21 | 显示全部楼层
:thank :thank
发表于 2004-1-5 23:33:51 | 显示全部楼层
推荐你看一本书
《UNIX环境高级编程》
这些细节问题书上讲得很详细的
我最近也在看
如果暂时不想买的话我有电子版的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表