Get TTY for systemd session

I am trying to open terminal on session of some process, but it is too hard. I am wrote some simple code, but it do not work when process is inside terminal emulator. Also, it should work for graphical session (and in this case start GUI program). I known to start a GUI program, I probably could use systemd run --user via DBUS (it is also hard, because I must known, where is socket for DBUS daemon and what is cookie).

This is my code:

static int get_terminal(char *data, int *major_r, int *minor_r)
{
  int number, major, minor;
  char *end;

  while (' ' == *data) ++data;
  puts(data);
  end = data;
  while (' ' != *end && '\0' != *end) ++ end;

  *end = '\0';

  puts(data);
  number = atoi(data);

  major = (number >> 8) & 0xFF;
  minor = ((number >> 13) & ~0b1111111) | (number & 0b11111111);

  *major_r = major;
  *minor_r = minor;
  //printf ("Major: %d\nMinor: %d\nFrom:%d\n\n", major, minor,number);

}
#if 0
static void spawn_message_on_tty(int major, int minor, const char *app, const char *file, dbus_int32_t rights)
{
  int fd =
}
#endif

static void skip_value(char **next_val_)
{
  bool complex_field = false;
  char *next_val = *next_val_;

  while (' ' == *next_val) ++next_val;

  if ('(' == *next_val) {
    while (')' != *next_val && '\0' != *next_val) ++next_val;
  }
  else {
    while (' ' != *next_val && '\0' != *next_val) ++next_val;

  }

    puts(next_val);
  *next_val_ = next_val;
}

static DBusHandlerResult handle_dbus_message(DBusConnection *connection, DBusMessage *message, void *user_data)
{
  DBusError error;
  const char *method = dbus_message_get_member(message);
  const char *interface = dbus_message_get_interface(message);

  if (0==strcmp("pl.art.lach.slawek.apps.SecureHome.SessionHelper", interface)) {
    if (0==strcmp("askForPermission", method)) {
      int fd;
      int pos;
      char path[PATH_MAX+1];
      char buffer[819200];
      dbus_int32_t rights;
      pid_t prog_pid;
      pid_t current_prog_pid;
      char *curr = buffer;
      int major, minor;


      const char *file;
      const char *app;
      dbus_error_init(&error);
      dbus_message_get_args(message, &error, DBUS_TYPE_STRING,&file, DBUS_TYPE_STRING,&app, DBUS_TYPE_INT32, &prog_pid,DBUS_TYPE_INT32, &rights,DBUS_TYPE_INVALID);

      if (dbus_error_is_set(&error)) {

        return DBUS_HANDLER_RESULT_HANDLED;
      }

#if 0
      /proc/[pid]/status:
       (7) tty_nr  %d
                    The controlling terminal of the process.  (The minor
                    device number is contained in the combination of
                    bits 31 to 20 and 7 to 0; the major device number is
                    in bits 15 to 8.)
      Separated by space probably
#endif
current_prog_pid = prog_pid;
  do {
      snprintf(path, sizeof(path), "/proc/%d/stat", current_prog_pid);

      fd = open(path, O_RDONLY);

      if (-1 == fd) {

        return DBUS_HANDLER_RESULT_HANDLED;
      }

      if (1 > (pos = read(fd, buffer, sizeof(buffer)))) {

        close(fd);
        return DBUS_HANDLER_RESULT_HANDLED;
      }

      close(fd);

      buffer[pos] = '\0';

      skip_value(&curr);
      skip_value(&curr);
      skip_value(&curr);
      skip_value(&curr);
      skip_value(&curr);
      skip_value(&curr);
      skip_value(&curr);

      get_terminal(curr, &major, &minor);

  printf ("Major: %d\nMinor: %d\n\n", major, minor);
      if (5 != major) {
        pid_t new_prog_id;
        char *substr;

        snprintf(path, sizeof(path), "/proc/%d/status", current_prog_pid);

        fd = open(path, O_RDONLY);

        if (1 > (pos = read(fd, buffer, sizeof(buffer)))) {
           close(fd);
           return DBUS_HANDLER_RESULT_HANDLED;
        }

        close(fd);

        buffer[pos] = '\0';

        substr = strstr(buffer, "\nPPid:");

        if (NULL == substr) {
          return DBUS_HANDLER_RESULT_HANDLED;
        }

        substr += sizeof("\nPPID:") - 1;

        while (isspace(*substr)) ++ substr;

        new_prog_id = atoi(substr);

        if (new_prog_id == current_prog_pid) {
          return DBUS_HANDLER_RESULT_HANDLED;
        }
        current_prog_pid = new_prog_id;
        continue;
      }
      break;
  } while (true);

  printf ("Major: %d\nMinor: %d\n\n", major, minor);
    }
  }

  return DBUS_HANDLER_RESULT_HANDLED;
}

So I read from state the controlling terminal and try to go up (to parent process) until we found 5 major number (tty) as controlling terminal. But I went to 1 and got 0 in next step as pid.

If you know session, you can use loginctl (or direct systemd-logind D-Bus interface) to obtain tty. If you need to know session, you can use GetSessionByPID method.

https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html

Sorry?

systemd-run --user --machine user@.host ...

Thaks.

I think that I do not understood systemd sessions.
In Bash:

> dbus-send --print-reply --system --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.GetSessionByPID uint32:$$
Error org.freedesktop.login1.NoSessionForPID: PID 34748 does not belong to any known session

Even:

> dbus-send --print-reply --system --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.GetSessionByPID uint32:`pidof kwin_wayland`

Do not work.

What I figure out:

> cat /proc/`pidof kwin_wayland`/cgroup 
0::/user.slice/user-1000.slice/user@1000.service/session.slice/plasma-kwin_wayland.service
slawomir@opensuse:~> cat /proc/`pidof startplasma-wayland`/cgroup 
0::/user.slice/user-1000.slice/session-3.scope

So only process for which dbus command worked have session-3.scope .

Meanwhile.

 cat /proc/$$/sessionid
4slawomir@opensuse:~> loginctl list-sessions 
SESSION  UID USER     SEAT  LEADER CLASS   TTY  IDLE SINCE
      3 1000 slawomir seat0 1822   user    tty3 no   -    
      4 1000 slawomir -     1827   manager -    no   -   

Returns some value. But there is no tty and no seat associated with session 4.