Невозможно запустить ./program с exec и makeargv в c - PullRequest
0 голосов
/ 06 мая 2018

Итак, для начала эта программа состоит из двух основных частей. Первый получает ввод из командной строки, используя fgets, а затем создает массив argv с функцией makeargv. Второй, берет этот массив argv и запускает его, используя execvp. Проблема, с которой я сталкиваюсь, заключается в том, что программа будет запускать только системные программы, такие как "ls", "pwd", "vim" и т. Д., Но не будет запускать никакие программы, если указан каталог, например "./program". Я уже пробовал разные версии exec, но единственное отличие, которое я сделал, состоит в том, что моя программа больше не будет запускать никаких команд.

Для приведенной ниже программы я вырезал весь код, который не имел отношения к вопросу, чтобы избежать путаницы.

#ifndef MAX_CANON
#define MAX_CANON 8192
#endif

int makeargv(const char *s, const char *delimiters, char ***argvp);

int main (int argc, char *argv[]) {
char cmd[MAX_CANON];
char delim[] = "\t";
char **myargv;



printf("Beginning program...\nEnter a command to execute:\n");
while(fgets(cmd, MAX_CANON, stdin) != NULL){    // Here's where I get input from the command line
    /* Remove newline from end of command */
    if (*(cmd + strlen(cmd) - 1) == '\n' || *(cmd + strlen(cmd) - 1) == ' ' )
        *(cmd + strlen(cmd) - 1) = 0;

    /*---- Child Code ----*/
    if((p = fork()) == 0){  
        if (makeargv(cmd, delim, &myargv) == -1) {  // Here is where I make the argv array
            fprintf(stderr, "Child failed to construct an argument array for %s\n", &cmd[0]);
            return 1;
        }

      fprintf(stderr, "Command is: %s\n", *&myargv[0]); 
        if(execvp(myargv[0], &myargv[0]) == -1){   // Here is where the error keeps appearing
            fprintf(stderr, "Error: Failed to execute command!\n");
            return 1;
        }
        return 0;
    } 
    /*---- Parent Code ----*/

Вот код makeargv

#include <errno.h>
#include <stdlib.h>
#include <string.h>

int makeargv(const char *s, const char *delimiters, char ***argvp) {
   int error;
   int i;
   int numtokens;
   const char *snew;
   char *t;

   if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
      errno = EINVAL;
      return -1;
   }
   *argvp = NULL;                           
   snew = s + strspn(s, delimiters);         /* snew is real start of string */
   if ((t = malloc(strlen(snew) + 1)) == NULL) 
      return -1; 
   strcpy(t, snew);               
   numtokens = 0;
   if (strtok(t, delimiters) != NULL)     /* count the number of tokens in s */
      for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ; 

                             /* create argument array for ptrs to the tokens */
   if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
      error = errno;
      free(t);
      errno = error;
      return -1; 
   } 
                        /* insert pointers to tokens into the argument array */
   if (numtokens == 0) 
      free(t);
   else {
      strcpy(t, snew);
      **argvp = strtok(t, delimiters);
      for (i = 1; i < numtokens; i++)
          *((*argvp) + i) = strtok(NULL, delimiters);
    } 
    *((*argvp) + numtokens) = NULL;             /* put in final NULL pointer */
    return numtokens;
}     

Edit:

Заменен fprintf на perror.

if(execvp(myargv[0], &myargv[0]) == -1){   // Here is where the error keeps appearing
    fprintf(stderr, "Error: Failed to execute command!\n");
    return 1;
}

if(execvp(myargv[0], &myargv[0]) == -1){   // Here is where the error keeps appearing
    perror("Error: Failed to execute command!\n");
    return 1;
}

Теперь я получаю сообщение об ошибке «Нет такого файла или каталога».

ИСПРАВЛЕНО: Программа makeargv использовала "\t" в качестве разделителя вместо " ", поэтому не создавала массив правильно.

Изменение:

char delim[] = "\t";

Кому:

char delim[] = " ";

Исправляет проблему.

1 Ответ

0 голосов
/ 15 мая 2018

Существует 2 типа исполнения:

  • Первому нужен путь в качестве среды PATH, в которой находится местоположение (где находятся исполняемые файлы sys)
  • и другие, как взять реальное местоположение файла.

Форма справочной страницы (https://linux.die.net/man/3/exec):

Функции execlp (), execvp () и execvpe () дублируют действия оболочки при поиске исполняемого файла, если указанное имя файла не содержит символ косой черты (/) .

Так что это означает, что вам нужно использовать абсолютное местоположение, которое всегда начинается с /.

Вы можете использовать getwd () и strcat () для объединения двух строк.

Для execvp:

int execvp(const char *file, char *const argv[]); // From the man (I <3 mans)

Итак:

char argv[3][] = { "/bin/ls", "/", NULL};
if (execvp("/bin/ls", argv) == -1)
      return (1);

Для evecv:

int execv(const char *path, char *const argv[]);

Есть проблема, нужна системная переменная PATH. Если вы не знаете, что это, введите "echo $ PATH" в bash. Это список каталогов, в которых система может найти двоичные файлы, такие как "ls" в "/ bin", объединенные с ":" в качестве sparator. Я нахожу точное определение здесь .

Для вашего makeargv:

Я не понимаю, почему вы так уважаете его и берете адрес после.

execvp (myargv [0], & myargv [0])

char **myargv; //That's we have 
char *const argv[]; //that's we need

//so you should try simply:
execvp(myargv[0], myargv);
//or if there is a cast problem
execvp(myargv[0], (char *const[])myargv);

Удачи!

...