我的进程作为守护进程运行。我想使用信号重新加载配置。问题是,如果配置错误,它应该以 tty 形式发出错误消息,发送信号。
- 有没有办法做到这一点?
- 是推荐的方式吗?
如果不是推荐的方式。检查它是否成功的更合适的方法是什么?
要获取信号源的 pid,您需要在设置信号处理程序时使用sa_sigaction
,而不是:sa_handler
static pid_t g_killer_pid = 0;
static void signal_handler( int num, siginfo_t *info, void* blabla )
{
g_killer_pid = info->si_pid;
}
int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_sigaction = &signal_handler;
sa.sa_flags = SA_SIGINFO;
sigaction( SIGTERM, &sa, NULL );
sigaction( SIGINT, &sa, NULL );
pause();
hello_killer( g_killer_pid );
return 0;
}
现在你有了源进程的 pid。
获取源进程的终端ID并不是那么简单。一种方法是从proc/<pid>/stat
文件中读取它。文件中的一个数字是tty_nr
.
tty_nr
对我来说有点奇怪,所以我不知道这甚至是便携式的东西。但它包含次要编号,可用于打开正确的终端进行写入:
static void hello_killer( pid_t killer )
{
char filename[200];
FILE* fil;
FILE* out;
int tty_nr;
sprintf( filename, "/proc/%ld/stat", (long int)killer );
fil = fopen( filename, "r" );
if( fil )
{
if( fscanf( fil, "%*s %*s %*s %*s %*s %*s %d ", &tty_nr ) == 1 )
{
sprintf( filename, "/dev/pts/%d", (tty_nr & 0xF) | ((tty_nr >> 20) & 0xFFF) );
out = fopen( filename, "a" );
if( out )
{
fprintf( out, "Hello!\n" );
fclose( out );
}
}
fclose( fil );
}
}
我不确定这个/dev/pts
技巧是否正确/最好的方法。但它似乎适用于我的 Linux 机器:
~ # killall temp_test
Hello!
~ #
我猜你喜欢捕捉SIGUSR1
然后重新加载配置?
你应该记住,信号处理程序应该尽可能的小而快,而不是做一些可能导致另一个信号的事情。所以基本上你应该尽可能地避免 I/O。最好的方法可能是有一个非常简单的信号处理程序,它只设置一个标志,然后在你的主循环中检查这个标志,然后在你的主线程的上下文中重新加载你的配置。在那里,您可以随心所欲地输出到控制台。
你可以做到这一点,但没有简单的方法可以做到这一点。您需要为守护进程安排一种机制来反馈给发送信号的进程。
一些可能的方法包括:
在那些命名管道中,我认为我的第一选择是 - 您可以使用正常权限限制对它的访问,并且它最容易变得健壮和正确。
我怀疑您是否可以确定信号的来源,即使可以,也不必是终端。使用简单的 tcp/ip 协议怎么样?接受特殊端口上的 tcp/ip 连接。读取命令直到第一个新行。如果该命令是“重新配置”,请进行重新配置并通过已建立的 TCP/IP 连接发送消息。