Skip to content

Commit 010e671

Browse files
Add list -a flag to show exited sessions
Scan for .log files without a matching socket and display them with [exited] tag. Allows users to see sessions that ended cleanly but still have replay logs available.
1 parent 0277b3e commit 010e671

4 files changed

Lines changed: 54 additions & 9 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ If no command is given, `$SHELL` is used.
8383
| `push <session>` | Copy stdin verbatim to the session. |
8484
| `kill [-f] <session>` | Gracefully stop a session (SIGTERM, then SIGKILL after 5 s if needed). With `-f` / `--force`, skip the grace period and send SIGKILL immediately. |
8585
| `clear [<session>]` | Truncate the on-disk session log. Defaults to the current session when run inside one. |
86-
| `list` | List all sessions. Shows `[attached]` when a client is connected, `[stale]` for leftover sockets with no running master. Prints `(no sessions)` when the list is empty. |
86+
| `list [-a]` | List sessions. Shows `[attached]` when a client is connected, `[stale]` for leftover sockets with no running master. With `-a`, also shows `[exited]` sessions that have a log file but are no longer running. Prints `(no sessions)` when the list is empty. |
8787
| `current` | Print the current session name and exit 0 if inside a session; exit 1 silently if not. |
8888

8989
Short aliases: `a``attach`, `n``new`, `s``start`, `p``push`,

atch.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,17 @@ static int is_cmd(const char *arg, const char *a, const char *b, const char *c)
343343
(b && strcmp(arg, b) == 0) || (c && strcmp(arg, c) == 0);
344344
}
345345

346-
/* atch list */
347-
static int cmd_list(void)
346+
/* atch list [-a] */
347+
static int cmd_list(int argc, char **argv)
348348
{
349-
return list_main();
349+
int show_all = 0;
350+
351+
while (argc >= 1 && strcmp(argv[0], "-a") == 0) {
352+
show_all = 1;
353+
argc--;
354+
argv++;
355+
}
356+
return list_main(show_all);
350357
}
351358

352359
/* atch current
@@ -595,7 +602,7 @@ static void usage(void)
595602
" -f, --force\t\t\tSkip grace period, send SIGKILL immediately\n"
596603
" clear [<session>]"
597604
"\t\t\tTruncate the session log\n"
598-
" list\t\t\t\t\tList all sessions\n"
605+
" list [-a]\t\t\t\tList sessions (-a includes exited)\n"
599606
" current\t\t\t\tPrint current session name\n"
600607
"\n"
601608
"Options:\n"
@@ -667,7 +674,7 @@ int main(int argc, char **argv)
667674
if (mode == '?' || mode == 'h')
668675
usage();
669676
if (mode == 'l')
670-
return cmd_list();
677+
return cmd_list(argc, argv);
671678
if (mode == 'i')
672679
return cmd_current();
673680
if (mode != 'a' && mode != 'A' && mode != 'c' &&
@@ -762,7 +769,7 @@ int main(int argc, char **argv)
762769
--argc;
763770

764771
if (is_cmd(cmd, "list", "l", "ls"))
765-
return cmd_list();
772+
return cmd_list(argc, argv);
766773
if (is_cmd(cmd, "current", NULL, NULL))
767774
return cmd_current();
768775
if (is_cmd(cmd, "attach", "a", NULL))

atch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ int replay_session_log(int saved_errno);
135135
int attach_main(int noerror);
136136
int master_main(char **argv, int waitattach, int dontfork);
137137
int push_main(void);
138-
int list_main(void);
138+
int list_main(int show_all);
139139
int kill_main(int force);
140140

141141
char const * clear_csi_data(void);

attach.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ int kill_main(int force)
603603
return 1;
604604
}
605605

606-
int list_main(void)
606+
int list_main(int show_all)
607607
{
608608
char dir[512];
609609
char path[768]; /* sizeof(dir) + '/' + NAME_MAX */
@@ -656,6 +656,44 @@ int list_main(void)
656656

657657
closedir(d);
658658

659+
/* Second pass: show exited sessions (log files without a socket). */
660+
if (show_all) {
661+
d = opendir(dir);
662+
if (d) {
663+
while ((ent = readdir(d)) != NULL) {
664+
struct stat lst;
665+
char age[32];
666+
size_t nlen = strlen(ent->d_name);
667+
668+
if (nlen <= 4 ||
669+
strcmp(ent->d_name + nlen - 4, ".log") != 0)
670+
continue;
671+
672+
/* Build socket path (name without .log). */
673+
snprintf(path, sizeof(path), "%s/%.*s",
674+
dir, (int)(nlen - 4), ent->d_name);
675+
676+
/* Skip if the socket still exists (already listed). */
677+
if (access(path, F_OK) == 0)
678+
continue;
679+
680+
/* Stat the log file for its mtime. */
681+
snprintf(path, sizeof(path), "%s/%s",
682+
dir, ent->d_name);
683+
if (stat(path, &lst) < 0)
684+
continue;
685+
686+
format_age(now > lst.st_mtime ?
687+
now - lst.st_mtime : 0,
688+
age, sizeof(age));
689+
printf("%-24.*s since %s ago [exited]\n",
690+
(int)(nlen - 4), ent->d_name, age);
691+
count++;
692+
}
693+
closedir(d);
694+
}
695+
}
696+
659697
empty:
660698
if (count == 0 && !quiet)
661699
printf("(no sessions)\n");

0 commit comments

Comments
 (0)