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.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.