Как оболочка угадывает PATH, когда порождается в пустой среде? - PullRequest
1 голос
/ 02 октября 2011

Использование следующего кода для запуска команды ls через /bin/sh nworks fine:

#include <unistd.h>
int main(int argc, char **argv, char **envp) {
    execle("/bin/sh", "sh", "-c", "ls", (char*)NULL, envp);
}

Однако, если я запускаю оболочку в пустой среде, изменим строку execle следующим образом:

execle("/bin/sh", "sh", "-c", "ls", (char*)NULL, NULL);

Это тоже работает.

Как оболочка узнает путь к ls, хотя я не проходил никакой среды?

Ответы [ 4 ]

2 голосов
/ 02 октября 2011

Позволяет переписать вашу программу следующим образом:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv, char **envp) 
{
        execle("/bin/sh", "sh", "-c", "ls", (char*)NULL, NULL);
        return 0;
}

Теперь, как только вы скомпилируете и запустите ltrace , вы увидите следующий фрагмент кода:

<... bsearch resumed> )                                                     = NULL
strlen("ls")                                                                = 2
memcpy(0x0061cbe0, "/usr/local/sbin", 15)                                   = 0x0061cbe0
strcpy(0x0061cbf0, "ls")                                                    = 0x0061cbf0
__xstat64(1, "/usr/local/sbin/ls", 0x7fffb173e120)                          = -1
strlen("ls")                                                                = 2
memcpy(0x0061cbe0, "/usr/local/bin", 14)                                    = 0x0061cbe0
strcpy(0x0061cbef, "ls")                                                    = 0x0061cbef
__xstat64(1, "/usr/local/bin/ls", 0x7fffb173e120)                           = -1
strlen("ls")                                                                = 2
memcpy(0x0061cbe0, "/usr/sbin", 9)                                          = 0x0061cbe0
strcpy(0x0061cbea, "ls")                                                    = 0x0061cbea
__xstat64(1, "/usr/sbin/ls", 0x7fffb173e120)                                = -1
strlen("ls")                                                                = 2
memcpy(0x0061cbe0, "/usr/bin", 8)                                           = 0x0061cbe0
strcpy(0x0061cbe9, "ls")                                                    = 0x0061cbe9
__xstat64(1, "/usr/bin/ls", 0x7fffb173e120)                                 = -1
strlen("ls")                                                                = 2
memcpy(0x0061cbe0, "/sbin", 5)           
strcpy(0x0061cbe6, "ls")                                                    = 0x0061cbe6
__xstat64(1, "/sbin/ls", 0x7fffb173e120)                                    = -1
strlen("ls")                                                                = 2
memcpy(0x0061cbe0, "/bin", 4)                                               = 0x0061cbe0
strcpy(0x0061cbe5, "ls")                                                    = 0x0061cbe5
__xstat64(1, "/bin/ls", 0x7fffb173e120)                                     = 0
strlen("ls")                                                                = 2
malloc(26)                                                                  = 0x025fa110
strcpy(0x025fa123, "ls")                                                    = 0x025fa123
realloc(NULL, 160)                                                          = 0x025fa140
fork()                         

Как вы можете видеть, он явно ищет правильный путь перед выполнением fork () с '/bin/ls', который является правильным путем для 'ls'. Если задана переменная $PATH, sh попытается использовать эти пути, чтобы найти местоположение ls. Поскольку в этом случае не предусмотрено $PATH, тем не менее, вероятные пути (например, /bin, /usr/bin, /sbin) пробуются.

С execle man-page:

Если эта переменная PATH не указана, путь по умолчанию устанавливается в соответствии с _PATH_DEFPATH определение в, который установлен в /usr/bin:/bin.

1 голос
/ 02 октября 2011

Причина, по которой это может работать, заключается в том, что POSIX говорит об этом PATH:

Если PATH не установлен или имеет значение null, поиск пути определяется реализацией.

Ваш /bin/sh использует PATH по умолчанию для этого случая, который включает в себя каталог с исполняемым файлом ls. В моей системе (FreeBSD) я могу проверить это с помощью

$ strings -a /bin/sh | grep /bin:
/usr/bin:/bin:/usr/sbin:/sbin
PATH=/usr/bin:/bin
1 голос
/ 02 октября 2011

/bin/sh устанавливает множество переменных самостоятельно, если они не определены к моменту запуска. Вы можете легко увидеть полный список, набрав env -i sh -c set

Например, в моей системе:

$ env -i sh -c set
IFS='   
'
OPTIND='1'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='2299'
PS1='$ '
PS2='> '
PS4='+ '
PWD='/home/jb'

Обратите внимание, как сюда входит PATH. Также обратите внимание, что PATH получает статус только переменной; он не продвигается в экспортируемую среду. Перепроверьте это с env -i sh -c env.

$ env -i sh -c env
PWD=/home/jb
1 голос
/ 02 октября 2011

со страницы руководства execle:

On some other systems the default path (used when the environment does not contain the variable PATH) has the current working directory listed after /bin and /usr/bin, as an anti-Trojan-horse measure. Linux uses here the traditional "current directory first" default path.

Так что я думаю, ваш путь по умолчанию ./:/bin:/usr/bin, если в Linux, /bin:/usr/bin в противном случае.

...