Euphoria
Ticket #968:
read_file fails to read /proc/<pid>/cmdline on Linux
-
Reported by
jmduro
Aug 24, 2017
Tested on
Euphoria Interpreter v4.1.0 development
64-bit Linux, Using System Memory
Revision Date: 2015-02-02 14:18:53, Id: 5861:57179171dbed
cat /proc/1713/cmdline shows command line of pid 1713
$ cat /proc/1713/cmdline
/usr/lib/kde4/libexec/kaccessibleapp$
read_file returns an empty sequence
printf(1, "[%d] %s\n", {i, sprint(s)})
name = read_file("/proc/" & s[D_NAME] & "/cmdline")
printf(1, " %s: %s\n", {"/proc/" & s[D_NAME] & "/cmdline", sprint(name)})
[214] {{49,55,49,51},{100},0,2017,8,24,7,39,56,0,0}
/proc/1713/cmdline: {}
Jean-Marc
Details
1. Comment by jmduro
Aug 24, 2017
read_lines does the job where read_file fails:
/proc/1713/cmdline: {{47,117,115,114,47,108,105,98,47,107,100,101,52,47,108,105,98,101,120,101,99,47,107,97,99,99,101,115,115,105,98,108,101,97,112,112,0}}
2. Comment by jimcbrown
Aug 24, 2017
This one is pretty straight-forward.
read_file() relies on seek(-1) to figure out the length of the file. However, procfs doesn't appear to support this. procfs is an unusual case. du and ls also report that /proc/1/cmdline is 0 bytes, and file reports that it is an empty file.
This is described better here: https://unix.stackexchange.com/questions/282701/why-some-shells-read-builtin-fail-to-read-the-whole-line-from-file-in-proc
I don't think it's worth bothering to fix read_file() to handle this unusual case, but it may make sense to have some alternative function that just does flatten(read_lines()) or something. If we really did want to fix read_file(), we could modify it so that if the seek(-1) reports a length of zero or less, then ignore it and just use a while loop to read data until EOF is hit. (This, incidently, is how read_lines() works and thus the reason that it is able to read data from those files.)
3. Comment by jmduro
Aug 24, 2017
OK Jim,
Here is how I get my process IDs:
without warning
include std/error.e
include std/filesys.e
include std/os.e
include std/text.e
include std/convert.e
include std/search.e
include std/io.e
include lib/_types_.e
include lib/_debug_.e
include lib/_file_.e
include lib/_sequence_.e
include lib/_conv_.e
------------------------------------------------------------------------------
function get_process_id(sequence processname)
-- Returns pids of processname instances
object x
sequence processes = {}, s, name
integer fn, c, ownPID
x = dir("/proc/*")
ownPID = get_pid()
if sequence(x) then -- Exclude forbidden DIRs
for i = 1 to length(x) do -- Loop through DIR content
s = x[i]
if find('d',s[D_ATTRIBUTES]) and
not (equal(s[D_NAME],".") or equal(s[D_NAME],"..")) then -- Check for SubDIRs
if is_integer(s[D_NAME]) and (ownPID != to_number(s[D_NAME])) then
fn = open("/proc/" & s[D_NAME] & "/cmdline", "rb")
name = ""
c = getc(fn)
while (c != EOF) do
if c then name &= c end if -- remove NULL
c = getc(fn)
end while
close(fn)
if sequence(name) and length(name) then
if match(processname, name) then
processes = append(processes, s[D_NAME])
end if
end if
end if
end if
end for
end if
return processes
end function
------------------------------------------------------------------------------
function is_running(sequence processname)
-- Returns true if at least one instance of processname is running
sequence processes
processes = get_process_id(processname)
return length(processes) > 0
end function
------------------------------------------------------------------------------
sequence processname
sequence cmd = command_line()
if length(cmd)< 3 then
puts(1, "Syntax: is_running process_cmdline\n")
abort(1)
end if
processname = cmd[3]
puts(1, "processname: '" & processname & "'\n")
if length(processname)>0 then
if is_running(processname) then
puts(1, "Process " & processname & " is running\n")
else
puts(1, "No process " & processname & " found\n")
end if
end if