Home » Php » php – Cron sessionclean errors: find: `/proc/xxxxx/fd': No such file or directory

php – Cron sessionclean errors: find: `/proc/xxxxx/fd': No such file or directory

Posted by: admin July 12, 2020 Leave a comment

Questions:

After PHP upgrade I started to get the following cron errors several times a day:

find: `/proc/xxxxx/fd': No such file or directory

It comes from PHP sessionclean cron job:

[ -x /usr/lib/php5/sessionclean ] && /usr/lib/php5/sessionclean

Any ideas?

How to&Answers:

There now is a Debian bug reported (and fixed) about this.

It mentions about a release to stable:

In the next security upload, e.g. roughly two weeks after 5.6.23 is
released, unless something else critical shows up.

5.6.23 is out, so I expect it within the next two weeks.

The fix there is to add

if [ -d "/proc/$pid/fd" ]; then

before the

find "/proc/$pid/fd"

command.

Answer:

You can ignore those errors, the sessionclean search for session attached to a no longer existing pid.

[ -x /usr/lib/php5/sessionclean ] && /usr/lib/php5/sessionclean 2>/dev/null

You should look inside your session directory to check that they are correctly cleaned because such message might be symptomatic of a too long processing.

Answer:

I found a way to eliminate the errors, although, all bets are off as to whether you are eliminating a problem or just masking it. I have several containers running, and some have this problem while others don’t.

The /usr/lib/php5/sessionclean that will generate the error is:

#!/bin/sh -e

SAPIS="apache2:apache2\napache2filter:apache2\ncgi:php5\nfpm:php5-fpm\n"

# Iterate through all web SAPIs
(
printf "$SAPIS" | { \
proc_names=""
while IFS=: read -r conf_dir proc_name; do
    if [ -e /etc/php5/${conf_dir}/php.ini ]; then
        # Get all session variables once so we don't need to start PHP to get each config option
        session_config=$(php5 -c /etc/php5/${conf_dir}/php.ini -d "error_reporting='~E_ALL'" -r 'foreach(ini_get_all("session") as $k => $v) echo "$k=".$v["local_value"]."\n";')
        save_handler=$(echo "$session_config" | sed -ne 's/^session\.save_handler=\(.*\)$//p')
        save_path=$(echo "$session_config" | sed -ne 's/^session\.save_path=\(.*\)$//p')
        gc_maxlifetime=$(($(echo "$session_config" | sed -ne 's/^session\.gc_maxlifetime=\(.*\)$//p')/60))

        if [ "$save_handler" = "files" -a -d "$save_path" ]; then
            proc_names="$proc_names $proc_name";
            printf "%s:%s\n" "$save_path" "$gc_maxlifetime"
        fi
    fi
done
# first find all open session files and touch them (hope it's not massive amount of files)
for pid in $(pidof $proc_names); do
    find "/proc/$pid/fd" -ignore_readdir_race -lname "$save_path/sess_\*" -exec touch -c {} \;
done
} ) | sort -rn -t: -k2,2 | sort -u -t: -k 1,1 | while IFS=: read -r save_path gc_maxlifetime; do
    # find all files older then maxlifetime and delete them
    find -O3 "$save_path" -depth -mindepth 1 -name 'sess_*' -ignore_readdir_race -type f -cmin "+$gc_maxlifetime" -delete
done

exit 0

But if I replace that w/a /usr/lib/php5/sessionclean from a container that doesn’t generate the error, which is:

#!/bin/sh -e

SAPIS="apache2:apache2\napache2filter:apache2\ncgi:php5\nfpm:php5-fpm\n"

# Iterate through all web SAPIs
(
proc_names=""
printf "$SAPIS" | \
while IFS=: read -r conf_dir proc_name; do
    if [ -e /etc/php5/${conf_dir}/php.ini ]; then
        # Get all session variables once so we don't need to start PHP to get each config option
        session_config=$(php5 -c /etc/php5/${conf_dir}/php.ini -d "error_reporting='~E_ALL'" -r 'foreach(ini_get_all("session") as $k => $v) echo "$k=".$v["local_value"]."\n";')
        save_handler=$(echo "$session_config" | sed -ne 's/^session\.save_handler=\(.*\)$//p')
        save_path=$(echo "$session_config" | sed -ne 's/^session\.save_path=\(.*\)$//p')
        gc_maxlifetime=$(($(echo "$session_config" | sed -ne 's/^session\.gc_maxlifetime=\(.*\)$//p')/60))

        if [ "$save_handler" = "files" -a -d "$save_path" ]; then
            proc_names="$proc_names $proc_name";
            printf "%s:%s\n" "$save_path" "$gc_maxlifetime"
        fi
    fi
done
# first find all open session files and touch them (hope it's not massive amount of files)
for pid in $(pidof $proc_names); do
    find "/proc/$pid/fd" -ignore_readdir_race -lname "$save_path/sess_\*" -exec touch -c {} \;
done
) | sort -rn -t: -k2,2 | sort -u -t: -k 1,1 | while IFS=: read -r save_path gc_maxlifetime; do
    # find all files older then maxlifetime and delete them
    find -O3 "$save_path" -depth -mindepth 1 -name 'sess_*' -ignore_readdir_race -type f -cmin "+$gc_maxlifetime" -delete
done

exit 0

Then I don’t get the errors.