配置为系统服务时程序不起作用
Program doesn't work when configured as a systemd service
我正在尝试编写一个可以 运行 作为 Linux 上的服务的程序。
主要是与服务器收发数据,接收服务器发送的.so
文件,使用dlopen()
执行里面的函数
当我通过sudo
命令手动启用它时它起作用了。
我试图写一个 systemd
文件让它自动启动,但是那不起作用。例如使用Xlib
的截屏功能得到一张全黑的图片。
我试过将调试信息重定向到文件中,但是只能得到主程序的调试信息;获取不到插件的运行信息。确定插件的功能已经执行,但是执行过程中出现错误
其程序的结果是截图内容全黑,客户端发送截图后自动断开连接。可能是客户端遇到segment fault,但是我手动启动程序的时候并没有出现这种情况
有什么想法吗?
这是我的服务文件。
[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:%d\r\n",(int)sizeof(short));
// DEBUG("size of int:%d\r\n",(int)sizeof(int));
// DEBUG("size of long:%d\r\n",(int)sizeof(long));
// DEBUG("dwBmpSize:%d\r\n",(int)dwBmpSize);
// DEBUG("BITMAPFILEHEADER:%d\r\n",(int)sizeof(BITMAPFILEHEADER));
// DEBUG("BITMAPINFOHEADER:%d\r\n",(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,%s\n","CaptureDesktop","Cannot connect to local display");
return 0;
}
desktop = RootWindow(dsp,0);/* Refer to the root window */
if(0==desktop)
{
// DEBUG("%s,%s\n","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 %d\n",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启动的服务的环境变量有问题,但是小程序没有环境变量应该可以正常工作,但是作为一个服务,却不能正常工作。
我认为主要问题可能不是截图功能,因为其他功能也有类似的结果。
您不能从那种服务调用 Xlib,因为它没有附加到用户会话。唯一可以合理使用 Xlib 的服务是用户登录服务。
如果检查环境变量,DISPLAY 和 XAUTHORITY 将为空白。这是直接失败的原因。用“正确的”值填充它们将允许它工作。如果您设法找到它们,setenv(3)
将设置它们并且 Xlib 将拾取它们。您可以以 root 身份玩把戏,并尝试追踪当前 X 会话的内容,但这是一个矢量-标量问题。我 运行 多个 X 会话。哪个是对的?
一般来说,我什么都不知道(比如建议使用缺少的 X 服务器的答案),我尝试的一种方法是直接 运行 宁你的 /mnt/main.debug
运行 它与 strace: strace -f -o /tmp/main.debug.strace.log /mnt/main.debug
。 -o
将指定输出文件,如果 systemd 以方便的方式收集输出,则可能不需要。如果您 fork 并希望从子进程中收集信息,则 -f
选项很有用。通常 strace
的输出会给出非常有用的指示,表明程序在何处失败。您可以看到诸如失败的系统调用、读取的文件内容和所有试图读取的文件,以及程序如何与您背后的系统交互的所有事情。您可以将输出与在 systemd 之外 strace
下 运行ning 您的程序的输出进行比较,看看它成功地做了哪些在 systemd 服务上下文中不起作用的事情。
要尝试的另一件事是启用调试符号和核心转储。请参阅您的 Linux 发行版(或 systemd)文档,了解如何在系统中启用它们或参阅 proc(5) and core(5) 手册页。然后,您可以使用 gdb
来调查核心文件并查看堆栈跟踪(如果应用程序是多线程的,则为跟踪)。很可能您的程序中有崩溃的确切行。或者它可能是错误的指针,因为由于早期的故障,某些东西没有正确初始化。它将有助于减少优化标志(例如 -O3
更改为 -O1
或什至更友好的调试)以获得更好的堆栈跟踪(但请确认程序在使用更安全的编译器选项构建后仍然崩溃).
我正在尝试编写一个可以 运行 作为 Linux 上的服务的程序。
主要是与服务器收发数据,接收服务器发送的.so
文件,使用dlopen()
执行里面的函数
当我通过sudo
命令手动启用它时它起作用了。
我试图写一个 systemd
文件让它自动启动,但是那不起作用。例如使用Xlib
的截屏功能得到一张全黑的图片。
我试过将调试信息重定向到文件中,但是只能得到主程序的调试信息;获取不到插件的运行信息。确定插件的功能已经执行,但是执行过程中出现错误
其程序的结果是截图内容全黑,客户端发送截图后自动断开连接。可能是客户端遇到segment fault,但是我手动启动程序的时候并没有出现这种情况
有什么想法吗?
这是我的服务文件。
[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:%d\r\n",(int)sizeof(short));
// DEBUG("size of int:%d\r\n",(int)sizeof(int));
// DEBUG("size of long:%d\r\n",(int)sizeof(long));
// DEBUG("dwBmpSize:%d\r\n",(int)dwBmpSize);
// DEBUG("BITMAPFILEHEADER:%d\r\n",(int)sizeof(BITMAPFILEHEADER));
// DEBUG("BITMAPINFOHEADER:%d\r\n",(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,%s\n","CaptureDesktop","Cannot connect to local display");
return 0;
}
desktop = RootWindow(dsp,0);/* Refer to the root window */
if(0==desktop)
{
// DEBUG("%s,%s\n","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 %d\n",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启动的服务的环境变量有问题,但是小程序没有环境变量应该可以正常工作,但是作为一个服务,却不能正常工作。 我认为主要问题可能不是截图功能,因为其他功能也有类似的结果。
您不能从那种服务调用 Xlib,因为它没有附加到用户会话。唯一可以合理使用 Xlib 的服务是用户登录服务。
如果检查环境变量,DISPLAY 和 XAUTHORITY 将为空白。这是直接失败的原因。用“正确的”值填充它们将允许它工作。如果您设法找到它们,setenv(3)
将设置它们并且 Xlib 将拾取它们。您可以以 root 身份玩把戏,并尝试追踪当前 X 会话的内容,但这是一个矢量-标量问题。我 运行 多个 X 会话。哪个是对的?
一般来说,我什么都不知道(比如建议使用缺少的 X 服务器的答案),我尝试的一种方法是直接 运行 宁你的 /mnt/main.debug
运行 它与 strace: strace -f -o /tmp/main.debug.strace.log /mnt/main.debug
。 -o
将指定输出文件,如果 systemd 以方便的方式收集输出,则可能不需要。如果您 fork 并希望从子进程中收集信息,则 -f
选项很有用。通常 strace
的输出会给出非常有用的指示,表明程序在何处失败。您可以看到诸如失败的系统调用、读取的文件内容和所有试图读取的文件,以及程序如何与您背后的系统交互的所有事情。您可以将输出与在 systemd 之外 strace
下 运行ning 您的程序的输出进行比较,看看它成功地做了哪些在 systemd 服务上下文中不起作用的事情。
要尝试的另一件事是启用调试符号和核心转储。请参阅您的 Linux 发行版(或 systemd)文档,了解如何在系统中启用它们或参阅 proc(5) and core(5) 手册页。然后,您可以使用 gdb
来调查核心文件并查看堆栈跟踪(如果应用程序是多线程的,则为跟踪)。很可能您的程序中有崩溃的确切行。或者它可能是错误的指针,因为由于早期的故障,某些东西没有正确初始化。它将有助于减少优化标志(例如 -O3
更改为 -O1
或什至更友好的调试)以获得更好的堆栈跟踪(但请确认程序在使用更安全的编译器选项构建后仍然崩溃).