1 /* Examine all the clients attached to our screen and find the one
2 * with the least idle time. */
4 /* Inconsistent results may appear in case of nested screens on the
19 #include "screenenv.h"
27 /* Load procinfo for given process. */
28 static void get_procinfo(pid_t pid
, struct procinfo
*pi
)
34 snprintf(statfname
, sizeof(statfname
), "/proc/%d/stat", pid
);
35 int fd
= open(statfname
, O_RDONLY
);
38 ssize_t r
= read(fd
, pi
->buf_
, sizeof(pi
->buf_
) - 1);
43 pi
->name
= strchr(pi
->buf_
, '(') + 1;
44 char *nameend
= strrchr(pi
->buf_
, ')');
46 pi
->ppid
= atol(nameend
+ 4);
49 /* Find master screen process. */
50 static pid_t
get_screen_pid(pid_t base_pid
)
52 struct procinfo pi
= { .ppid
= base_pid
};
54 get_procinfo(pi
.ppid
, &pi
);
55 } while (pi
.name
&& strcmp(pi
.name
, "screen") && pi
.ppid
> 0);
56 if (!pi
.name
|| pi
.ppid
<= 0)
62 /* Find pts of a process with the least idle time. */
63 static dev_t
get_active_pts(pid_t pid
)
66 snprintf(fddname
, sizeof(fddname
), "/proc/%d/fd", pid
);
67 DIR *fdd
= opendir(fddname
);
73 struct dirent
*de
, *res
;
74 de
= alloca(sizeof(*de
) + 4096);
76 if (readdir_r(fdd
, de
, &res
) != 0)
81 /* Pick files we can see and are pts devices */
83 if (fstatat(dirfd(fdd
), de
->d_name
, &s
, 0) != 0)
85 if (major(s
.st_rdev
) != 136)
87 /* and choose the one with the least idletime. */
88 if (s
.st_atime
< bestatime
)
91 bestatime
= s
.st_atime
;
95 return bestatime
> 0 ? bestpts
: 0;
99 /* Scan all processes for a screen with the given pts as stdin. */
100 static pid_t
get_client_by_pts(dev_t pts
)
102 DIR *procd
= opendir("/proc");
103 if (!procd
) return 0;
105 struct dirent
*de
, *res
;
106 de
= alloca(sizeof(*de
) + 4096);
108 if (readdir_r(procd
, de
, &res
) != 0)
112 int namelen
= strlen(de
->d_name
);
114 /* Pick numerical directories */
115 if (de
->d_type
!= DT_DIR
|| !isdigit(de
->d_name
[0]))
119 char name
[namelen
+ 7];
120 stpcpy(stpcpy(name
, de
->d_name
), "/fd/0");
123 if (fstatat(dirfd(procd
), name
, &s
, 0) != 0)
125 if (s
.st_rdev
!= pts
)
128 /* Is this screen? */
129 pid_t pid
= atol(de
->d_name
);
131 get_procinfo(pid
, &pi
);
132 if (pi
.name
== NULL
|| strcmp(pi
.name
, "screen"))
144 /* Find the client screen process watching base_pid with the least
146 pid_t
get_client_pid(pid_t base_pid
)
148 static pid_t screen_pid
;
149 if (screen_pid
< 0) return -1;
150 if (screen_pid
== 0) {
151 screen_pid
= get_screen_pid(base_pid
);
152 if (screen_pid
< 0) return -1;
154 dev_t client_pts
= get_active_pts(screen_pid
);
155 if (client_pts
== 0) return -1;
156 return get_client_by_pts(client_pts
);
163 printf("%d\n", get_client_pid(getpid()));