Отправка exe c вывода из функции в основной метод - PullRequest
0 голосов
/ 16 апреля 2020

У меня есть метод, который я вызываю из основного метода, который выполняет ls-l для определенного каталога, я хочу, чтобы он выполнил его и отправил результат в виде строки в основной метод.

Мой текущий дефектный код:

char *lsl(){
     char *stringts=malloc(1024);
      chdir("/Users/file/path");
      char * lsargs[] = { "/bin/ls" , "-l", NULL};
    stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
    return stringts;
}

В настоящее время я получаю только вывод exec на экране, Я понимаю почему это происходит (exec вызывается до достижения точки возврата). Однако я не знаю, как я мог бы делать то, что я хочу, и если это на самом деле выполнимо.

Я думал об использовании каналов и dup2(), поэтому я не позволяю функции exec использовать stdout, но я не знаю, возможно ли поместить вывод в строку.

Ответы [ 2 ]

2 голосов
/ 16 апреля 2020

Как уже отмечал в комментариях Джонатан Леффлер, в C нет оператора '+' для объединения строк.

Возможность динамически расширять строки - использовать reallo c вместе с strcat.

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

Вы должны сами следить за размером текущей строки. Вы можете сделать это с переменной типа size_t.

Если вы объедините это с обработкой popen, это может выглядеть примерно так:

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

int main(void) {
    FILE *fp;
    if ((fp = popen("ls -l", "r")) == NULL) {
        perror("popen failed");
        return EXIT_FAILURE;
    }

    size_t str_size = 1024;
    char *stringts = malloc(str_size);
    if (!stringts) {
        perror("stringts allocation failed");
        return EXIT_FAILURE;
    }
    stringts[0] = '\0';

    char buf[128];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
        buf[n] = '\0';
        size_t capacity = str_size - strlen(stringts) - 1;
        while (n > capacity) {
            str_size *= 2;
            stringts = realloc(stringts, str_size);
            if (!stringts) {
                perror("stringts realloation failed");
                return EXIT_FAILURE;
            }
            capacity = str_size - strlen(stringts) - 1;
        }
        strcat(stringts, buf);
    }
    printf("%s\n", stringts);
    free(stringts);
    if (pclose(fp) != 0) {
        perror("pclose failed");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
0 голосов
/ 18 апреля 2020

В вашем коде есть несколько fl aws:

char *lsl(){
     char *stringts=malloc(1024);
      chdir("/Users/file/path");
      char * lsargs[] = { "/bin/ls" , "-l", NULL};
    stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
    return stringts;
}
  • Если вы malloc(3) 1024-байтовый буфер в указатель stringts, но затем вы назначаете другое значение указатель, делающий ваш буфер потерянным в объеме вашей оперативной памяти.
  • Когда вы делаете вызов execv(2), вся память вашего процесса освобождается ядром и перезагружается при выполнении команды ls -l, вы получите вывод в стандартном выводе процесса, а затем получите подсказку оболочки. Это делает остальную часть вашей программы бесполезной, так как после того, как вы запустите c, пути назад уже нет, и ваша программа выгружена и освобождена.
  • Вы можете добавить (+) к значению указателя (вы действительно добавьте к адресу, указывающему на строку "The result of the ls -l..." и --- в результате выполнения exe c - ничто, поскольку новая программа загружена - вы ничего не получите) Если execv завершится неудачей, то вы получите указатель, указывающий на предыдущий символ этой строки, который является допустимым выражением в C, но заставляет вашу программу работать непредсказуемо в неопределенном поведении. Используйте strcpy(3), strcat(3) или snprintf(3), в зависимости от того, какой именно текст вы хотите скопировать в пространство выделенного буфера.
  • Ваш return неверный адрес в результате. Проблема в том, что, если execv(2) работает, он не возвращается. Только в случае неудачи вы получаете неверный указатель, который вы не можете использовать (по вышеуказанной причине), и, конечно, ls -l не был выполнен. Ну, вы не говорите, что вы получили, как выход, так что мне трудно догадаться, действительно ли вы exec() d программа или нет.

С другой стороны, у вас есть popen(3) библиотечная функция, которая позволяет вам выполнять подпрограмму и позволяет вам читать из файлового дескриптора его вывод (я рекомендую вам не chdir безвозмездно в вашей программе, так как это глобальное изменение в вашей программной среде, IMHO, это лучше передать ls(1) каталог, который вы хотите перечислить в качестве параметра)

#include <stdio.h>

FILE *lsl() {
    /* the call creates a FILE * descriptor that you can use as input and
     * read the output of the ls command. It's bad resources use to try to
     * read all in a string and return the string instead. Better read as
     * much as you can/need and then pclose() the descriptor. */
    return popen("/bin/ls -l /Users/file/path|", "rt");
}

и тогда вы сможете прочитать (так как это может быть очень длинный вывод, у вас, вероятно, нет достаточно буферного пространства для обработки все это в памяти, если у вас огромный каталог)

FILE *dir = lsl();
if (dir) {
    char buffer[1024]; 
    while (fgets(buffer, sizeof buffer, dir)) {
        process_line_of_lsl(buffer);
    }
    pclose(dir); /* you have to use pclose(3) with popen(3) */
}

Если вы не хотите использовать popen(3), то вы не можете использовать execv(2) в одиночку, и сначала вам нужно fork(2), создать новый процесс и exec() в дочернем процессе (после монтирования перенаправления самостоятельно). Прочитайте хорошее введение в fork() / exec() и как перенаправить ввод-вывод между fork() и exec(), так как здесь намного длиннее и подробнее, чтобы поместить его здесь (снова)

...