Включить службу Linux, чтобы показать всплывающее окно - PullRequest
0 голосов
/ 24 августа 2018

Я разработал IP-мессенджер на языке C, и я хотел бы поделиться некоторыми деталями его реализации, чтобы полностью понять мою проблему.

  1. Использовал библиотеку GTK + -2.0 для отображения окон графического интерфейса.
  2. Имеет сокет прослушивания, и при каждом новом соединении он создает новый процесс для обслуживания соединения.
  3. Всякий раз, когда приходит новое сообщение, оно отображает окно графического интерфейса пользователя для отображения полученного сообщения (например, всплывающее окно).
  4. Для запуска требуются права доступа root, поскольку для отправки эхо-пакетов ICMP используется необработанный сокетопределить доступные хосты в локальной сети.(Для сокета RAW требуются супер разрешения)
  5. Процесс демонизирован, поэтому он будет работать в фоновом режиме и показывать всплывающие окна только при получении сообщения.
  6. Мой компьютер - CentOS 6.9

И все прекрасно работает, когда я запускаю этот процесс из терминала.Но затем я создал запись запуска для этой программы, чтобы запустить ее как службу, добавив сценарий запуска в каталог /etc/init.d/.затем я запустил свой сервис, используя команду service,

 # service ipmsnger start

Теперь я вижу, что процесс запущен, используя команду ps.но оно не показывает всплывающее окно, если приходит сообщение.отправитель сообщения получает отчет об успешной доставке от мессенджера.В чем будет причина?В чем разница между запуском процесса демона из терминала пользователем и запуском его в качестве службы запуска системой?

Ответы [ 2 ]

0 голосов
/ 24 августа 2018

Когда вы запускаете вашу программу из окна терминала, она ассоциируется с вашим текущим сеансом входа в систему.Это дает контекст, необходимый для представления всплывающих окон в вашем GUI.

Но помните, что Linux является многопользовательской системой, поддерживающей даже несколько одновременных сеансов GUI.Каждый графический интерфейс принадлежит одному сеансу;нет никакого смысла в единственном истинном графическом интерфейсе для машины.Если вы запускаете свою программу как системную службу, то она не связана с каким-либо конкретным сеансом входа в систему, поэтому она не знает о вашем графическом интерфейсе для представления чего-либо там.

Учитывая, что служба работает с привилегией root, она можетдля него возможно обнаружить сеансы входа в систему и всплыть в них сообщения, но вы не получаете это бесплатно.

Я предполагаю, что смысл запуска вашей программы как службы состоит в том, чтобы сделать ее пригодной для использования людьми, которыене может отстаивать привилегии root.В этом случае я предлагаю рефакторинг на две программы: сервис, работающий от имени пользователя root, и клиент, работающий без привилегий.Ожидается, что пользователи будут запускать клиента, как и они, в сеансе, где они хотят получать всплывающие окна.Клиент регистрируется на сервере.Сервер получает сообщения из сети и рассылает их зарегистрированным клиентам для их отображения.

0 голосов
/ 24 августа 2018

Я не очень знаком с init.d, так как systemd в настоящее время более распространен.Я предполагаю, что вы работаете с X11, а не с Wayland.

Либо используйте CAP_NET_RAW и запустите вашу программу в качестве пользователя. Диалог должен отображаться.

Или запуститезапрограммируйте как root, изменив UID пользователя для отображения во время его отображения.Вы также должны установить DISPLAY, который в основном равен :0 и DBUS_SESSION_BUS_ADDRESS на unix:path=/run/user/<UID of user to display to>/bus


Пример с libnotify.
#include <libnotify/notify.h>
#include <unistd.h>
#include <errno.h>

int main(void) {
    if (getuid() != (uid_t)1000 && setuid(1000) == -1) {
        perror("setuid");
        return -1;
    }
    if (setenv("DISPLAY", ":0", 0) == -1) {
          perror("setenv DISPLAY");
          return-1;
    } // guessing 1000 as UID
    if (setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/1000/bus", 1) == -1) {
        perror("setenv DBUS");
        return-1;
    }

    notify_init ("Hello world!");
    NotifyNotification * Hello = notify_notification_new("Hello world",
            "This is an example notification.", "dialog-information");
    notify_notification_show(Hello, NULL);

    g_object_unref(G_OBJECT(Hello));
    notify_uninit();

    return 0;
}
...