# Валится /sbin/runscript при запуске вне консоли

## Mellon

Проблема выявилась полторы недели назад. Пр попытках запустить некоторые инит скрипты через pppd при поднятии соединения. Но сегодня выяснилось, что инит-скрипты, к примеру, /etc/init.d/bluetooth точно также, с похожими ошибками malloc не могут выполнится если их запускает udev, при появлении девайса. Ниже приведена ситуация с запуском через pppd (которая. теперь является типичной  :Sad:  ).

Понадобилось при поднятии соединения запускать некоторый сервис и останавливать его при разьединении.

Для этого в /etc/ppp/ip-up.d/90-local.sh вписал 

```
/etc/init.d/privoxy start
```

, и в /etc/ppp/ip-down.d/90-local.sh соответственно 

```
/etc/init.d/privoxy stop
```

Всё было нормально и работало, но полторы недели назад неожиданно перестало работать. Проведя исследование обнаружил, что init-скрипт валится с ошибкой 

```
*** glibc detected *** /sbin/runscript: malloc(): memory corruption: 0x08063808 ***
```

, но /etc/ppp/ip-up вручную из консоли работает без ошибок,

```
/etc/init.d/privoxy start
```

 тоже срабатывает без проблем. Прогнал memtest - с памятью всё нормально. Тогда пошел дальше и получил вывод strace Вот его окончание:

```
open("/dev/tty", O_RDWR|O_NOCTTY|O_NONBLOCK) = -1 ENXIO (No such device or address)

writev(2, [{"*** glibc detected *** ", 23}, {"/sbin/runscript", 15}, {": ", 2}, {"malloc(): memory corruption", 27}, {": 0x", 4}, {"08063808", 8}, {" ***\n", 5}], 7) = 84

open("/etc/ld.so.cache", O_RDONLY)      = 4

fstat64(4, {st_mode=S_IFREG|0644, st_size=170111, ...}) = 0

mmap2(NULL, 170111, PROT_READ, MAP_PRIVATE, 4, 0) = 0xb7f58000

close(4)                                = 0

open("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/libgcc_s.so.1", O_RDONLY) = 4

read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\3264A4\0\0\0"..., 512) = 512

mmap2(NULL, 2097152, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0xb7d55000

munmap(0xb7d55000, 700416)              = 0

munmap(0xb7f00000, 348160)              = 0

mprotect(0xb7e00000, 135168, PROT_READ|PROT_WRITE) = 0

fstat64(4, {st_mode=S_IFREG|0644, st_size=42540, ...}) = 0

mmap2(0x4134c000, 41700, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x4134c000

mmap2(0x41356000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x9) = 0x41356000

close(4)                                = 0

munmap(0xb7f58000, 170111)              = 0

rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0

gettid()                                = 7271

tgkill(7271, 7271, SIGABRT)             = 0

--- SIGABRT (Aborted) @ 0 (0) ---

+++ killed by SIGABRT +++

```

При остановке запущенного вручную сервиса во время разъединения связи происходит тоже самое.

Данные о /dev/tty: 

```
crw-rw-rw- 1 root tty 5, 0 Дек 12 05:22 /dev/tty
```

Вывод emerge --info

В чем может быть причина, и как её можно устранить?

Ещё раз повторюсь. Работа инит-скриптов из консоли происходит нормально. Выполнение и остановка во время загрузки и завершении работы тоже не вызывает нареканий, за исключениме тех, что контролируются udev'ом

----------

## calculator

Честно говоря не очень понял как udev запускает bluetooth, но наверняка полторы недели назад что-то было и, может быть, 

```
# etc-update && revdep-rebuild
```

 помогут.

----------

## user11

Если приводить strace, то желательно указать фрагмент, где "нормальный" и "сбойный" сценарий начинают различаться. В приведённом фрагменте дан только собственно вывод сообщения об ошибке - а это уже заведомо поздно...

----------

## Mellon

