Некоторые консольные приложения несмотря на интуитивную предрасположенность к скриптовой автоматизации предполагают интерактивное взаимодействие с пользователем, что напрочь убивает любые попытки составления простых скриптов для автоматического выполнения тех или иных действий с их помощью.
Для исправления ситуации существуют немногочисленные программы, позволяющие создавать своего рода псевдотерминалы, отслеживающие появление на консоли того или иного текста и позволяющие задать текст, автоматически отправляемый в ответ на данный текст. Типовым примером является утилита 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.