getting tty of caller in signal handler in php - php

I just wrote php daemon for my app and want to implement some output information generated on specified signal (SIGUSR1). I got signal handler in code
pcntl_signal(SIGUSR1, array($this, 'signal_status'));
and function handler prepared
protected function signal_status($signal_number)
{ printf("blah\n"); }
Everything work except one thing. When i send signal to my daemon (posix_kill($pid, SIGUSR1) or even simple kill -10 pid in bash) i got output in console that starts daemon.
Is it possible to get file descriptor of caller and not of the daemon? I wan't to send this data to specified output (for example after kill -10 PID) and not into FD of daemon.
I hope i wrote this clearly :)

Well, you can not, sending a signal is just setting up some operating system primitives, it has nothing to do with setting up a communication path between your daemon on one hand and the tool used to generate the signal on the other hand. The alternatives you have are either watching the console output of the daemon, or making the daemon dump status to a logfile and create some sort of utility to send the signal and print the logfile (and if you're going that way, why not throw out the logfile altogether and setup a periodical dump of your logging anyhow, since signals are not a polite way of doing inteprocess communiation.

Related

Kill processes using their name in php

i have the name of a long running process like ffmpeg (or more) and i want to kill it - or them - in php and without using the exec
Is that possible ? Its just like killall ffmpeg linux command .
You can kill process in safe way using the posix function "posix_kill".
Example:
// We assumes that 1223 PID is one ffmpeg process
posix_kill(1223, SIGHUP); // This send a polite termination signal to the process
posix_kill(1223, SIGINT); // This send a interrupt signal to the process
posix_kill(1223, SIGTERM); // This send the termination signal and tried to clean-up the process (Use it if SIGHUP and SIGINT fails)
posix_kill(1223, SIGKILL); // This send an unpolite signal to the kernel explaining that we want to kill the process ASAP and unconditionally and we don't care if we loss some data and the process is going to generate some memory leak (Use this as last option).
Now the problem is that you want to have the ffmpeg PID's, you can achieve that in a non-intrusive way reading the processes information from the "proc" filesystem.
Example that provides the process name:
/proc/1223/cmdline
In order to get the higher/maximum process number, you have to read the file /proc/sys/kernel/pid_max. Now you have to iterate across the process information in the "proc" filesystems until the pid_max is reached. You have have to check that process directory exists and that string returned from the /proc/xxxx/cmdline is contain the string "ffmpeg" or "libav" (Some linux distributions have renamed ffmpeg by libav or something like that).
Remember that in order to kill the ffmpeg processes the PHP script owner (Maybe Apache?) should be added to the same group that launch the ffmpeg processes.
Actually you can use linux commands via "exec" function, i don't know any other way. Check this out :
http://php.net/manual/en/function.exec.php

How to profile a PHP shell script app or worker using Blackfire

I noticed that when I have an endless worker I cannot profile PHP shell scripts. Because when it's killed it doesn't send the probe.
What changes shall I do?
When you are trying to profile a worker which is running an endless loop. In this case you have to manually edit your code to either remove the endless loop or instrument your code to manually call the close() method of the probe (https://blackfire.io/doc/manual-instrumentation).
That's because the data is sent to the agent only when the close() method is called (it is called automatically at the end of the program unless you killed it).
You can manually instrument some code by using the BlackfireProbe class that comes bundled with the Blackfire's probe:
// Get the probe main instance
$probe = BlackfireProbe::getMainInstance();
// start profiling the code
$probe->enable();
// Calling close() instead of disable() stops the profiling and forces the collected data to be sent to Blackfire:
// stop the profiling
// send the result to Blackfire
$probe->close();
As with auto-instrumentation, profiling is only active when the code is run through the Companion or the blackfire CLI utility. If not, all calls are converted to noops.
I don't know, maybe in 2015 following page did not exist, but now you can do profiling in following way: https://blackfire.io/docs/24-days/17-php-sdk
$blackfire = new LoopClient(new Client(), 10);
$blackfire->setSignal(SIGUSR1);
$blackfire->attachReference(7);
$blackfire->promoteReferenceSignal(SIGUSR2);
for (;;) {
$blackfire->startLoop($profileConfig);
consume();
$blackfire->endLoop();
usleep(400000);
}
Now you can send signal SIGUSR1 to process of this worker and LoopClient will start profiling. It'll listen 10 iterations of method consume and send last probe. After that it'll stop profiling.

How to get process PID started by Symfony?

How can I get PID of process started by Symfony?
The code bellow
$process = new \Symfony\Component\Process\Process('vlc');
$process->start();
return $process->getPid();
returns PID 1488. But there is no process (no vlc, no php) in system with same PID.
Edit
Presented code runs in app/console (Symfony\Component\Console\Command\Command)
Process forking
It's not unlikely for processes to spawn off their UI separately and letting the starter process end normally, i.e.
----> vlc (1488) ---> EOL
|
+--> vlc-ui (??) ---> Application
This behaviour is observable by running the application from the command line and checking whether the prompt returns almost immediately.
Hangup signal
Also note that when a parent process exits (your script), the child process may choose to also exit by listening to SIGHUP signals. If you're not doing so already, you could let your script "live" longer by adding a sleep() statement while you investigate.
Another approach that may work in some situations is doing it inversely like a script to grep parse a 'ps -A' containing the desired process (PHP e.g.) and rip off PID from the result. You don't have control on "who's who" on the result set but have control on "who's" actually running.

Process respawn and signal handling in PHP

Specifics
I have an issue in PHP, when respawned processes are not handling signals, while before respawning, handling working correctly. I narrowed down my code to the very basic:
declare(ticks=1);
register_shutdown_function(function() {
if ($noRethrow = ob_get_contents()) {
ob_end_clean();
exit;
}
system('/usr/bin/nohup /usr/bin/php '.__FILE__. ' 1>/dev/null 2>/dev/null &');
});
function handler($signal)
{
switch ($signal) {
case SIGTERM:
file_put_contents(__FILE__.'.log', sprintf('Terminated [ppid=%s] [pid=%s]'.PHP_EOL, posix_getppid(), posix_getpid()), FILE_APPEND);
ob_start();
echo($signal);
exit;
case SIGCONT:
file_put_contents(__FILE__.'.log', sprintf('Restarted [ppid=%s] [pid=%s]'.PHP_EOL, posix_getppid(), posix_getpid()), FILE_APPEND);
exit;
}
}
pcntl_signal(SIGTERM, 'handler');
pcntl_signal(SIGCONT, 'handler');
while(1) {
if (time() % 5 == 0) {
file_put_contents(__FILE__.'.log', sprintf('Idle [ppid=%s] [pid=%s]'.PHP_EOL, posix_getppid(), posix_getpid()), FILE_APPEND);
}
sleep(1);
}
As you can see, it does following:
Registering shutdown function, in which respawn a process with nohup (so, to ignore SIGHUP when parent process dies)
Registering handler via pcntl_signal() for SIGTERM and SIGCONT. First will just log a message that process was terminated, while second will lead to respawn of the process. It is achieved with ob_* functions, so to pass a flag, what should be done in shutdown function - either exit or respawn.
Logging some information that script is "alive" to log file.
What is happening
So, I'm starting script with:
/usr/bin/nohup /usr/bin/php script.php 1>/dev/null 2>/dev/null &
Then, in log file, there are entries like:
Idle [ppid=7171] [pid=8849]
Idle [ppid=7171] [pid=8849]
Let's say, then I do kill 8849:
Terminated [ppid=7171] [pid=8849]
Thus, it is successful handling of SIGTERM (and script indeed exits). Now, if I instead do kill -18 8849, then I see (18 is numeric value for SIGCONT):
Idle [ppid=7171] [pid=8849]
Restarted [ppid=7171] [pid=8849]
Idle [ppid=1] [pid=8875]
Idle [ppid=1] [pid=8875]
And, therefore: first, SIGCONT was also handled correctly, and, judging by next "Idle" messages, newly spawned instance of script is working well.
Update #1 : I was thinking about stuff with ppid=1 (thus, init global process) and orphan processes signal handling, but it's not the case. Here is log part, which shows that orphan (ppid=1) process isn't the reason: when worker is started by controlling app, it also invokes it with system() command - same way like worker respawns itself. But, after controlling app invokes worker, it has ppid=1 and responds to signals correctly, while if worker respawns itself, new copy is not responding to them, except SIGKILL. So, issue appears only when worker respawns itself.
Update #2 : I tried to analyze what is happening with strace. Now, here are two blocks.
When worker was yet not respawned - strace output. Take a look on lines 4 and 5, this is when I send SIGCONT, thus kill -18 to a process. And then it triggers all the chain: writing to the file, system() call and exiting current process.
When worker was already respawned by itself - strace output. Here, take a look to lines 8 and 9 - they appeared after receiving SIGCONT. First of: looks like process is still somehow receiving a signal, and, second, it ignores the signal. No actions were done, but process was notified by the system that SIGCONT was sent. Why then the process ignores it - is the question (because, if installing of user handler for SIGCONT failed, then it should end execution, while process is not ended). As for SIGKILL, then output for already respawned worker is like:
nanosleep({1, 0}, <unfinished ...>
+++ killed by SIGKILL +++
Which indicates, that signal was received and did what it should do.
The problem
As the process is respawn, it is not reacting neither to SIGTERM, nor to SIGCONT. However, it is still possible to end it with SIGKILL (so, kill -9 PID indeed ends the process). For example, for process above both kill 8875 and kill -18 8875 will do nothing (process will ignore signals and continue to log messages).
However, I would not say that registering signals is failing completely - because it redefines at least SIGTERM (which normally leads to termination, while in this case it is ignored). Also I suspect that ppid = 1 points to some wrong thing, but I can not say for sure now.
Also, I tried any other kind of signals (in fact, it didn't matter what is the signal code, result was always the same)
The question
What could be the reason of such behavior? Is the way, which I'm respawning a process, correct? If not, what are other options which will allow newly spawned process to use user-defined signal handlers correctly?
Solution : Eventually, strace helped to understand the problem. This is as follows:
nanosleep({1, 0}, {0, 294396497}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
restart_syscall(<... resuming interrupted call ...>) = 0
Thus, it shows the signal was received, but ignored. To fully answer the question, I will need to figure out, why process added signals to ignore list, but unblocking them forcefully with pcntl_sigprocmask() is doing the thing:
pcntl_sigprocmask(SIG_UNBLOCK, [SIGTERM, SIGCONT]);
then all goes well and respawned process receives/handles signals as it is intended. I tried to add only SIGCONT for unblocking, for example - and then it was handled correctly, while SIGTERM was blocked, which points to the thing, that it is exactly the reason of failing to dispatch signals.
Resolution : for some reason, when process spawns itself with signal handlers installed, new instance has those signals masked for ignoring. Unmasking them forcefully solves the issue, but why signals are masked in new instance - that is an open question for now.
It's due to the fact, that you spawn a child process by executing system(foo), and then proceeding with dying of the current process. Hence, the process becomes an orphan, and its parent becomes PID 1 (init).
You can see the change using pstree command.
Before:
init─┬─cron
(...)
└─screen─┬─zsh───pstree
├─3*[zsh]
├─zsh───php
└─zsh───vim
After:
init─┬─cron
(...)
└─php
What wikipedia states:
Orphan processes is kind of the opposite situation of zombie processes, since it refers to the case where a parent process terminates before its child processes, in which case these children are said to become "orphaned".
Unlike the asynchronous child-to-parent notification that happens when a child process terminates (via the SIGCHLD signal), child processes are not notified immediately when their parent finishes. Instead, the system simply redefines the "parent-pid" field in the child process's data to be the process that is the "ancestor" of every other process in the system, whose pid generally has the value 1 (one), and whose name is traditionally "init". It is thus said that "init 'adopts' every orphan process on the system".
For your situation, I would suggest two options:
Use two scripts: one for managing the child, and second one, "worker", to actually perform the job,
or, use one script, that will include both: outer part will manage, inner part, forked from outer, will do the job.

Alerting php when new event occurs in linux debian

I have a daemon program that prints in the terminal when new device is plugged or removed, now i want it to be printed in php like the way it was printed in linux. it's like realtime output. when a new device is plugged in linux it will alert php without you clicking any button it just prints in the screen. what my daemon program prints in linux also php prints.
I also have another program which scan devices but not daemon i can get it's output without a problem and prints it in php.
How am i supposed to make a real time output with my daemon program in php?
Thanks,
Comments becoming long so I add a post here.
First off the redirection of stderr and stdout to file by ~$ my-daemon >> my_logfile 2>&1 - unless your daemon has a log-file option.
Then you could perhaps use inotifywait with the -m flag on modify events (if you want to parse/do something on system outside PHP, i.e. by bash.)
Inotify can give you notification on various changes - This is i..e a short few lines of a bash script I use to check for new files in a specific directory:
notify()
{
...
inotifywait -m -e moved_to --format "%f" "$path_mon" 2>&- |
awk ' { print $0; fflush() }' |
while read buf; do
printf "NEW:[file]: %s\n" "$buf" >> "$file_noti_log"
blah blah blah
...
done
}
What this does is: each time a file get moved to $path_mon the script enters inside the while loop and perform various actions defined by the script.
Haven't used inotify on PHP but this looks perhaps like what you want:
inotify_init (separate module in PHP).
inotify check various events in one or several directories, or you can target a specific file. Check man inotifywait or inotify. You would most likely want to use the "modify" flag, "IN_MODIFY" under PHP: Inotify Constants.
You could also write your own in C. Haven't read this page, but IBM's pages use to be quite OK : Monitor file system activity with inotify
Another option could be to use PCNTL or similar under PHP.
it will alert php without you clicking any button
So you're talking about client side PHP.
The big problem is alerting the client browser.
For short lengths of time you could ignore the problem and just disable all buffering and send the daemon output to the browser. It's neither elegant nor really working in the long run, and it has... aesthetic issues. Moreover, you can't really manipulate the output client side at all, not easily or cleanly at least.
So you need to have a program running on the client, which means Javascript. The JS and the PHP programs must communicate, and PHP must also talk to the daemon, or at least monitor what it's doing.
There are ways of doing the first using Web Sockets, or maybe multipart-x-mixed-replace, but they're not very portable yet.
You could refresh the Web page but that's wasteful, and slow.
The problem of getting the notification to the client browser is then, in my opinion, best solved with an AJAX poll. You don't get an immediate alert, but you do get alerted within seconds.
You would send a query to PHP from AJAX every, say, 10 seconds (10000 ms)
function poll_devices() {
$.ajax({
url: '/json/poll-devices.php',
dataType: 'json',
error: function(data) {
// ...
},
success: function(packet) {
setTimeout(function() { poll_devices(); }, 10000);
// Display packet information
},
contentType: 'application/json'
});
}
and the PHP would check the accumulating log and send the situation.
Another possibility is to have the PHP script block up to 20 seconds, not enough to make AJAX time out and give up, and immediately return in case of changes. You would then employ an asynchronous AJAX function to drive the poll back-to-back.
This way, the asynchronous function starts and immediately goes to sleep while the PHP script is sleeping too. After 20 seconds, the call returns and is immediately re-issued, sleeping again.
The net effect is to keep one connection constantly open, and changes being echoed back to client side Javascript immediately. You have to manage connection interruptions, though. But this way, every 20 seconds you only issue one call, and still manage to be alerted almost instantly.
Server side PHP can check the log file's size at the start (last read position being saved in the session), and keep it open read only in shared mode and block reads with fgets(), if the daemon allows it.
Or you could pipe the daemon to logger, and get messages to syslog. Configure syslog to send those messages to a specific unbuffered file readable by PHP. Now PHP should be able to do everything with fopen(), ftell() and fgets(), without requiring additional notification systems.

Categories