Полный вывод strace приведён ссылкой, вот, продублирую: http://pastebin.org/11225.

Может, я упустил непосредствено в описании важную деталь. последние месяца два использую sys-apps/baselayout-2.0.0_rc6

На счёт того как udev управляет инит-скриптами, к примеру bluetooth.

```
% cat /etc/udev/rules.d/70-bluetooth.rules

# Bluetooth devices:

#

KERNEL=="hci[0-9]*", RUN+="/lib/udev/bluetooth.sh"

```

```
% cat /lib/udev/bluetooth.sh

#!/bin/sh

#

# bluetooth.sh: udev external RUN script

#

# Copyright 2005-2006 Henrik Brix Andersen <brix@gentoo.org>

# Distributed under the terms of the GNU General Public License v2

script=/etc/init.d/bluetooth

# Find out where sysfs is mounted. Exit if not available

sysfs=`grep -F sysfs /proc/mounts | awk '{print $2}'`

if [ "$sysfs" = "" ]; then

    echo "sysfs is required"

    exit 1

fi

if [ ! -d $sysfs/class/bluetooth/hci[0-9]* ]; then

    if $script --quiet status; then

        $script stop

    fi

else

    if ! $script --quiet status; then

        $script start

    fi

fi

```

И поверьте, уже проделал стандартные пассы c etc-update, revdep-rebuild, emerge -e system.

----------

## user11

Вы не привели strace нормального сценария; будем считать, что strace нормального сценария вплоть до самой ошибки не отличается от сбойного.

Тогда ещё одно предположение (собственно, 90% проблем, которые лично я встречал с init.d-скриптами) - возможно, дело в environment, с которым стартует скрипт.

Для проверки, мне кажется, стоит попробовать запустить скрипт из консоли, но в очищенном окружении (например, командой "exec -c bash"). (Можно добавить ещё source /etc/profile и прочие "пассы" - к сожалению, не могу сказать, что именно нужно.)

Если произойдёт сбой, аналогично тому, как это происходит через udev, вероятно, проблема именно в environment.

----------

## Mellon

user11, да, как-только прочитал твое сообщение, сразу проверил. И вот, что из этого получилось (приведу лишь итоги):

```
localhost ~ # env | grep ^PATH

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/i686-pc-linux-gnu/gcc-bin/4.1.2:/usr/qt/3/bin:/usr/local/sbin:/usr/local/bin:/opt/nessus/bin:/opt/nessus/sbin:/usr/kde/3.5/sbin:/usr/kde/3.5/bin:/opt/bin

localhost ~ # echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/i686-pc-linux-gnu/gcc-bin/4.1.2:/usr/qt/3/bin:/usr/local/sbin:/usr/local/bin:/opt/nessus/bin:/opt/nessus/sbin:/usr/kde/3.5/sbin:/usr/kde/3.5/bin:/opt/bin

localhost ~ # exec -c bash

setterm: $TERM is not defined.

root@localhost root # env | grep ^PATH

root@localhost root # echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

root@localhost root # /etc/init.d/privoxy start

*** glibc detected *** /sbin/runscript: malloc(): memory corruption: 0x08061808 ***

Aborted

root@localhost root # PATH="" /etc/init.d/privoxy start

privoxy          | * Starting privoxy ... [ ok ]

root@localhost root # env | grep ^PATH

root@localhost root # echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

root@localhost root # unset PATH

root@localhost root # env | grep ^PATH

bash: grep: No such file or directory

bash: env: No such file or directory

root@localhost root # echo $PATH

root@localhost root # /etc/init.d/privoxy start

*** glibc detected *** /sbin/runscript: malloc(): memory corruption: 0x08061808 ***

Aborted

root@localhost root # PATH="" /etc/init.d/privoxy start

privoxy          | * WARNING: privoxy has already been started

root@localhost root # PATH="" /etc/init.d/privoxy stop

privoxy          | * Stopping privoxy ... [ ok ]

root@localhost root # export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

root@localhost root # env | grep ^PATH

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

root@localhost root # echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

root@localhost root # /etc/init.d/privoxy start

privoxy          | * Starting privoxy ... [ ok ]

root@localhost root # /etc/init.d/privoxy stop

privoxy          | * Stopping privoxy ... [ ok ]
```

