1 #! /bin/sh 2 # SPDX-License-Identifier: GPL-2.0 3 # Copyright (c) 2020, Google LLC. All rights r 4 # Author: Saravana Kannan <saravanak@google.com 5 6 function help() { 7 cat << EOF 8 Usage: $(basename $0) [-c|-d|-m|-f] [filter op 9 10 This script needs to be run on the target devi 11 shell. 12 13 The script takes as input a list of one or mor 14 /sys/devices and then lists the probe dependen 15 parents) of these devices. It does a breadth f 16 chain, so the last entry in the output is clos 17 dependency chain. 18 19 By default it lists the full path to the devic 20 21 It also takes an optional modifier flag as the 22 what information is listed in the output. If t 23 not available, the device name is printed. 24 25 -c lists the compatible string of the dep 26 -d lists the driver name of the dependenc 27 -m lists the module name of the dependenc 28 -f list the firmware node path of the dep 29 -g list the dependencies as edges and nod 30 -t list the dependencies as edges for tso 31 32 The filter options provide a way to filter out 33 --allow-no-driver By default dependencie 34 attached are ignored. 35 device links to "class 36 when the consumer prob 37 dependency). If you wa 38 anyway, use this flag. 39 40 --exclude-devlinks Don't follow device li 41 dependencies. 42 43 --exclude-parents Don't follow parent de 44 dependencies. 45 46 EOF 47 } 48 49 function dev_to_detail() { 50 local i=0 51 while [ $i -lt ${#OUT_LIST[@]} ] 52 do 53 local C=${OUT_LIST[i]} 54 local S=${OUT_LIST[i+1]} 55 local D="'$(detail_chosen $C $ 56 if [ ! -z "$D" ] 57 then 58 # This weirdness is ne 59 # using the -t option. 60 printf '%05u\t%s\n' ${ 61 fi 62 i=$((i+2)) 63 done 64 } 65 66 function already_seen() { 67 local i=0 68 while [ $i -lt ${#OUT_LIST[@]} ] 69 do 70 if [ "$1" = "${OUT_LIST[$i]}" 71 then 72 # if-statement treats 73 return 0 74 fi 75 i=$(($i+2)) 76 done 77 78 # if-statement treats 1 (error) as fal 79 return 1 80 } 81 82 # Return 0 (no-error/true) if parent was added 83 function add_parent() { 84 85 if [ ${ALLOW_PARENTS} -eq 0 ] 86 then 87 return 1 88 fi 89 90 local CON=$1 91 # $CON could be a symlink path. So, we 92 # then go up one level to find the rea 93 local PARENT=$(realpath $CON/..) 94 95 while [ ! -e ${PARENT}/driver ] 96 do 97 if [ "$PARENT" = "/sys/devices 98 then 99 return 1 100 fi 101 PARENT=$(realpath $PARENT/..) 102 done 103 104 CONSUMERS+=($PARENT) 105 OUT_LIST+=(${CON} ${PARENT}) 106 return 0 107 } 108 109 # Return 0 (no-error/true) if one or more supp 110 function add_suppliers() { 111 local CON=$1 112 local RET=1 113 114 if [ ${ALLOW_DEVLINKS} -eq 0 ] 115 then 116 return 1 117 fi 118 119 SUPPLIER_LINKS=$(ls -1d $CON/supplier: 120 for SL in $SUPPLIER_LINKS; 121 do 122 SYNC_STATE=$(cat $SL/sync_stat 123 124 # sync_state_only links are pr 125 # They can also have cycles. S 126 if [ "$SYNC_STATE" != '0' ] 127 then 128 continue 129 fi 130 131 SUPPLIER=$(realpath $SL/suppli 132 133 if [ ! -e $SUPPLIER/driver -a 134 then 135 continue 136 fi 137 138 CONSUMERS+=($SUPPLIER) 139 OUT_LIST+=(${CON} ${SUPPLIER}) 140 RET=0 141 done 142 143 return $RET 144 } 145 146 function detail_compat() { 147 f=$1/of_node/compatible 148 if [ -e $f ] 149 then 150 echo -n $(cat $f) 151 else 152 echo -n $1 153 fi 154 } 155 156 function detail_module() { 157 f=$1/driver/module 158 if [ -e $f ] 159 then 160 echo -n $(basename $(realpath 161 else 162 echo -n $1 163 fi 164 } 165 166 function detail_driver() { 167 f=$1/driver 168 if [ -e $f ] 169 then 170 echo -n $(basename $(realpath 171 else 172 echo -n $1 173 fi 174 } 175 176 function detail_fwnode() { 177 f=$1/firmware_node 178 if [ ! -e $f ] 179 then 180 f=$1/of_node 181 fi 182 183 if [ -e $f ] 184 then 185 echo -n $(realpath $f) 186 else 187 echo -n $1 188 fi 189 } 190 191 function detail_graphviz() { 192 if [ "$2" != "ROOT" ] 193 then 194 echo -n "\"$(basename $2)\"->\ 195 else 196 echo -n "\"$(basename $1)\"" 197 fi 198 } 199 200 function detail_tsort() { 201 echo -n "\"$2\" \"$1\"" 202 } 203 204 function detail_device() { echo -n $1; } 205 206 alias detail=detail_device 207 ALLOW_NO_DRIVER=0 208 ALLOW_DEVLINKS=1 209 ALLOW_PARENTS=1 210 211 while [ $# -gt 0 ] 212 do 213 ARG=$1 214 case $ARG in 215 --help) 216 help 217 exit 0 218 ;; 219 -c) 220 alias detail=detail_co 221 ;; 222 -m) 223 alias detail=detail_mo 224 ;; 225 -d) 226 alias detail=detail_dr 227 ;; 228 -f) 229 alias detail=detail_fw 230 ;; 231 -g) 232 alias detail=detail_gr 233 ;; 234 -t) 235 alias detail=detail_ts 236 ;; 237 --allow-no-driver) 238 ALLOW_NO_DRIVER=1 239 ;; 240 --exclude-devlinks) 241 ALLOW_DEVLINKS=0 242 ;; 243 --exclude-parents) 244 ALLOW_PARENTS=0 245 ;; 246 *) 247 # Stop at the first ar 248 break 249 ;; 250 esac 251 shift 252 done 253 254 function detail_chosen() { 255 detail $1 $2 256 } 257 258 if [ $# -eq 0 ] 259 then 260 help 261 exit 1 262 fi 263 264 CONSUMERS=($@) 265 OUT_LIST=() 266 267 # Do a breadth first, non-recursive tracking o 268 # considered a "supplier" as a device can't pr 269 i=0 270 while [ $i -lt ${#CONSUMERS[@]} ] 271 do 272 CONSUMER=$(realpath ${CONSUMERS[$i]}) 273 i=$(($i+1)) 274 275 if already_seen ${CONSUMER} 276 then 277 continue 278 fi 279 280 # If this is not a device with a drive 281 # suppliers. 282 if [ ! -e ${CONSUMER}/driver -a ${ALLO 283 then 284 continue 285 fi 286 287 ROOT=1 288 289 # Add suppliers to CONSUMERS list and 290 # 291 # We don't need to worry about a cycle 292 # infinite loops. That's because the k 293 # device links unless it's a sync_stat 294 # sync_state_only device links inside 295 if add_suppliers ${CONSUMER} 296 then 297 ROOT=0 298 fi 299 300 if add_parent ${CONSUMER} 301 then 302 ROOT=0 303 fi 304 305 if [ $ROOT -eq 1 ] 306 then 307 OUT_LIST+=(${CONSUMER} "ROOT") 308 fi 309 done 310 311 # Can NOT combine sort and uniq using sort -su 312 # isn't really stable. 313 dev_to_detail | sort -k2 -k1 | uniq -f 1 | sor 314 315 exit 0
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.