c语言 - 程序在配置为 systemd 服务时不起作用



我想写一个可以在Linux上作为服务运行的程序。它主要通过服务器发送和接收数据,接收服务器发送的.so文件,并使用dlopen()执行里面的功能。

通过sudo命令手动启用生效。我试图写一个systemd文件,使其自动启动,但这不起作用。例如,使用Xlib的截屏功能,得到一张全黑的图片。

我试图将调试信息重定向到文件,但我只能得到主程序的调试信息;我无法获取插件的操作信息。我确信插件的功能已经执行,但是执行过程中出现错误。

其程序的结果是截图内容全黑,客户端发送截图后自动断开连接。这可能是在客户端遇到段错误,但是当我手动启动程序时没有发生这种情况

任何想法?

这是我的服务文件

[Unit]
Description=just for test
[Service]
Type=forking
ExecStart=/mnt/main.debug
Environment=DBUS_SESSION_BUS_ADDRESS,DISPLAY,WAYLAND_DISPLAY(new added)
[Install]
WantedBy=multi-user.target

我试图通过systemctl start ps-hak.service启动服务,错误消息是:

a@ubuntu:~$ sudo systemctl daemon-reload
a@ubuntu:~$ sudo systemctl start ps-hak.service
^[OAJob for ps-hak.service failed because a fatal signal was delivered to the control process. See "systemctl status ps-hak.service" and "journalctl -xe" for details.
a@ubuntu:~$ sudo systemctl start ps-hak.service^C
a@ubuntu:~$ systemctl status ps-hak.service
● ps-hak.service - just for test
Loaded: loaded (/etc/systemd/system/ps-hak.service; disabled; vendor preset: 
Active: failed (Result: signal) since Tue 2021-08-03 19:20:18 PDT; 18s ago
Process: 2662 ExecStart=/mnt/main.debug (code=killed, signal=SEGV)
Aug 03 19:20:08 ubuntu systemd[1]: Starting just for test...
Aug 03 19:20:08 ubuntu main.debug[2662]: 
Aug 03 19:20:08 ubuntu main.debug[2662]: [DEBUG|main.cpp:40 (main)]: WAYLAND_DIS
Aug 03 19:20:08 ubuntu main.debug[2662]: DISPLAY=(null)
Aug 03 19:20:08 ubuntu main.debug[2662]: 
Aug 03 19:20:18 ubuntu systemd[1]: ps-hak.service: Control process exited, code=
Aug 03 19:20:18 ubuntu systemd[1]: Failed to start just for test.
Aug 03 19:20:18 ubuntu systemd[1]: ps-hak.service: Unit entered failed state.
Aug 03 19:20:18 ubuntu systemd[1]: ps-hak.service: Failed with result 'signal'.

我只能确定程序的环境是错误的,我已经尝试添加Environment=DBUS_SESSION_BUS_ADDRESS,DISPLAY,WAYLAND_DISPLAY,但它没有意义。

我编写了一个调试SYSTEMd的小程序。代码如下。手动启用时,可以正常生成截图,但注册为服务服务后,无法正常工作。在指定的目录中甚至没有文件生成,但是在systemctl status test中没有错误消息。代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdio>
#include <sys/time.h>
#include <X11/Xlib.h>
#pragma pack (1)
typedef struct BitMAPFILEHEADER 
{
short    bfType;
int    bfSize;
short    bfReserved1;
short    bfReserved2;
int   bfOffBits;
} BITMAPFILEHEADER;
typedef struct BitMAPINFOHEADER
{
int  biSize;
int   biWidth;
int   biHeight;
short   biPlanes;
short   biBitCount;
int  biCompression;
int  biSizeImage;
int   biXPelsPerMeter;
int   biYPelsPerMeter;
int  biClrUsed;
int  biClrImportant;
} BITMAPINFOHEADER;
void saveXImageToBitmap(const char* filename,XImage *pImage)
{
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFOHEADER bmpInfoHeader;
FILE *fp;
memset(&bmpFileHeader, 0, sizeof(BITMAPFILEHEADER));
memset(&bmpInfoHeader, 0, sizeof(BITMAPINFOHEADER));
bmpFileHeader.bfType = 0x4D42;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
int biBitCount =32;
int dwBmpSize = ((pImage->width * biBitCount + 31) / 32) * 4 * pImage->height;
// DEBUG("size of short:%drn",(int)sizeof(short));
// DEBUG("size of int:%drn",(int)sizeof(int));
// DEBUG("size of long:%drn",(int)sizeof(long));
// DEBUG("dwBmpSize:%drn",(int)dwBmpSize);
// DEBUG("BITMAPFILEHEADER:%drn",(int)sizeof(BITMAPFILEHEADER));
// DEBUG("BITMAPINFOHEADER:%drn",(int)sizeof(BITMAPINFOHEADER));
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +  dwBmpSize;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = pImage->width;
bmpInfoHeader.biHeight = pImage->height;
bmpInfoHeader.biHeight = - bmpInfoHeader.biHeight;  // important,otherwise the pic will be reversed
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = biBitCount;
bmpInfoHeader.biSizeImage = 0;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
fp = fopen(filename,"wb");
if(fp == NULL)
return;
fwrite(&bmpFileHeader, sizeof(bmpFileHeader), 1, fp);
fwrite(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, fp);
fwrite(pImage->data, dwBmpSize, 1, fp);
fclose(fp);
}
int CaptureDesktop(const char* filename)
{
Window desktop;
Display* dsp;
XImage* img;
int screen_width;
int screen_height;
dsp = XOpenDisplay(NULL);/* Connect to a local display */
if(NULL==dsp)
{
// DEBUG("%s,%sn","CaptureDesktop","Cannot connect to local display");
return 0;
}
desktop = RootWindow(dsp,0);/* Refer to the root window */
if(0==desktop)
{
// DEBUG("%s,%sn","CaptureDesktop","cannot get root window");
return 0;
}
/* Retrive the width and the height of the screen */
screen_width = DisplayWidth(dsp,0);
screen_height = DisplayHeight(dsp,0);
// DEBUG("%d %dn",screen_width,screen_height);
img = XGetImage(dsp,desktop,0,0,screen_width,screen_height,~0,ZPixmap);
saveXImageToBitmap(filename,img);

XCloseDisplay(dsp);
return 1;
}
int main()
{
CaptureDesktop("/home/a/out.bmp");
return 0;
}

操作过程:

a@ubuntu:~$ sudo systemctl daemon-reload
a@ubuntu:~$ sudo systemctl enable test
a@ubuntu:~$ sudo systemctl start test
a@ubuntu:~$ sudo systemctl status test
● test.service - just for test
Loaded: loaded (/etc/systemd/system/test.service; enabled; vendor preset: ena
Active: inactive (dead) since Tue 2021-08-03 20:17:57 PDT; 5s ago
Process: 2501 ExecStart=/mnt/test (code=exited, status=0/SUCCESS)
Aug 03 20:17:57 ubuntu systemd[1]: Starting just for test...
Aug 03 20:17:57 ubuntu systemd[1]: Started just for test.
lines 1-7/7 (END)

我可以确认systemd启动的服务的环境变量有问题,但是applet在没有环境变量的情况下应该可以正常工作,但是作为一个服务,它不能正常工作。我认为主要的问题可能不是截图功能,因为其他功能也有类似的结果。

您不能从这种服务调用Xlib,因为它没有附加到用户会话。唯一一种可以合理使用Xlib的服务是用户登录服务。

如果检查环境变量,DISPLAY和XAUTHORITY将为空。这是失败的直接原因。用"right"值将允许它工作。如果您设法找到它们,setenv(3)将设置它们,Xlib将拾取它们。作为根用户,您可以使用一些技巧,并尝试跟踪当前X会话的内容,但这是一个向量标量问题。我运行多个X会话。哪一个是正确的?

在一般情况下,不知道任何事情(像答案暗示缺少X服务器使用),我要尝试的一种方法是,而不是运行您的/mnt/main.debug直接运行strace:strace -f -o /tmp/main.debug.strace.log /mnt/main.debug-o将指定输出文件,如果systemd以方便的方式收集输出,则可能不需要该文件。如果您也希望从子进程收集信息,那么-f选项很有用。strace的输出经常给出非常有用的指示,说明程序在哪里失败。你可以看到失败的系统调用,读取文件的内容以及所有试图读取的文件,以及所有程序如何在你背后与系统交互的东西。您可以将输出与在systemd之外的strace下运行程序的输出进行比较,看看它成功执行了哪些在systemd服务上下文中不起作用的操作。

另一个可以尝试的是启用调试符号和核心转储。请参考您的Linux发行版(或者systemd)文档如何在系统中启用它们,或者参考proc(5)和core(5)手册页。然后,您可以使用gdb来调查核心文件并查看堆栈跟踪(或如果应用程序是多线程的跟踪)。很可能您的程序中就有崩溃的那一行。或者它可能是一个坏指针,因为由于先前的失败而没有正确初始化某些内容。它将有助于减少优化标志(例如-O3-O1或甚至更调试友好的东西改变)以获得更好的堆栈跟踪(但请务必验证程序在使用更安全的编译器选项构建后仍然崩溃)。

最新更新