C Проверка существования файла перед вызовом execvp

Я пишу мини-оболочку UNIX на Ubuntu и сейчас пытаюсь добавить встроенные команды. Когда это не встроенная команда, я разветвляю ее, а затем ее выполняет дочерний элемент, однако для встроенных команд я просто выполняю ее в текущем процессе.

Итак, мне нужен способ узнать, существуют ли файлы (если они существуют, это не встроенная команда), однако execvp использует переменную среды PATH для их автоматического поиска, поэтому я понятия не имею, как я буду вручную проверять заранее.

Итак, ребята, вы знаете, как я могу проверить аргумент, чтобы увидеть, является ли он встроенной командой, просто указав имя?

Спасибо, парни.


person robins35    schedule 07.10.2012    source источник
comment
Если вы знаете, какие у вас встроенные команды, почему бы вам не проверить, является ли программа таковой, просмотрев список встроенных команд? Вы управляете ими, верно? Или реальный вопрос, как проверить наличие файла в C?   -  person nemo    schedule 07.10.2012
comment
Это хороший момент, так было бы больше смысла. Я сохраняю встроенные функции в другом файле .c, есть ли простой способ проверить, существуют ли функции в области основного файла?   -  person robins35    schedule 07.10.2012
comment
Я не уверен, что вы пытаетесь. Существуют есть способы узнать, какие функции определены в C, но прежде чем вы это сделаете, вы должны спросить себя, правильно ли вы там делаете. Проверка IMO, является ли предоставленная команда встроенной, не должна быть чем-то большим, чем поиск в списке строк или что-то подобное.   -  person nemo    schedule 07.10.2012
comment
Обратите внимание, что test — это встроенная оболочка; она выполняется оболочкой, даже если вы пишете тестовую программу с именем test, если вы вызываете test без пути (но если вы указываете путь, то используется ваша программа ./test). Это вызывает путаницу при первом программировании в Unix. Точно так же, если я создаю команду с именем cd, оболочка игнорирует ее и вызывает свою встроенную команду, когда имя просто cd (но, как и раньше, если в имени команды есть путь, такой как ./cd, то это вызывается оболочка).   -  person Jonathan Leffler    schedule 07.10.2012
comment
Я посмотрел на тест, но я не совсем уверен, что это такое. В другом посте вы сказали, что я не должен явно искать существование определенной функции, а должен явно искать существование файла. Я совсем запутался, я собирался просто попытаться найти способ увидеть, существует ли функция в основной области видимости, а если нет, то она не встроена.   -  person robins35    schedule 07.10.2012


Ответы (4)


Я проверил ответ Тома

Он содержал ряд проблем. Я исправил их здесь и предоставил тестовую программу.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

int is_file(const char* path) {
    struct stat buf;
    stat(path, &buf);
    return S_ISREG(buf.st_mode);
}

/*
 * returns non-zero if the file is a file in the system path, and executable
 */
int is_executable_in_path(char *name)
{
    char *path = getenv("PATH");
    char *item = NULL;
    int found  = 0;

    if (!path) 
        return 0;
    path = strdup(path);

    char real_path[4096]; // or PATH_MAX or something smarter
    for (item = strtok(path, ":"); (!found) && item; item = strtok(NULL, ":"))
    {
        sprintf(real_path, "%s/%s", item, name);
        // printf("Testing %s\n", real_path);
        if ( is_file(real_path) && !(
               access(real_path, F_OK) 
            || access(real_path, X_OK))) // check if the file exists and is executable
        {
            found = 1;
        }
    }

    free(path);
    return found;
}

int main()
{
    if (is_executable_in_path("."))
        puts(". is executable");
    if (is_executable_in_path("echo"))
        puts("echo is executable");
}

Заметки

  1. проверка возвращаемого значения access была отменена
  2. второй вызов strtok имел неправильный разделитель
  3. strtok изменил аргумент path. В моем образце используется копия
  4. не было ничего, что могло бы гарантировать правильный разделитель пути в объединенном real_path
  5. не было проверки, действительно ли совпадающий файл был файлом (каталоги также могут быть «исполняемыми»). Это приводит к таким странным вещам, как ., распознаваемый как внешний двоичный файл.
person sehe    schedule 07.10.2012

Что вы можете сделать, так это изменить путь к конкретному каталогу, а затем использовать заголовочный файл #include<dirent.h> и его функции readdir и scandir для просмотра каталога или структуры stat, чтобы увидеть, существует ли файл в каталоге или нет.

person Recker    schedule 07.10.2012

Вы можете перебирать каталоги PATH и для каждой записи в PATH (вам придется разделить PATH на :, возможно, используя strtok) объединяют в конце каждого пути имя вызываемой команды. Когда вы создадите этот путь, проверьте, существует ли файл и является ли он исполняемым, используя доступ .

int is_built_in(char *path, char *name)
{
  char *item = strtok(path, ":");

  do {
    char real_path[4096] = strcat(item, name); // you would normally alloc exactly the size needed but lets stick to it for the sake of the example
    if (!access(real_path, F_OK) && !access(real_path, X_OK)) // check if the file exists and is executable
      return 0;
  } while ((item = strtok(NULL, ":")) != NULL);
  return 1;
}
person tomahh    schedule 07.10.2012
comment
Спасибо, я попытаюсь явно искать встроенные функции, но если это не сработает, я сделаю это. - person robins35; 07.10.2012
comment
Вы можете сделать это, но на практике быстрее и надежнее вызывать execve() для каждого элемента — или даже просто позволить execvp() выполнять эту работу — чем заставлять систему проверять с помощью access. Кроме всего прочего, результаты access() не обязательно учитывают списки управления доступом. Использование strtok() в PATH тоже опасно; он искажает путь, поэтому вы не сможете повторно использовать его при следующем вызове. - person Jonathan Leffler; 07.10.2012

Почему вы хотите проверить перед вызовом execvp? Это неправильный подход. Просто позвоните execvp, и он сообщит вам, если программа не существует.

person R.. GitHub STOP HELPING ICE    schedule 07.10.2012