diff --git a/man/ps.1 b/man/ps.1 index 7f933fcd..095425f4 100644 --- a/man/ps.1 +++ b/man/ps.1 @@ -1,10 +1,15 @@ -'\" t -.\" (The preceding line is a note to broken versions of man to tell -.\" Man page for ps. -.\" Quick hack conversion by Albert Cahalan, 1998. -.\" Licensed under version 2 of the Gnu General Public License. .\" -.TH PS "1" "2023-01-16" "procps-ng" "User Commands" +.\" Copyright 1998 Albert Cahalan +.\" 2011-2023 Jim Warner +.\" 2011-2023 Craig Small +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" +.TH PS "1" "2023-01-18" "procps-ng" "User Commands" .\" .\" To render this page: .\" groff -t -b -man -X -P-resolution -P100 -Tps ps.1 & @@ -598,6 +603,16 @@ Set screen width. .B \-\-cumulative Include some dead child process data (as a sum with the parent). .TP +.TP +.BI \-D \ format +Set the date format of the \fBlstart\fR field to \fIformat\fR. This format is parsed +by +.BR strftime (3) +and should be a maximum of 24 characters to not mis-align columns. +.TP +.BI \-\-date-format \ format +Identical to \fB\-D\fR. +.TP .B e Show the environment after the command. .TP @@ -1385,8 +1400,8 @@ the T} lstart STARTED T{ -time the command started. See also -.BR bsdstart , \ start , \ start_time ", and" \ stime . +time the command started. This will be in the form "DDD mmm HH:MM:SS YYY" +unless changed by the \fB\-D\fR option. T} lsession SESSION T{ @@ -2064,10 +2079,18 @@ unix98 standard .TE .PP .PP +.SH BUGS +The fields \fBbsdstart\fR and \fBstart\fR will only show the abbreviated +month name in English. The fields \fBlstart\fR and \fBstime\fR will show +the abbreviated month name in the configured locale but may exceed the +column width due to the different lengths for abbreviated month and day +names across languages. +.PP .SH "SEE ALSO" .BR pgrep (1), .BR pstree (1), .BR top (1), +.BR strftime (3), .BR proc (5). .PP .PP diff --git a/src/ps/common.h b/src/ps/common.h index 26bd38c0..6e416a34 100644 --- a/src/ps/common.h +++ b/src/ps/common.h @@ -451,6 +451,7 @@ extern int header_gap; extern int header_type; /* none, single, multi... */ extern int include_dead_children; extern int lines_to_next_header; +extern char *lstart_format; extern int max_line_width; extern int negate_selection; extern int page_size; // "int" for math reasons? diff --git a/src/ps/global.c b/src/ps/global.c index db67a782..826ca924 100644 --- a/src/ps/global.c +++ b/src/ps/global.c @@ -183,6 +183,7 @@ int header_gap = -1; int header_type = -1; int include_dead_children = -1; int lines_to_next_header = -1; +char *lstart_format = NULL; int negate_selection = -1; int running_only = -1; int page_size = -1; // "int" for math reasons? diff --git a/src/ps/help.c b/src/ps/help.c index b64833d3..dfd602d1 100644 --- a/src/ps/help.c +++ b/src/ps/help.c @@ -126,6 +126,7 @@ void do_help (const char *opt, int rc) { } if (section == HELP_OUT || section == HELP_ALL) { fputs(_("\nOutput formats:\n"), out); + fputs(_(" -D date format for lstart\n"), out); fputs(_(" -F extra full\n"), out); fputs(_(" -f full-format, including command lines\n"), out); fputs(_(" f, --forest ascii art process tree\n"), out); diff --git a/src/ps/output.c b/src/ps/output.c index 26001a6c..3074549c 100644 --- a/src/ps/output.c +++ b/src/ps/output.c @@ -1044,11 +1044,21 @@ setREL1(VM_RSS) return snprintf(outbuf, COLWID, "%2u.%u", (unsigned)(pmem/10), (unsigned)(pmem%10)); } +// Format cannot be %c as the length changes depending on locale +#define DEFAULT_LSTART_FORMAT "%a %b %e %H:%M:%S %Y" static int pr_lstart(char *restrict const outbuf, const proc_t *restrict const pp){ - time_t t; + time_t t; + struct tm start_time; + size_t len; setREL1(TICS_BEGAN) - t = boot_time() + rSv(TICS_BEGAN, ull_int, pp) / Hertz; - return snprintf(outbuf, COLWID, "%24.24s", ctime(&t)); + t = boot_time() + rSv(TICS_BEGAN, ull_int, pp) / Hertz; + if (localtime_r(&t, &start_time) == NULL) + return 0; + len = strftime(outbuf, COLWID, + (lstart_format?lstart_format:DEFAULT_LSTART_FORMAT), &start_time); + if (len <= 0 || len >= COLWID) + outbuf[len = 0] = '\0'; + return len; } /* Unix98 specifies a STIME header for a column that shows the start diff --git a/src/ps/parser.c b/src/ps/parser.c index b8362414..544f7369 100644 --- a/src/ps/parser.c +++ b/src/ps/parser.c @@ -244,6 +244,13 @@ static const char *parse_sysv_option(void){ if(err) return err; selection_list->typecode = SEL_COMM; return NULL; /* can't have any more options */ + case 'D': + trace("-D sets lstart date format\n"); + arg = get_opt_arg(); + if (!arg) return _("date format must follow -D"); + if (lstart_format) free(lstart_format); + lstart_format = strdup(arg); + break; case 'F': /* DYNIX/ptx -f plus sz,rss,psr=ENG between c and stime */ trace("-F does fuller listing\n"); format_modifiers |= FM_F; @@ -794,6 +801,7 @@ static const char *parse_gnu_option(void){ {"columns", &&case_columns}, {"context", &&case_context}, {"cumulative", &&case_cumulative}, + {"date-format", &&case_dateformat}, {"deselect", &&case_deselect}, /* -N */ {"forest", &&case_forest}, /* f -H */ {"format", &&case_format}, @@ -881,6 +889,12 @@ static const char *parse_gnu_option(void){ if(s[sl]) return _("option --cumulative does not take an argument"); include_dead_children = 1; return NULL; + case_dateformat: + arg=grab_gnu_arg(); + if (!arg) return _("date format must follow --date-format"); + if (lstart_format) free(lstart_format); + lstart_format = strdup(arg); + return NULL; case_deselect: trace("--deselect\n"); if(s[sl]) return _("option --deselect does not take an argument");