aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/usr/bin/zenity-cancel
blob: d0aa7f53b3bf11421a41490e539c9fe0cb56e2af (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash
###################################################################################################
# zenity-cancel
###################################################################################################
# Copyright 2017 Nicolas Bernaerts 
# http://bernaerts.dyndns.org/linux/331-linux-cancel-zenity-progress-dialog-right-way
#
# Enhanced by Jean-Christophe Manciot <jcmanciot@sdxlive.com>
# All descendants are now taken into account, not just children processes.
#
# Licensed under a GPLv3 License; you may not use this file except in compliance with the License. 
# You may obtain a copy of the License at
#
#    https://www.gnu.org/licenses/gpl-3.0.md
#
# The licensor cannot revoke these freedoms as long as you follow the license terms.
#
# Attribution — You must give appropriate credit, provide a link to the license, and indicate if 
#               changes were made. You may do so in any reasonable manner, but not in any way that 
#               suggests the licensor endorses you or your use.
###################################################################################################

###################################################################################################
#
# Cancelling a Zenity Progress Dialog the right way
#
###################################################################################################
#
# Requirements:
# ------------
#
# - We assume that:
#       + findutils & procps packages are already installed.
#
###################################################################################################
#
# Parameters:
# ----------
#
# - <parent_pgid> contains the firstly created parent process id, which is running all its children
#
# - <zenity_pid> contains the zenity process id
#
###################################################################################################
#
# Returned values:
# ---------------
#
# 0
#
###################################################################################################
#
# Usage example:
# -------------
#
# drive-list | zenity --progress --pulsate --auto-close --width=700 \
#                     --title="Listing selected remote files/folders" &
#
### Passing zenity process ID & drive-menu process ID to manage zenity cancel action
# zenity_pid=${!}
# parent_pgid=$(ps -C drive-menu -o pid=)
# zenity-cancel $parent_pgid $zenity_pid
#
###################################################################################################
# Listing all descendants of PGID, not only children
# Most credits go to @Graeme from http://unix.stackexchange.com/questions/124127/kill-all-descendant-processes
function list-descendants ()
{
        local children=$(ps -o pid= --ppid "$1")

        for pid in $children
        do
                list-descendants "$pid"
        done

        echo "$children"
}

if [[ $LOG_ZENITY_CANCEL == ON ]]; then
        # Getting the last existing file descriptor of ~/.drive-google/logs/drive-google.log
        fd=$(ls -al /proc/$$/fd | grep ~/.drive-google/logs/drive-google.log | sed -E 's|^.* ([0-9]+) -> .*$|\1|g' | sort -V | tail -n 1)

        # Case where fd is unset, i.e the file ~/.drive-google/logs/drive-google.log has not yet been opened
        if [[ -z $fd ]]; then
                lowest_unused_fd () 
                {
                        local fd=0
                        while [ -e /proc/$$/fd/${fd} ]; do
                                fd=$((fd+1))
                        done
                        echo $fd
                }
                fd=$(lowest_unused_fd)

                # Opening ~/.drive-google/logs/drive-google.log as file descriptor $fd for appending
                eval "exec $fd>> ~/.drive-google/logs/drive-google.log"
        fi

        # Writing the trace output generated when set -x is enabled to file descriptor $fd 
        eval "BASH_XTRACEFD=$fd"
        # Logging line numbers - We could also use ${0} for ${BASH_SOURCE}
        BASH_SOURCE_BASENAME=$(basename ${BASH_SOURCE})
        export PS4='${BASH_SOURCE_BASENAME}.${LINENO}+ '
        # Expanding all variables and prints the full commands before output of the command
        set -x
fi

# get firstly created parent group process id, which is running all children
parent_pgid=$1

# get zenity process id
zenity_pid=$2

# loop to check that progress dialog has not been cancelled
while [ "$zenity_pid" != "" ]
do
        # check if zenity PID is still there (dialog box still open)
        zenity_pid=$(ps h -o pid --pid ${zenity_pid} | xargs)

        # sleep for 1 second
        sleep 1
done

# Getting PIDs of all running children processes
children_pids=$(pgrep -d ' ' -P ${parent_pgid})
# Getting PID of current script
current_pid=$(ps -C zenity-cancel -o pid=)

# if some running tasks are still there, kill the whole group of process children & their descendants except their creator
if [[ "${children_pids}" != "" ]]; then
        descendants_list=()
        readarray -t descendants_list < <(list-descendants $parent_pgid)

        for descendant_pid in "${descendants_list[@]}"
        do
                # Killing all $parent_pgid's descendants, except for:
                # - the current script which will die naturally
                # - the parent script which should not be killed
                if [[ (-n "$descendant_pid") && ($descendant_pid -ne $current_pid) && ($descendant_pid -ne $parent_pgid) ]]; then
                        descendant_name=$(ps -q $descendant_pid -o comm=)
                        kill $descendant_pid 2>/dev/null
                fi
        done
fi

exit 0