1

The ps command on a POSIX compliant system can output the start time of a process, known as "STIME". Is there a corresponding POSIX syscall that I can make in C to work out a process's start time by PID?

Jack M
  • 4,769
  • 6
  • 43
  • 67

1 Answers1

3

The only portable, POSIX-compliant way appears to be to parse the output of the ps -o etime ... command to get the duration in days, hours, minutes, and seconds since the process was started - there doesn't appear to be a way to force the STIME column of ps -f ... to allow a precise determination of time. GNU/Linux ps, for example, will truncate the STIME column down to a MMMDD format, with no portable way to expand.

Per the POSIX ps documentation:

...

The -o option allows the output format to be specified under user control.

The application shall ensure that the format specification is a list of names presented as a single argument, or -separated. Each variable has a default header. The default header can be overridden by appending an and the new text of the header. The rest of the characters in the argument shall be used as the header text. The fields specified shall be written in the order specified on the command line, and should be arranged in columns in the output. The field widths shall be selected by the system to be at least as wide as the header text (default or overridden value). If the header text is null, such as -o user=, the field width shall be at least as wide as the default header text. If all header text fields are null, no header line shall be written.

The following names are recognized in the POSIX locale:

...

etime

In the POSIX locale, the elapsed time since the process was started, in the form:

[[dd-]hh:]mm:ss

where dd shall represent the number of days, hh the number of hours, mm the number of minutes, and ss the number of seconds. The dd field shall be a decimal integer. The hh, mm, and ss fields shall be two-digit decimal integers padded on the left with zeros.

...

For example, if you know the process id:

sprintf( buffer, "ps -o etime= -p %lld", ( long long ) pid );

FILE *pp = popen( buffer, "r" );

If you want to get all processes:

FILE *pp = popen( "ps -eo pid= -o etime=", "r" );

Note the use of the = after each format specifier. The = can be used with format specifiers to denote the column header. Leaving all column headers empty causes the header line to not be emitted, simplifying parsing.

You'll have to parse each line, and compare the duration to the current time to get an approximate start time of the process. The time you get may be skewed by any time updates to the system, and won't be accurate to more than a second or so, since the ps command it self will take time to run, and you can't really select a correct "current time" to compare each separate line from the ps output to since you can't tell how the ps command calculated the duration.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • 1
    Using `etime` is actually a magnitude better then using `ps -f` with `STIME` column. The problem is really `STIME` has no standard format, and [procps-ng ps](https://gitlab.com/procps-ng/procps/blob/master/ps/output.c#L1009) uses three possible formats with `strftime` for outputting the time depending on how long ago it was. – KamilCuk Dec 23 '19 at 22:20
  • @KamilCuk Nice that it can collapse all the way down to a year. :-( I seem to remember getting modification time off a file in `/proc` in the past (not portable nor POSIX, but I remember that it was simple and worked), but I looked at that on a Centos 7 server and the times in `/proc/self` were no longer constant and not a one reflected the actual start time of my shell. – Andrew Henle Dec 23 '19 at 22:28