红山玉龙

导航

[转]关于exec系列函数的文件路径问题及延伸

原文地址:http://blog.csdn.net/abcdef0966/article/details/5725541

源代码:

    源代码:  
    /********************************************************* 
    prog8-8.c 
    APUE第二版 P191 程序清单8-8 exec函数实例 
     
    ************************************************************/  
    #include <stdlib.h>  
    #include <stdio.h>  
    #include <unistd.h>  
    #include <sys/wait.h>  
    #include <errno.h>  
      
    char *env_init[] = { "USER=unknown", "PATH=/tmp", NULL};  
      
    int main(void)  
    {  
        pid_t pid;  
      
        if ((pid = fork()) < 0)  
        {  
            printf("fork error.");  
            exit(1);  
        }  
        else if (pid == 0)  
        {  
            //调用prog8-9.c生成的可执行程序echoall,该可执行程序在/home/user01/apue_exercise下  
            //调用此execle相当于在echoall目录下执行./echoall myarg1 "MY ARG2"  
            if (execle("~/apue_exercise/echoall", "echoall", "myarg1", /  
                   "MY ARG2", (char*)0, env_init) < 0)  
            {  
                printf("%s/n", strerror(errno));  
                exit(1);  
            }  
        }  
      
        if (waitpid(pid, NULL, 0) < 0)  
        {  
            printf("wait error./n");  
            exit(1);  
        }  
      
        if ((pid = fork()) < 0)  
        {  
            printf("fork error./n");  
            exit(1);  
        }  
        else if (pid == 0)  
        {  
             if (execlp("echoall", "echoall", "only 1 arg", (char *)0) < 0)  
             {  
                 printf("%s/n", strerror(errno));  
                 exit(1);  
             }  
        }  
      
        exit(0);  
    }  

[注,此处APUE原书作者的代码不是这样的,请看]

 1 #include "apue.h"
 2 #include <sys/wait.h>
 3 char    *env_init[] = { "USER=unknown", "PATH=/tmp", NULL };
 4 int
 5 main(void)
 6 {
 7     pid_t   pid;
 8     if ((pid = fork()) < 0) {
 9         err_sys("fork error");
10     } else if (pid == 0) {  /* specify pathname, specify environment */
11         if (execle("/home/sar/bin/echoall", "echoall", "myarg1",
12                 "MY ARG2", (char *)0, env_init) < 0)
13             err_sys("execle error");
14     }
15     if (waitpid(pid, NULL, 0) < 0)
16         err_sys("wait error");
17     if ((pid = fork()) < 0) {
18         err_sys("fork error");
19     } else if (pid == 0) {  /* specify filename, inherit environment */
20         if (execlp("echoall", "echoall", "only 1 arg", (char *)0) < 0)
21             err_sys("execlp error");
22     }
23     exit(0);
24 }
View Code

 

#include "apue.h"

int main(int argc, char *argv[])
{
    int        i;
    char        **ptr;
    extern char    **environ;

    for (i = 0; i < argc; i++)
        printf("argv[%d]: %s\n", i, argv[i]);
    
    for (ptr = environ; *ptr != 0; ptr++)
        printf("%s\n", *ptr);
    
    exit(0);
}

 

问题:

首先,执行 gcc -o echoall prog8-9.c

这样,echoall就在prog8-9.c的目录/home/user01/apue_exercise下。

然后执行gcc prog8-8.c

./a.out

发现在exec处报错:No such file or directory

          No such file or directory

两次调用exec函数都找不到可执行文件!!

 

解决方法:

其一、

发现APUE 第二版P188页8.10exec函数一节写到:

(execlp execvp)当指定filename作为参数时:

如果filename中包含/,则将其视为路径名。

否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件。

 

于是查看当前的PATH环境变量echo $PATH, 很明显,echoall所在的目录不在PATH环境变量中,只好在执行程序前先手动将当前目录(即/home/user01/apue_exercise加上。

$export PATH=$PATH:$PWD

这样,再执行./a.out

$./a.out

输出结果:

No such file or directory

argv[0]: echoall

argv[1]: only 1 arg

 

说明execlp的调用执行正确了。那第一次调用execle为什么会出错呢?

 

其二、

if (execle("~/apue_exercise/echoall", "echoall", "myarg1", /

               "MY ARG2", (char*)0, env_init) < 0)

 

试着将这句代码中引用的路径改为:

/home/user01/apue_exercise/echoll,

if (execle("/home/user01/apue_exercise/echoall ", "echoall", "myarg1", /

               "MY ARG2", (char*)0, env_init) < 0)

再次执行:

$export PATH=$PATH:$PWD

$./a.out

输出结果:

argv[0]: echoall

argv[1]: myarg1

argv[2]: MY ARG2

argv[0]: echoall

argv[1]: only 1 arg

 执行正确!

 

那么,为什么不能在此处使用~呢?

原因是由于~只是shell对$home的引用,在系统函数中是不会对此进行相同的扩展的。

 

系统函数如何解释路径呢?

$man path_resolution

可得到相关的信息。大致意思如下:

某些unix/linux系统调用有文件名参数。文件名(或路径名)按下列方式解析:

如果路径名以/开头,则从当前进程的root目录开始查找路径。此所谓绝对路径。

如果路径名不以/开头,则从该进程的当前工作目录开始查找。此所谓相对路径。

一般情况下,每个目录都有一个”. “和 “..”, 用于表示当前目录和父目录。这也是能被正确解析的。

 

据此来看,系统调用并不能解析~。

 

试验:

因为echoall在当前工作目录下,

所以将

if (execle("/home/user01/apue_exercise/echoall ", "echoall", "myarg1", /

               "MY ARG2", (char*)0, env_init) < 0)

改为

if (execle("echoall ", "echoall", "myarg1",  "MY ARG2", (char*)0, env_init) < 0)

或者

if (execle("./echoall ", "echoall", "myarg1", /

               "MY ARG2", (char*)0, env_init) < 0)

两个路径都能被正确解析,并且能够在进程的当前目录中找到echoall,所以程序能正确运行。

posted on 2014-11-04 18:17  红山玉龙  阅读(591)  评论(0)    收藏  举报