| 197 | /* Display a line of information about UTMP_ENT. */ |
| 198 | |
| 199 | static void |
| 200 | print_entry (STRUCT_UTMP const *utmp_ent) |
| 201 | { |
| 202 | /* If ut_line contains a space, the device name starts after the space. */ |
| 203 | char *line = utmp_ent->ut_line; |
| 204 | char *space = strchr (line, ' '); |
| 205 | line = space ? space + 1 : line; |
| 206 | |
| 207 | int dirfd; |
| 208 | if (IS_ABSOLUTE_FILE_NAME (line)) |
| 209 | dirfd = AT_FDCWD; |
| 210 | else |
| 211 | { |
| 212 | static int dev_dirfd; |
| 213 | if (!dev_dirfd) |
| 214 | { |
| 215 | dev_dirfd = open ("/dev", O_PATHSEARCH | O_DIRECTORY); |
| 216 | if (dev_dirfd < 0) |
| 217 | dev_dirfd = AT_FDCWD - 1; |
| 218 | } |
| 219 | dirfd = dev_dirfd; |
| 220 | } |
| 221 | |
| 222 | struct stat stats; |
| 223 | time_t last_change; |
| 224 | char mesg; |
| 225 | if (AT_FDCWD <= dirfd && fstatat (dirfd, line, &stats, 0) == 0) |
| 226 | { |
| 227 | mesg = (stats.st_mode & S_IWGRP) ? ' ' : '*'; |
| 228 | last_change = stats.st_atime; |
| 229 | } |
| 230 | else |
| 231 | { |
| 232 | mesg = '?'; |
| 233 | last_change = 0; |
| 234 | } |
| 235 | |
| 236 | char *ut_user = utmp_ent->ut_user; |
| 237 | if (strnlen (ut_user, 8) < 8) |
| 238 | printf ("%-8s", ut_user); |
| 239 | else |
| 240 | fputs (ut_user, stdout); |
| 241 | |
| 242 | if (include_fullname) |
| 243 | { |
| 244 | struct passwd *pw = getpwnam (ut_user); |
| 245 | if (pw == NULL) |
| 246 | /* TRANSLATORS: Real name is unknown; at most 19 characters. */ |
| 247 | printf (" %19s", _(" ???")); |
| 248 | else |
| 249 | { |
| 250 | char *const comma = strchr (pw->pw_gecos, ','); |
| 251 | |
| 252 | if (comma) |
| 253 | *comma = '\0'; |
| 254 | |
| 255 | char *result = create_fullname (pw->pw_gecos, pw->pw_name); |
| 256 | printf (" %-19.19s", result); |
no test coverage detected