If you're using C or C++, and don't want the systemd dependency, you can use the POSIX standard ttyname() or ttyname_r() to get your process's controlling terminal:
SYNOPSIS
#include <unistd.h>
char ttyname(int fildes);
int ttyname_r(int fildes, char name, size_t namesize);
DESCRIPTION
The ttyname() function shall return a pointer to a string containing a null-terminated pathname of the terminal associated with file descriptor fildes. The application shall not modify the string returned. The returned pointer might be invalidated or the string content might be overwritten by a subsequent call to ttyname(). The returned pointer and the string content might also be invalidated if the calling thread is terminated.
The ttyname() function need not be thread-safe.
The ttyname_r() function shall store the null-terminated pathname of the terminal associated with the file descriptor fildes in the character array referenced by name. The array is namesize characters long and should have space for the name and the terminating null character. The maximum length of the terminal name shall be {TTY_NAME_MAX}.
Just pass 0 (or STDIN_FILENO) to get the name of your process's controlling terminal in a portable manner.
On every instance of Linux I've checked, users logged on to a text console have a /dev/ttyN tty.
That seems to be definitive for text console logins.
Graphical logins are a bit harder. On Linux you'll get a psuedoterminal name like /dev/pts/N. Which means your DISPLAY environment variable is your controlling terminal. As a first approximation, if that's :0 or :0.0, the process is almost certainly being run by someone logged in to the physical console. That may be enough for you, although you could make an XOpenDisplay() call with the value from the DISPLAY environment variable to be sure.
That will misidentify anyone using something like XVNC or other remote-desktop protocols to access a system that's configured to give those users the :0 display instead of starting with the :10 display as being logged in to the physical console. That is something I've never seen, but it's theoretically possible.
If you don't have to deal with that, you've now identified that your process is running on a Linux physical console.
If you do have to handle that situation, you have to determine if the X server you're connecting to is running on the physical console. Offhand, I don't know any easy way to do that, but if it's a local display you should be able to get the PID from lsof /tmp/.X11-unix/XN (although parsing the output of fuser is probably easier), where N is the display number from the DISPLAY environment variable. Once you get the PID, you can read /proc/PID/fd/0 to get the controlling terminal of the X server, and if that's /dev/ttyN, that again indicates the user is logged on to the physical console, with physical access to the system.
ResultActive/ResultInactivewould fit the bill? See for example Is there anything that can be done via a console login, but not via an SSH login? – steeldriver Jun 11 '23 at 02:10