Как заставить программу работать на переднем плане

В UNIX каталоги специальные (я чувствую, что передаю Церковную Госпожу из SNL). Каталоги содержат другие файлы, поэтому для их удаления требуется другая операция. Даже когда каталог пуст, в нем все еще есть два файла (. и .. ), поэтому удаление каталога невозможно, пока он не станет действительно пустым, а ссылка будет считаться соответствующие файлы были обновлены.

На заре UNIX (мой первый опыт работы с 6-м изданием Bell Labs) были две разные команды ( rm и rmdir ) для обычных файлов и каталогов, которые отражает тот факт, что это два разных системных вызова. rm был прост: он просто удалял запись, имя которой вы дали ему, из каталога и уменьшал счетчик ссылок на файл, на который он указывал (конечно, файл не удаляется на самом деле, если счетчик ссылок не идет до 0). rmdir требовал гораздо большего (на самом деле не в приложении, а в системном вызове), он должен был перейти в каталог и найти . и .. , перейдите к этим индексным дескрипторам и уменьшите счетчик ссылок, а затем удалите запись в родительском элементе и уменьшите счетчик ссылок (тот самый, который он только что уменьшил для . в самом каталоге, который тогда должен быть 0).Все это занимало несколько разных секторов диска, и поэтому необходимо было тщательно настроить, чтобы возможность прерывания (то есть сбоя системы) в любой момент была устранена с помощью fsck.

Конечно, в более современных системах UNIX аппаратные ограничения (например, максимальный размер программы 64 Кбайт, равен «K») были ослаблены, и теперь вы можете выполнить rm -r и многое из того, что лежит в основе особой природы каталогов, менее очевидны, но они все еще существуют. Я помню, что мне нужно было удалить большое дерево на машине 6-го выпуска, что включало в себя вход в каждый каталог, удаление всех файлов, возвращение к родительскому и выполнение rmdir и, по сути, выполнение всей рекурсии по всем деревьям каталогов вручную. Мы действительно думали о сценарии, который помог бы с этим, но в те дни он появлялся так редко и был достаточно опасен, что мы решили, что если требовать от кого-то приложить все усилия, это поможет предотвратить катастрофические ошибки.

В первый раз вы получите вопрос, который гласит: «Я набрал ' sudo rm -rf / ' вместо ./ как мне восстановить?» вы можете понять, почему мы были осторожны.

3
29.03.2017, 02:00
2 ответа

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

Если, например, у вас нет времени получить pid до его выхода, вы можете запустить команду под strace -f и таким образом следовать дочернему процессу.У меня нет простых демонстраций демонов, но вы можете увидеть, как это может работать, на следующем примере:

$ strace -f -e exit bash -c 'nohup bash -c "sleep 10; exit 2" &'
strace: Process 9688 attached
[pid  9687] +++ exited with 0 +++
nohup: appending output to 'nohup.out'
strace: Process 9689 attached
[pid  9689] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9689, si_uid=127, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 2 +++

Здесь мы видим, что нам удалось собрать код выхода 2 из внутренней "демонизированной" команды bash.


В качестве альтернативы, если у вас есть systemd , вы можете запустить команду try в отдельной контрольной группе:

$ systemd-run --user --service-type=forking  bash -c '(sleep 99;exit 2)& exit 0'
Running as unit run-8772.service.

Я не знаю, как собрать результирующий код выхода, кроме как путем опроса. Когда это сделано слишком рано, демон все еще активен:

$ systemctl --user status run-8772
  ...
   Active: active (running) since Wed 2017-03-29 18:56:43 CEST; 14s ago
   CGroup: /user.slice/user-1000.slice/user@1000.service/run-8772.service
       |-8774 /usr/bin/bash -c (sleep 99;exit 2)& exit 0
       `-8775 sleep 99

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

$ systemctl --user status run-8772
   Active: failed (Result: exit-code) since Wed 2017-03-29 18:58:22 CEST; 3s ago
 Main PID: 8774 (code=exited, status=2)
1
27.01.2020, 21:15

Когда процесс демонизируется, он разветвляется (как минимум один раз ), родительский процесс возвращается немедленно, а дочерний процесс выполняет эту работу.

Когда этот ребенок умирает, у него больше нет родителя. Вернее, он был принятinit(процессом id 1 ). initсможет получить статус выхода.

В Linux и начиная с ядра 3.4 вы можете указать, какой процесс будет принимать осиротевшие процессы (для своих потомков и потомков ), используяPR_SET_CHILD_SUBREAPERprctl().

Итак, как и в этом очень похожем вопросе и ответе , если в Linux 3.4+ вы можете запустить свой демон под оболочкой, которая объявляет себя дочерним поджнецом , и он сообщает о статусе выхода. его потомков-сирот:

Здесь используется perlи жестко заданное значениеPR_SET_CHILD_SUBREAPERprctl():

perl -MPOSIX -le '
  require "syscall.ph";
  syscall(&SYS_prctl,36,1) >= 0 or die "cannot set subreaper: $!";
  if (!fork) {
    exec @ARGV;
    exit(127);
  }
  # now reporting on all children and grand-children:
  while (($pid = wait) > 0) {
   print "$pid: ". WEXITSTATUS($?)
  }' your-daemon here
4
27.01.2020, 21:15

Теги

Похожие вопросы