Действительно, /sbin/runscript валится когда не определена переменная PATH, то есть, если эту переменную определить, пусть даже как пустую (export PATH="", к примеру), то скрипт(ы) запускается удачно. Но здесь есть неясный момент, если "exec -c" - запуск команды в пустом окружении, то почему "echo $PATH" печатает непустое значение переменной PATH?

Ну и насущные вопросы.

Почему всё-таки валится /sbin/runscript? Причем валится с любым скриптом запущенным в данном окружении.

Куда теперь лучше прописать определение PATH, или подключение /etc/profile (/etc/profile.env)?

PS.

Привожу выводы strace (пожато bz2) удачного запуска: http://slil.ru/25266883 ;

неудачного запуска: http://slil.ru/2526688

PPS.

Будьте добры, порекомендуйте пару адресов хороших публичных файлохранилищ для логов и конфигов (на pastebin.org пожатое не выложить, а лимит есть на размер  :Smile:  )

----------

## user11

Чтобы покончить с логами strace, приведу свой вывод:

сбой происходит после чтения /etc/profile.env - в нормальном сценарии идёт

```
open("/lib/rc/init.d/softlevel", O_RDONLY) = 3
```

а в сбойном этого нет - сразу происходит нарушение работы с памятью (попытка открыть /dev/tty - это просто попытка вывести на консоль информацию об ошибке).

(кстати, у меня такого файла нет, а есть /var/rc/init.d/softlevel)

По идее, этот сбой из-за пустого PATH стоит отписать как баг разработчикам самой загадочной (шутка) части gentoo - /sbin/runscript.

Насчёт того, как с этим сосуществовать - думаю, стоит всё же выяснить, с каким именно окружением запускается этот скрипт. Для этого достаточно вставить в скрипт что-то типа

```
/usr/bin/env >/tmp/env.log
```

или

```
set >/tmp/set.log
```

и потом пытаться понять, есть ли там PATH, точно ли в нём дело, и откуда он такой берётся (например, сравнить env с env самого udev: "ps feU 0 |grep [u]devd" под рутом).

/* К сожалению, дальше для меня в этой теме тёмный лес. */

----------

## Mellon

 *Quote:*   

> По идее, этот сбой из-за пустого PATH стоит отписать как баг разработчикам самой загадочной (шутка) части gentoo - /sbin/runscript.

 

Согласен, и весьма даже за, но у меня с английским неважно  :Sad: 

В принципе, если никто не захочет, то через некоторое время могу в багзиллу запостить, но исключительно на языке консоли и баша.  :Smile: 

 *Quote:*   

> думаю, стоит всё же выяснить, с каким именно окружением запускается этот скрипт.

 

Выяснено. я и писал, что это итоги, в смысле того, что все переменные из стандартного окружения рута кроме PATH проверены и исключены из подозреваемых.

pppd и udev выполняют команды в очень ограниченном окружении без PATH. При этом значения необходимых переменных, если они не определены в окружении, должны браться /sbin/runscript из /etc/profile.env согласно /lib/rc/conf.d/env_whitelist и /etc/conf.d/env_whitelist. Отсюда очевидно, что нет необходимости определять PATH в окружении в котором запускается скрипт,

Окружение в самих скриптах весьма разнообразно. Но в случае с неопределённой переменной PATH, интерпретатор  /sbin/runscript вылится в самом начале, до начала исполнения скрипта.

Пока раставил костыли в виде прописывания export PATH="${PATH}" перед запуском init-скриптов.

user11, благодарю за бесценную помощь, огромное спасибо  :Smile: 

----------

