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:%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 会话。哪个是正确的?
推荐阅读
- python - 如何在 python 中插入 youtube 视频
- sql - 如何从 PostgreSQL 返回“稀疏”json(选择多个属性)
- flutter - iOS 模拟器在使用 image_picker 时崩溃
- javascript - 我怎样才能摆脱 JSON 格式的“”?
- codeigniter - php spark服务错误无法写入缓存
- git - 如何让我的 Github 分支与我的本地分支匹配
- android - 防止在android WebView上双击到达html,但让点击到达html
- validation - Nestjs使用validationSchema验证嵌套对象
- javascript - 反应 App.js 和类之间的连接信息
- html - Bootstrap 5.0.2 汉堡菜单不起作用