Есть ли недостатки в использовании вызовов system () вместо функций вашего языка программирования?

Я программирую на C, чтобы создать API для встроенного устройства. Это встроенное устройство работает под управлением версии Linux. Я не очень знаком с C - я больше знаком со сценариями оболочки / bash.

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

Есть ли недостатки в выполнении этих вызовов system и popen вместо того, чтобы выяснять, как сделать каждую из этих вещей в C, а затем использовать функции C.


person Pimgd    schedule 02.07.2015    source источник
comment
Тогда вам следует написать сценарий bash. Зачем тебе это в c? И неправда, что так проще, обработка вывода болезненна.   -  person Iharob Al Asimi    schedule 02.07.2015
comment
@iharob Коммуникационная библиотека предоставляет только интерфейс C, поэтому я должен использовать C для API. Это для IP-камеры, и один из запросов API - сколько места осталось на SD-карте? Для этого я мог бы либо вызвать некоторые команды оболочки, либо реализовать функции C, касающиеся использования диска ... но я уже знаком с командами оболочки.   -  person Pimgd    schedule 02.07.2015
comment
Все делайте с помощью c, не вызывайте системные утилиты. Их вывод в c трудно разобрать.   -  person Iharob Al Asimi    schedule 02.07.2015
comment
@iharob, который звучит как допустимый недостаток, функции C имеют хорошо документированный и полезный вывод, который не требует grepping или фильтрации ... что означает, что я буду иметь дело с вещами в индивидуальном порядке? Если есть простая команда оболочки, используйте ее, иначе используйте функцию C?   -  person Pimgd    schedule 02.07.2015
comment
Нет, вообще не используйте никакие команды оболочки из c, это сделало бы очень опасную программу на c.   -  person Iharob Al Asimi    schedule 02.07.2015
comment
Какую библиотеку вы хотите использовать?   -  person Iharob Al Asimi    schedule 02.07.2015
comment
Опасно Я имею в виду, что программа практически выполнит что угодно, вы не можете быть уверены, что она будет выполнять.   -  person Iharob Al Asimi    schedule 02.07.2015
comment
@iharob nabto.com/#download-list библиотека uNabto - это то, что я использую для связи . ... Кроме того, я понимаю, что выполнение пользовательского ввода может быть не лучшим, но зачем жестко запрограммировать, например. system("[ -e /mnt/sd/video ]") уметь что-нибудь выполнить?   -  person Pimgd    schedule 02.07.2015
comment
@iharob Он не выполняет опасные команды оболочки, а выполняет произвольный, ненадежный ввод пользователя как опасную команду оболочки. Создание командных строк в вашем коде из значений, которые вы контролируете, совершенно безопасно (хотя и неэффективно).   -  person chepner    schedule 02.07.2015
comment
@chepner Не обязательно, если вы измените переменную окружения текущего пользователя PATH и поместите вредоносный скрипт с именем какой-то из программ, выполняемых кодом c, то ...!   -  person Iharob Al Asimi    schedule 02.07.2015
comment
@chepner - Только если вы точно знаете, что делаете, и ничего не пропустите. Например, переменная среды IFS.   -  person Andrew Henle    schedule 02.07.2015
comment
Вы можете жестко запрограммировать имена путей для фактических команд. Если кто-то заменил /bin/ls, например, вредоносным кодом, что ж, у вас в системе больше проблем, чем у вашей программы.   -  person chepner    schedule 02.07.2015
comment
Как насчет того, чтобы пользователь установил LD_PRELOAD для запуска своего system() вместо поставляемого libc system()? Никаких системных компромиссов.   -  person Andrew Henle    schedule 02.07.2015
comment
Для моей модели безопасности, когда у клиента есть root-доступ или физический доступ к своей системе, меня больше не волнует. Если кто-то может дотронуться до камеры, он может схватить молоток и разбить его на тысячу крошечных битов. Возможность припаивать к нему провод и загружать в него вредоносные команды только для того, чтобы заставить мой код творить злые дела, не имеет значения, потому что к этому моменту вы могли бы просто удалить мой код и поместить туда свой собственный.   -  person Pimgd    schedule 02.07.2015


Ответы (4)


В конце концов, в системе Linux почти все в какой-то момент вызывают функции C.

