diff --git a/README.md b/README.md index ffb1e89..f1e2f15 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ If no command is given, `$SHELL` is used. | `kill [-f] ` | Gracefully stop a session (SIGTERM, then SIGKILL after 5 s if needed). With `-f` / `--force`, skip the grace period and send SIGKILL immediately. | | `clear []` | Truncate the on-disk session log. Defaults to the current session when run inside one. | | `tail [-f] [-n N] ` | Print the last N lines of the session log (default: 10). With `-f`, follow new output as it is written. | -| `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. | +| `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. | | `current` | Print the current session name and exit 0 if inside a session; exit 1 silently if not. | Short aliases: `a` → `attach`, `n` → `new`, `s` → `start`, `p` → `push`, diff --git a/atch.c b/atch.c index 94b49ae..ff8f2f1 100644 --- a/atch.c +++ b/atch.c @@ -343,10 +343,17 @@ static int is_cmd(const char *arg, const char *a, const char *b, const char *c) (b && strcmp(arg, b) == 0) || (c && strcmp(arg, c) == 0); } -/* atch list */ -static int cmd_list(void) +/* atch list [-a] */ +static int cmd_list(int argc, char **argv) { - return list_main(); + int show_all = 0; + + while (argc >= 1 && strcmp(argv[0], "-a") == 0) { + show_all = 1; + argc--; + argv++; + } + return list_main(show_all); } /* atch current @@ -709,7 +716,7 @@ static void usage(void) "\tPrint last N lines of session log\n" " -f\t\t\t\tFollow log output\n" " -n \t\t\tNumber of lines (default 10)\n" - " list\t\t\t\t\tList all sessions\n" + " list [-a]\t\t\t\tList sessions (-a includes exited)\n" " current\t\t\t\tPrint current session name\n" "\n" "Options:\n" @@ -781,7 +788,7 @@ int main(int argc, char **argv) if (mode == '?' || mode == 'h') usage(); if (mode == 'l') - return cmd_list(); + return cmd_list(argc, argv); if (mode == 'i') return cmd_current(); if (mode != 'a' && mode != 'A' && mode != 'c' && @@ -876,7 +883,7 @@ int main(int argc, char **argv) --argc; if (is_cmd(cmd, "list", "l", "ls")) - return cmd_list(); + return cmd_list(argc, argv); if (is_cmd(cmd, "current", NULL, NULL)) return cmd_current(); if (is_cmd(cmd, "attach", "a", NULL)) diff --git a/atch.h b/atch.h index d1a299a..8fc6829 100644 --- a/atch.h +++ b/atch.h @@ -135,7 +135,7 @@ int replay_session_log(int saved_errno); int attach_main(int noerror); int master_main(char **argv, int waitattach, int dontfork); int push_main(void); -int list_main(void); +int list_main(int show_all); int kill_main(int force); char const * clear_csi_data(void); diff --git a/attach.c b/attach.c index c3722b0..2de74ac 100644 --- a/attach.c +++ b/attach.c @@ -603,7 +603,7 @@ int kill_main(int force) return 1; } -int list_main(void) +int list_main(int show_all) { char dir[512]; char path[768]; /* sizeof(dir) + '/' + NAME_MAX */ @@ -656,6 +656,44 @@ int list_main(void) closedir(d); + /* Second pass: show exited sessions (log files without a socket). */ + if (show_all) { + d = opendir(dir); + if (d) { + while ((ent = readdir(d)) != NULL) { + struct stat lst; + char age[32]; + size_t nlen = strlen(ent->d_name); + + if (nlen <= 4 || + strcmp(ent->d_name + nlen - 4, ".log") != 0) + continue; + + /* Build socket path (name without .log). */ + snprintf(path, sizeof(path), "%s/%.*s", + dir, (int)(nlen - 4), ent->d_name); + + /* Skip if the socket still exists (already listed). */ + if (access(path, F_OK) == 0) + continue; + + /* Stat the log file for its mtime. */ + snprintf(path, sizeof(path), "%s/%s", + dir, ent->d_name); + if (stat(path, &lst) < 0) + continue; + + format_age(now > lst.st_mtime ? + now - lst.st_mtime : 0, + age, sizeof(age)); + printf("%-24.*s since %s ago [exited]\n", + (int)(nlen - 4), ent->d_name, age); + count++; + } + closedir(d); + } + } + empty: if (count == 0 && !quiet) printf("(no sessions)\n");