bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: bug when 'cd ..' to a directory who's parent has been deleted


From: Linda Walsh
Subject: Re: bug when 'cd ..' to a directory who's parent has been deleted
Date: Mon, 08 Feb 2016 15:39:16 -0800
User-agent: Thunderbird



Dave Rutherford wrote:


On Mon, Feb 8, 2016 at 11:34 AM, Linda Walsh <address@hidden <mailto:address@hidden>> wrote:
>> Why would that be more reasonable than anything else?  It references a
>> path that doesn't exist.
> Um...Not exactly.  As long as there's a handle open to the previous path,
> it still exists (at least on linux and unix).

Really?
11:40:24 address@hidden:~$ mkdir -p a/a
11:40:30 address@hidden:~$ cd a/a
[remove a in another window]
11:40:49 address@hidden:~/a/a$ touch file
touch: cannot touch ‘file’: No such file or directory
----

Yes!  Really.  You and Andreas have to read what was written.

Pretty much the same setup as you have, but I'm using an "fd" to
the previous path. Are you using an "fd" in your example, I seem
to be missing it.

Ish:lw> ll a
ls: cannot access a: No such file or directory
Ish:lw> mkdir -p a/a
Ish:lw> cd a/a
Ish:lw/a/a> cp /tmp/filesave.txt file.txt
Ish:lw/a/a> ll
total 4
-rw-rw-r-- 1 415 Feb  8 13:39 file.txt
Ish:lw/a/a> rm -f /tmp/ctl; Delayed_save_file_via_fd <file.txt /tmp/ctl &
[1] 41237
Ish:lw/a/a> ...Reading...

[[[[[ Other term>
Ish:lw> rm -fr "a/" ; echo -e ~/a/a/file.txt\\n.\\n >/tmp/ctl
]]]]] Original term:

saved 415 bytes in file "file.txt", dir "/home/lw/a/a"
cd "$PWD"
[1]+  Exit 1                  Delayed_save_file_via_fd /tmp/ctl < file.txt
Ish:lw/a/a> ll
total 4
-rw-rw-r-- 1 415 Feb  8 15:16 file.txt
--------------------
Delayed_save_file_via_fd is attached.




Andreas Schwab wrote:
You cannot have handles on file names, only on files.
---
I said:
    "As long as there's a handle open to the previous path..."


You can't open a file handle on a file.  The fd comes from some
OS call associating it with the file on disk (or some other connection).

Not only that, but you can **run** from those deleted paths --
the kernel says the "fd" is associate with deleted path:

Ish:lw/a/a> cp /usr/bin/sleep .
Ish:lw/a/a> ll
total 48
-rw-rw-r-- 1   415 Feb  8 15:16 file.txt
-rwxr-xr-x 1 41676 Mar  2  2015 sleep*
Ish:lw/a/a> sleep 999&
[1] 41987
Ish:lw/a/a> cd ../..
Ish:lw> rm -fr a
Ish:lw> deleted_procs

Deleted programs      Pid(s)
------------------     ------
/home/lw/a/a/sleep    41987


Looks like a path to me.  Will attach "deleted_procs" too.




#!/bin/bash -u

#include stdalias
shopt -s expand_aliases
alias sub=function my=declare
alias int='my -i'  string=my  intConst='my -ir' array='my -a'

export 
PS4='>${BASH_SOURCE:+${BASH_SOURCE[0]/$HOME/\~}}#${LINENO}${FUNCNAME:+(${FUNCNAME[0]})}>
 '

shopt -s extdebug

my cd=$PWD
int tries=-1
string h1="" h2=""
intConst EPERM=1 EINVAL=22 ENOTDIR=20
int verbose=0