Чтобы коснуться некоторых аргументов в комментариях, а также моих собственных мыслей:

  1. Выполнение команд оболочки из программы c, особенно при использовании аргументов пользователя, является потенциальной уязвимостью. Например, если вы разрешили пользователю вызывать вашу программу с аргументом «foo; rm -rf *»; в зависимости от того, как вы вызываете оболочку, есть вероятность, что вы могли бы эффективно вызвать «mkdir foo; rm -rf *», если вы хотите сделать каталог, предоставленный пользователем. Это может быть или не иметь большого значения в зависимости от того, насколько вы доверяете своим пользователям и т. Д.
  2. Выполнение команд оболочки приводит к потенциальным состояниям гонки, которых вы не можете избежать, с которыми можно было бы легче справиться, используя прямые системные вызовы, которые вы объединяете в цепочку.
  3. Анализ вывода команд означает работу с большим количеством строковых операций в C, что менее чем забавно.
  4. Если вы действительно предпочитаете bash, лучше всего, вероятно, реализовать небольшие программы, которые обертывают отдельные части C API вашей целевой библиотеки. В любом случае, это путь UNIX (tm).

ИЗМЕНИТЬ, чтобы ответить на комментарий Pimgd: обратите внимание, что условия гонки - это головная боль, и многие из них не обязательно являются проблемой для вашего конкретного варианта использования, но, по крайней мере, их стоит учитывать при взвешивании за / против. В любом случае, конкретные экземпляры состояния гонки, о которых я думал, включают (и, вероятно, есть другие классы):

  1. Условия гонки типа безопасности. Если вы создаете временный файл, содержащий набор команд, а затем выполняете его, существует вероятность, что между созданием и выполнением кто-то войдет и изменит файл. (На самом деле существует множество вариантов этой темы для таких вещей, как установка / сброс символьных ссылок и т. Д.). Судя по вашим комментариям, это в значительной степени выходит за рамки вашего проекта, но это то, о чем следует знать для других приложений.
  2. Условия многопроцессорной гонки. Самый простой пример, который я могу придумать, - это то, что происходит, если два экземпляра вашей программы хотят установить файл конфигурации и работают одновременно. Существуют определенные вызовы ОС, которые имеют определенные уровни гарантии атомарности, но вы теряете большую часть этого, если вызываете серию команд оболочки для записи в файл. (обратите внимание, что даже если вы делаете это из монолитного приложения C, а не из серии команд оболочки, вам все равно нужно будет сделать что-то дополнительное, чтобы экземпляр 1 не перезаписал изменение экземпляра 2, но вы, по крайней мере, вряд ли столкнетесь с В случае, если в результате вы столкнетесь с смешанными изменениями. В качестве примера рассмотрим:

    ФАЙЛ * fp = fopen ("config.txt", "wt");

    fprintf (fp, «Значение конфигурации 1:% s», config [0]);

    fprintf (fp, «Значение конфигурации 2:% s», config [1]);

    fflush (fp);

    fclose (fp);

vs.

system("echo Config value 1: `df | awk '{print $1}'` > config.txt");
system("echo Config value 2: `ps | grep foo | awk '{print $2}'` >> config.txt");

Где, если два экземпляра программы выполняются почти в одно и то же время, вы можете получить, например, 2 экземпляра значения конфигурации 2 в файле конфигурации в последнем случае.

person Foon    schedule 02.07.2015
comment
Хороший список. Легко понять, о чем говорят такие люди. Вы упоминаете о потенциальных условиях гонки? Это связано с использованием команд оболочки, или вы говорите о таких вещах, как использование команд оболочки для выполнения задачи в фоновом режиме, которая будет выполнена в какой-то момент в будущем (представляя промежуточное состояние полуобработки?). - person Pimgd; 02.07.2015

Минусы:

  1. это небезопасно, если есть ввод пользователя
  2. трудно разобрать вывод
  3. он будет полагаться на что-то внешнее, например сценарий оболочки.
  4. тяжелый процесс - system fork () и запустить другую программу параллельно

Плюсы:

  1. легко реализовать
  2. в зависимости от вывода программы синтаксический анализ может быть очень простым. пример system("ls -1");

Суммировать -

Все зависит от того, что вам нужно делать, но в общем случае отрицательных моментов больше, чем положительных.

person Nick    schedule 02.07.2015

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

Еще одна вещь, которую следует учитывать, заключается в том, что анализ вывода команд оболочки из c ужасно сложен.

И, наконец, вы не можете заставить свою программу случайным образом вызывать системную утилиту или сценарий оболочки просто потому, что это небезопасно.

person Iharob Al Asimi    schedule 02.07.2015
comment
Хороший отзыв о доступности, это может быть проблемой. В частности, для меня это не проблема (написание кода для одной конкретной системы), но могло быть. Анализировать вывод иногда просто, иногда сложно. На самом деле зависит от того, что вы делаете. Что касается последнего пункта, как говорили другие, это риск пользовательского ввода или случайного ввода, выполняемого в системе - выполнение жестко закодированных команд несет гораздо меньший риск. - person Pimgd; 02.07.2015
comment
@Pimgd less - это не 0, но заставляет меня думать ... 0 риска никогда не бывает. Попробуйте это echo 'echo "This is a virus, I will delete your home directory."' > ls; chmod +x ls; export PATH=${PWD}:${PATH};, а теперь просто перечислите содержимое каталога ls, теперь вы понимаете, о чем я ?. - person Iharob Al Asimi; 02.07.2015
comment
Я просто забываю, что делал это, и теперь он печатает This is a virus, I will delete your home directory. каждый раз, когда я набираю ls, что очень часто. Видишь, это подло. - person Iharob Al Asimi; 02.07.2015
comment
Чтобы внести это изменение, у вас должен быть доступ с достаточным количеством прав для его перезаписи. Это требует, чтобы вы обошли текущую безопасность камеры. Моя модель безопасности не включает защиту от угроз с таким уровнем доступа, потому что вместо изменения ls они просто изменяют myExecutable. Или просто прошейте руткит во внутреннюю память. - person Pimgd; 02.07.2015

Возможно, это правильный подход, если вы более знакомы со сценариями оболочки, чтобы сделать это следующим образом:

Используйте сценарий оболочки в качестве основы, которая выполняет все высокоуровневые вычисления. Этот сценарий может использовать одну (или несколько) команд для обращения к API; только чтобы предоставить эти команды, напишите небольшие программы на C.

Например:

#!/bin/bash
valueA=$(APIhelper -q valueA)
valueB=$(APIhelper -q valueB)

process() { … }

result=$(process "$valueA" "$valueB")

APIhelper -s result "$result"

Эта часть должна быть понятна, если вы разбираетесь в сценариях оболочки.

Теперь вам нужно только написать двоичный файл APIhelper (выберите более подходящее имя в зависимости от вашего контекста ;-).

Это может быть такая программа на C:

int main(int argc, char *argv[]) {
  if (argc > 1) {
    if (strstr(argv[1], "-q") == 0) {
      if (argc > 2) {
        char *variableName = argv[2];
        someType result = makeYourApiCall(variableName);
        printf("%O\n", result);  # use a fitting format instead of %O!
      } else {
        fprintf(stderr, "-q without variable name\n");
        exit(1);
      }
    else if (strstr(argv[1], "-s") == 0) {
      …
    } else {
      fprintf(stderr, "option not understood: %s\n", argv[1]);
      exit(1);
    }
  } else {
    fprintf(stderr, "missing option\n");
    exit(1);
  }
  return 0;
}

Таким образом, в программе на C выполняется только самая базовая обработка API, и вы можете придерживаться того, что лучше всего кодируете в: скриптах. Кроме того, таким образом вы можете легко отлаживать свой API, потому что этот инструмент APIhelper можно вызывать из командной строки в интерактивном режиме.

person Alfe    schedule 02.07.2015
comment
Этот подход лучше всего работает для простых значений, таких как целые числа и небольшие строки. Это будет сложно (а затем, вероятно, неосуществимо), если ваш API будет обрабатывать сложные структуры данных, такие как словари списков записей чего угодно. - person Alfe; 02.07.2015
comment
Это кажется отличным способом справиться с ситуацией, если библиотека предоставила свой интерфейс в сценариях оболочки. К сожалению (но, возможно, более логично с их стороны), он предоставляет свой интерфейс на C, поэтому мой код больше похож на веб-сервер, обслуживающий кучу .cgi, каждый из которых выполняет небольшую и простую функцию после массивного переключения. Престижность за идею, лежащую в основе этого подхода. - person Pimgd; 02.07.2015