web-based reboot or trigger: simple and cheap process synchronization via lockable read ()
Often, admin and web programming tasks require synchronization between different components of the system, for example, a webmord receives a command to perform some action, it is desirable to perform this action as early as possible, but the web interface itself cannot do this (say, it cannot change the rules firewall or routing table simply because root privileges are required). Usually I solved this in an ugly and inefficient way - the web interface wrote the command to some special file, and another shell script (working from the root) in the loop checked this file once every few seconds, and if there were commands, I processed them.
In this post, I will describe a simple way that:
The solution is spied in qmail source codes. The standard read () operation is blocked if there is no data to read (except when you specifically set non-blocking options to the socket). read () + fifo files solve the problem. The handler program should read data from a fifo file. While it is empty, it will simply go to sleep and will not create a load. And as soon as the data appears - read () is completed, and you can execute the processing code.
To do this, “on the knee” was written a simple program trigger . When it starts, it listens to the file specified by it, and when data appears in it, it immediately calls the command specified in the parameters (from the user from whom the trigger is launched, and not from the user who “pulled the trigger”)
The program was launched (by the daemon), created the FIFO file myfifo and when the data appears in it, it will start the prog.sh program. With the second team, we allowed everyone to write in FIFO, but, of course, you can configure it more carefully (for example, allow recording for group members and assign the www-data group).
The prog.sh script itself is very simple in our case - it simply logs the startup time: Naturally, in your case, you need to replace it with your script, which will do the job. Now let's check: We look at what happened: As you can see, the script was launched in the same second that the command was sent. Voila! The trigger itself weighs only 12Kb, and the blocked read () does not particularly load the system and works instantly.
Now you can easily stick the web interface to system operations (reboot the machine, restart the service, add rules to iptables, etc.). Naturally, we believe that the untrusted code from the web server group does not work, and access to the web interface will be password-protected via https and only from the local network. You have a trigger, so now it’s even more convenient to shoot your foot. :-)
In this post, I will describe a simple way that:
- no programming required - only unix-way building a system of small bricks
- It doesn’t eat a lot of resources (you don’t need to pour the file in vain, but the program itself weighs much less than shell)
- works instantly
The solution is spied in qmail source codes. The standard read () operation is blocked if there is no data to read (except when you specifically set non-blocking options to the socket). read () + fifo files solve the problem. The handler program should read data from a fifo file. While it is empty, it will simply go to sleep and will not create a load. And as soon as the data appears - read () is completed, and you can execute the processing code.
To do this, “on the knee” was written a simple program trigger . When it starts, it listens to the file specified by it, and when data appears in it, it immediately calls the command specified in the parameters (from the user from whom the trigger is launched, and not from the user who “pulled the trigger”)
xenon@dot:~/trigger-1.0$ ./trigger /tmp/myfifo ./prog.sh
fifo: /tmp/myfifo, program: ./prog.sh
file /tmp/myfifo doesn't exists, create it
created fifo /tmp/myfifo
xenon@dot:~/trigger-1.0$ chmod a+w /tmp/myfifo
xenon@dot:~/trigger-1.0$ pidof trigger
8552
The program was launched (by the daemon), created the FIFO file myfifo and when the data appears in it, it will start the prog.sh program. With the second team, we allowed everyone to write in FIFO, but, of course, you can configure it more carefully (for example, allow recording for group members and assign the www-data group).
The prog.sh script itself is very simple in our case - it simply logs the startup time: Naturally, in your case, you need to replace it with your script, which will do the job. Now let's check: We look at what happened: As you can see, the script was launched in the same second that the command was sent. Voila! The trigger itself weighs only 12Kb, and the blocked read () does not particularly load the system and works instantly.
xenon@dot:~/trigger-1.0$ cat prog.sh
#!/bin/sh
echo `date` started, ui: `whoami` >> program.log
www-data@dot:/tmp$ id
uid=33(www-data) gid=33(www-data) группы=33(www-data)
www-data@dot:/tmp$ echo > /tmp/myfifo
www-data@dot:/tmp$ echo > /tmp/myfifo
www-data@dot:/tmp$ echo > /tmp/myfifo
www-data@dot:/tmp$ exit
xenon@dot:~/trigger-1.0$ cat program.log
Чт. сент. 1 20:47:47 NOVST 2011 started, ui: xenon
Чт. сент. 1 20:47:48 NOVST 2011 started, ui: xenon
Чт. сент. 1 20:47:49 NOVST 2011 started, ui: xenon
Now you can easily stick the web interface to system operations (reboot the machine, restart the service, add rules to iptables, etc.). Naturally, we believe that the untrusted code from the web server group does not work, and access to the web interface will be password-protected via https and only from the local network. You have a trigger, so now it’s even more convenient to shoot your foot. :-)