#c #file #unix
#c #файл #unix
Вопрос:
У нас есть скрипт сборки, который создает встроенную систему для нескольких типов плат, и при захвате выходных данных одним способом, кажется, все работает нормально. С другой стороны, он частично проходит через вывод, а затем усекает файл перед продолжением.
Как это работает:
time ( cd ~ ; builder.sh 2>amp;1 | tee ~/builder.out )
И способ, которым это, кажется, усекается:
time ( cd ~ ; builder.sh > ~/builder.out 2>amp;1 )
Усечение, похоже, происходит в очень специфической точке, первая строка в файле после усечения всегда DEFAULT_INCDIRS=...
from qmake
. Тот факт, что это происходит в определенный момент процесса, а не когда файл достигает определенного размера, похоже, указывает на то, что усечение выполняется не какой-то внешней проверкой файлов.
В любом случае, если бы он был удален, скрипт продолжал бы записывать в индекс удаленного файла до тех пор, пока он не был закрыт, тогда он удалил бы указанный индекс.
На самом деле происходит то, что файл кажется усеченным, а затем запись продолжается с самого начала. Но я не знаю способа сделать это без того, чтобы программа фактически не имела доступа к самому дескриптору файла.
В обоих приведенных выше случаях скрипт builder фактически не знает о своем выходном файле, он просто записывает как выходные данные, так и сообщения об ошибках в stdout
и позволяет перенаправлению оболочки позаботиться об этом.
Итак, мои вопросы таковы: есть ли способ сделать это в модели ввода-вывода файлов UNIX (скажем, из вызовов C file API)? Другими словами, можете ли вы усечь файл, в который вы записываете, когда он был настроен с помощью перенаправления? Почему tee
вариант работает? Что мешает его усечению?
Ответ №1:
Итак, да, кто-то явно вызывает lseek()
или ftruncate()
включен stdout
, как вы уже заметили.
Чтобы отследить нарушителя, strace -f
безусловно, поможет. При выполнении чего-то столь экзотического, как это, вам может понадобиться сделать strace -f sh -c 'build.sh 2>amp;1 | cat > output' > log 2>amp;1
, потому что в противном случае он с радостью сожрет ваш вывод strace.
Как только у вас будет журнал, найдите вызов lseek(1,
, lseek(2,
, ftruncate(1,
или ftruncate(2,
. Оттуда выполните поиск в обратном направлении к предыдущему exec
, и вы должны знать.
Одна из программ, которая на законных основаниях выполняет игры с stdout
is cdrecord
, по крайней мере, некоторые версии которой хотят, чтобы ваш CD-диск записывался на стандартный вывод.
Комментарии:
1. Наш процесс сборки занимает 40 минут на плату, я не уверен, что у нас есть возможность хранить данные на 40 минут, но я посмотрю, что смогу найти 🙂
2. @paxdiablo: Используйте ssh и передавайте его куда-нибудь еще, например, на свою рабочую станцию, если это необходимо.
Ответ №2:
Хорошо, оказывается, что программы могут выполнять поиск по стандартному выводу (хотя я удивляюсь здравомыслию программ, которые это делают).
Следующая программа иллюстрирует это:
#include <stdio.h>
int main(void){
for (int i = 3; i > 0; --i) {
//rewind(stdout);
printf("Hello, world %d !n", i);
}
return 0;
}
Запустите это, записывая выходные данные, и в итоге вы получите файл, содержащий:
Hello, world 3 !
Hello, world 2 !
Hello, world 1 !
Однако, если вы раскомментируете rewind
строку, в конечном итоге вы получите только последнюю строку в выходном файле.
Достаточно интересно, что, поскольку я не контролирую усечение программы stdout
, это может быть полезным использованием cat для награды «бесполезное использование cat». Вместо выполнения:
myprog >outfile 2>amp;1
и, myProg
сократив файл, я могу вместо этого сделать:
myprog 2>amp;1 | cat >outfile
и конвейер защитит cat
выходной файл от усечения.
С точки зрения фактического вопроса, похоже, что qt5base
(часть buildroot
) по какой-то причине использует какие-то махинации с дескриптором выходного файла. Мы решили это с помощью cat
метода, описанного выше, поскольку у нас нет времени запускать buildroot (или создавать файлы исправлений), чтобы исправить это должным образом.
Комментарии:
1. Вы также можете попробовать
myprog >> outfile 2>amp;1
. Большинство оболочек реализуют это, открывая outfile в режиме только добавления, в котором все записи принудительно выполняются в конце файла независимо от того, что сделал lseek.