sub inf () {
        (($#)) || return 0
        int newline=1
        if [[ $1 == "-n" ]]; then newline=0; shift; fi
        (($#)) || return 0
        my out=""
        printf -v out "$@"
        if ((newline)) && [[ ${out:0-1} != $'\n' ]]; then
                out="$out"$'\n'
        fi
        printf >&2 "%s" "$out"
        ((verbose)) && sleep .1
        return 0
}

sub err () {
        int stat=$EINVAL
        if (($#)); then
                if [[ $1 =~ ^[-0-9]+$ ]]; then
                        stat=$1; shift
                fi
                if (($#)); then
                        inf "$@"
                else
                        inf 'Err status=%d\n' "$stat";
                fi
                return $stat
        else
                return 0
        fi
}

sub get_sp() {

        while [[ ! -f $control ]];do sleep 1; echo -n . ;  done
        while [[ ! $savepath ]]; do
                read -t 1 inp  <"$control"
                if [[ $inp ]]; then
                        if [[ $inp != . ]]; then
                                savepath=$inp
                        fi
                        break
                fi
        done

        [[ ${savepath:0:1} != / ]] && savepath="$cd$savepath"
}

sub get_content () {
        inf -n "Reading..."
        while read inp;do
                my out=""
                printf -v out '%s\n' "$inp"
                content+=( "$out" )
                content_len+=${#out}
        done
}



sub saveworker() {
        my control=${1:?"need place to get fn"}
        array content=()
        int content_len=0
        my inp="" savepath=""
        string h1=""
        string h2=""

        get_sp

        ((verbose)) && inf 'Got save path as:%s' "$savepath"

        get_content

        ((verbose)) && inf 'Attempting to save %d lines (%d chars) in %s\n' \
                        "address@hidden" "$content_len" "$savepath"

        my d=${savepath%/*}
        my f=${savepath##*/}

        while [[ ! -d $d ]]; do
                if ((tries+=1)); then
                        inf 'Attempting to REcreate %s\n' "$d"
                fi
                mkdir -p "$d/.hold"
                int mstat=$?

                if ((!mstat)); then h1="$d/.hold"
                else
                        err $mstat "Cannot mkdir -p %s" "$d/.hold"
                        return $?
                fi
                if ! cd "$d" ; then
                        err "$ENOTDIR" "Cannot mkdir %s; savefile failed.\n" 
"$d"
                        return $?
                fi
        done
        
        
        while [[ ! -s $f ]]; do
                if ! printf '%s' >"$f" "address@hidden" ; then
                        if [[ ! -O . ]]; then
                                err $EPERM 'Cannot write to dir "%s: Not 
Owner\n' "$d"
                                return $?
                        fi
                        if [[ ! -w . ]]; then 
                                if chmod u+rwx . ; then
                                        mkdir .hold2  && h2=1
                                fi
                                if [[ ! -d .hold2 ]]; then
                                        err $EPERM 'Cannot write in dir %s\n' 
"$f" "$d"
                                        return $?
                                fi
                        fi
                        continue
                fi
        done
        inf '\nsaved %d bytes in file "%s", dir "%s"' "$(stat -c"%s" "$f")" 
"$f" "$d"
        return 0
}
        
sub savefile() {
        saveworker "$@"
        [[ $h1 ]] && rd "$h1"
        [[ $h2 ]] && rd "$h2"
}
        
(($#)) || {
        err 'Need control file name into which gets savepath'
}

savefile "$@"

#!/bin/bash -u

declare op=""   p=""
declare -ia pds=()
declare -i n=0
declare dnul='/dev/null'
declare outfmt="%-21s  %s\n"

print_prog_n_pids () {
        declare -i pnum=${#pds[*]}
        ((pnum)) || return
        declare psfx="";
        ((pnum!=1)) && psfx="s"
        printf "$outfmt" "$op"  "${pds[*]}"
        pds=($n)
        op="$p"
}


printf "\n$outfmt"      " Deleted programs"     "Pid(s)"
printf "$outfmt"                "------------------"    "------"

sudo -- /usr/bin/ls 2>$dnul -gG --show-control-chars -lrt                       
                \
        $(ps h -eo pid,cmd      | grep -Pv '\[.+\]$|PID'        | print_field_n 
1       |
                sed -r 's!^(.*)$!/proc/\1/exe!'                                 
                | tr "\n" " " )         |
        fgrep "(deleted)"               |
        sed -r 's!^[^/]+/proc/!!
                                        s!^([1-9][0-9]*)/exe[^/]+(/.*) 
\(deleted\).*$!\2\t\1! ' |
        sort                                                            |
        while read p n; do 
                [[ ! $op ]] && op=$p
                if [[ $op == $p ]];then 
                        pds+=($n)
                else 
                        print_prog_n_pids "$op" "${pds[*]}"
                fi
        done

print_prog_n_pids



reply via email to

[Prev in Thread] Current Thread [Next in Thread]