Некоторые консольные приложения несмотря на интуитивную предрасположенность к скриптовой автоматизации предполагают интерактивное взаимодействие с пользователем, что напрочь убивает любые попытки составления простых скриптов для автоматического выполнения тех или иных действий с их помощью.
Для исправления ситуации существуют немногочисленные программы, позволяющие создавать своего рода псевдотерминалы, отслеживающие появление на консоли того или иного текста и позволяющие задать текст, автоматически отправляемый в ответ на данный текст. Типовым примером является утилита expect, требующая для работы интерпретатора tcl, или значительно более легкая и значительно менее известная утилита empty, заметно более подходящая для OpenWrt-роутеров.
В случае попытки запуска утилиты empty на роутере, работающем на процессоре архитектуры PowerPC (в частности, mpc85xx), обнаруживается, что любые действия приводят к ее моментальному сбою с сообщением о segfault’е (SIGSEGV) в системном логе:
Tue Apr 22 00:07:26 2014 kern.info kernel: [885768.318640] empty[9029]: unhandled signal 11 at 00004000 nip 4806f2a4 lr 10002180 code 30001
В ходе изучения исходников empty.c была выявлена особенность gcc-компилятора, что при вызове функции semctl() без четвертого параметра, который, в общем-то, должен бы являться необязательным, под архитектуру PowerPC генерируется некорректный код. Описание и workaround для данной проблемы представлен, к примеру, здесь (к слову, обратите внимание на дату заметки – 2003 год). Так, быстро исправить ситуацию позволяет добавление заглушки в виде указателя, к примеру, на неиспользуемую целочисленную переменную, в качестве четвертого параметра на каждом вызове функции semctl().
На базе этой информации был составлен патч mpc85xx-fix.patch:
--- a/empty.c 2014-04-22 00:04:32.317542049 +0400
+++ b/empty.c 2014-04-22 00:06:02.580442807 +0400
@@ -177,6 +177,7 @@
int fl_state = 2; /* 0 - in >>>
1 - out <<<
2 - unknown */
+ int dummy;
/* semaphores */
#ifdef _POSIX_SEMAPHORES
@@ -495,7 +496,7 @@
if (semop(sem, &free_sem, 1) == -1)
(void)perrxslog(255, "Can't release semaphore: %d from lock %m", sem);
- if (semctl(sem, 0, IPC_RMID) == -1)
+ if (semctl(sem, 0, IPC_RMID, &dummy) == -1)
(void)syslog(LOG_NOTICE, "Warning: Can't remove semaphore: %d %m", sem);
#if !defined(__SVR4) && !defined(__hpux__) && !defined(__AIX)
@@ -779,7 +780,10 @@
va_end(va);
if (sem != -1)
- semctl(sem, 0, IPC_RMID);
+ {
+ int dummy;
+ semctl(sem, 0, IPC_RMID, &dummy);
+ }
(void)closelog();
(void)exit(ex_code);
Для использования его нужно разместить в папку ./package/feeds/packages/empty/patches относительно корня каталога buildroot'а OpenWrt и затем пересобрать утилиту командой make package/feeds/packages/empty/{clean,compile}.
Что характерно, проблема проявляется только при сборке под mpc85xx (powerpc), тогда как, к примеру, утилита, собранная для ar71xx (mips32r) работает корректно.
PS: Название утилиты empty обыгрывает сокращение pty, означающее "псевдотерминал", и слово "empty", означающее "пустоту". И все было бы хорошо, не будь "empty" до такой степени распространенным словом при описании той или иной компьютерной проблемы. В результате найти в интернете хоть какие-то обсуждения утилиты empty и с добавлением дополнительных ключевых слов вроде "terminal", "console" или "utility" терпят сокрушительное фиаско. По этой причине данную утилиту больше шансов найти по не совсем логичному названию empty-expect, что подчеркивает ее связь со значительно более известной утилитой автоматизации интерактивных консольных программ - expect.