1# bash completion for ethtool(8) -*- shell-script -*- 2# shellcheck shell=bash disable=SC2207 3 4# Complete a word representing a set of characters. 5# @param $@ chars Characters which may be present in completed set. 6_ethtool_compgen_letterset() 7{ 8 local char 9 for char; do 10 case "$cur" in 11 *"$char"*) 12 # $cur already contains $char 13 ;; 14 *) 15 COMPREPLY+=( "$cur$char" ) 16 ;; 17 esac 18 done 19} 20 21# Generate completions for words matched case-insensitively 22# @param $@ choices Completion choices. 23_ethtool_compgen_nocase() 24{ 25 local reset 26 reset=$( shopt -p nocasematch ) 27 shopt -s nocasematch 28 29 local choice 30 for choice; do 31 case "$choice" in 32 "$cur"*) COMPREPLY+=( "$choice" ) ;; 33 esac 34 done 35 36 $reset 37} 38 39# Gets names from a section of ethtool output. 40# @param $1 section_bre POSIX BRE matching section heading (without : at end). 41# @param $@ ethtool arguments 42_ethtool_get_names_in_section() 43{ 44 local section_bre="$1" 45 shift 46 47 PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \ 48 ethtool "$@" 2>/dev/null | 49 command sed -n " 50# Line is section heading iff it ends with : 51# From requested section heading to next section heading 52/^$section_bre:$/,/:$/ { 53 # If line is section heading, ignore it 54 /:$/d 55 # Remove value and separator, if present 56 s/[[:space:]]*:.*// 57 # Remove leading space, if present 58 s/^[[:space:]]*// 59 # Print the line 60 p 61}" 62} 63 64# Complete an RSS Context ID 65_ethtool_context() 66{ 67 COMPREPLY=( 68 $(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \ 69 ethtool --show-nfc "${words[2]}" 2>/dev/null | 70 command sed -n 's/^[[:space:]]*RSS Context ID:[[:space:]]*\([0-9]*\)$/\1/p' | 71 sort -u) ) 72} 73 74# Complete a network flow traffic type 75# Available OPTIONS: 76# --hash Complete only types suitable for rx hashing 77_ethtool_flow_type() 78{ 79 local types='ah4 ah6 esp4 esp6 ether sctp4 sctp6 tcp4 tcp6 udp4 udp6' 80 if [ "${1-}" != --hash ]; then 81 types="$types ip4 ip6" 82 else 83 types="gtpc4 gtpc6 gtpc4t gtpc6t gtpu4 gtpu6 gtpu4e gtpu6e gtpu4u gtpu6u gtpu4d gtpu6d $types" 84 fi 85 COMPREPLY=( $( compgen -W "$types" -- "$cur" ) ) 86} 87 88# Completion for ethtool --change 89_ethtool_change() 90{ 91 local -A settings=( 92 [advertise]=notseen 93 [autoneg]=notseen 94 [duplex]=notseen 95 [mdix]=notseen 96 [msglvl]=notseen 97 [port]=notseen 98 [phyad]=notseen 99 [speed]=notseen 100 [wol]=notseen 101 [xcvr]=notseen 102 [lanes]=notseen 103 ) 104 105 local -A msgtypes=( 106 [drv]=notseen 107 [hw]=notseen 108 [ifdown]=notseen 109 [ifup]=notseen 110 [intr]=notseen 111 [link]=notseen 112 [pktdata]=notseen 113 [probe]=notseen 114 [rx_err]=notseen 115 [rx_status]=notseen 116 [timer]=notseen 117 [tx_done]=notseen 118 [tx_err]=notseen 119 [tx_queued]=notseen 120 [wol]=notseen 121 ) 122 123 # Mark seen settings and msgtypes, and whether in msglvl sub-command 124 local in_msglvl= 125 local word 126 for word in "${words[@]:3:${#words[@]}-4}"; do 127 if [ "$in_msglvl" ] && [ "${msgtypes[$word]+set}" ]; then 128 msgtypes[$word]=seen 129 elif [ "${settings[$word]+set}" ]; then 130 settings[$word]=seen 131 if [ "$word" = msglvl ]; then 132 in_msglvl=1 133 else 134 in_msglvl= 135 fi 136 fi 137 done 138 139 if [ "$in_msglvl" ] && [ "${msgtypes[$prev]+set}" ]; then 140 # All msgtypes take an on/off argument 141 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 142 return 143 fi 144 145 case "$prev" in 146 advertise) 147 # Hex number 148 return ;; 149 autoneg) 150 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 151 return ;; 152 duplex) 153 COMPREPLY=( $( compgen -W 'half full' -- "$cur" ) ) 154 return ;; 155 mdix) 156 COMPREPLY=( $( compgen -W 'auto on off' -- "$cur" ) ) 157 return ;; 158 msglvl) 159 # Unsigned integer or msgtype 160 COMPREPLY=( $( compgen -W "${!msgtypes[*]}" -- "$cur" ) ) 161 return ;; 162 port) 163 COMPREPLY=( $( compgen -W 'aui bnc fibre mii tp' -- "$cur" ) ) 164 return ;; 165 phyad) 166 # Integer 167 return ;; 168 sopass) 169 _mac_addresses 170 return ;; 171 speed) 172 # Number 173 return ;; 174 wol) 175 # $cur is a set of wol type characters. 176 _ethtool_compgen_letterset p u m b a g s f d e 177 return ;; 178 xcvr) 179 COMPREPLY=( $( compgen -W 'internal external' -- "$cur" ) ) 180 return ;; 181 lanes) 182 # Number 183 return ;; 184 esac 185 186 local -a comp_words=() 187 188 # Add settings not seen to completions 189 local setting 190 for setting in "${!settings[@]}"; do 191 if [ "${settings[$setting]}" = notseen ]; then 192 comp_words+=( "$setting" ) 193 fi 194 done 195 196 # Add settings not seen to completions 197 if [ "$in_msglvl" ]; then 198 local msgtype 199 for msgtype in "${!msgtypes[@]}"; do 200 if [ "${msgtypes[$msgtype]}" = notseen ]; then 201 comp_words+=( "$msgtype" ) 202 fi 203 done 204 fi 205 206 COMPREPLY=( $( compgen -W "${comp_words[*]}" -- "$cur" ) ) 207} 208 209# Completion for ethtool --change-eeprom 210_ethtool_change_eeprom() 211{ 212 local -A settings=( 213 [length]=1 214 [magic]=1 215 [offset]=1 216 [value]=1 217 ) 218 219 if [ "${settings[$prev]+set}" ]; then 220 # All settings take an unsigned integer argument 221 return 222 fi 223 224 # Remove settings which have been seen 225 local word 226 for word in "${words[@]:3:${#words[@]}-4}"; do 227 unset "settings[$word]" 228 done 229 230 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 231} 232 233# Completion for ethtool --coalesce 234_ethtool_coalesce() 235{ 236 local -A settings=( 237 [adaptive-rx]=1 238 [adaptive-tx]=1 239 [pkt-rate-high]=1 240 [pkt-rate-low]=1 241 [rx-frames]=1 242 [rx-frames-high]=1 243 [rx-frames-irq]=1 244 [rx-frames-low]=1 245 [rx-usecs]=1 246 [rx-usecs-high]=1 247 [rx-usecs-irq]=1 248 [rx-usecs-low]=1 249 [sample-interval]=1 250 [stats-block-usecs]=1 251 [tx-frames]=1 252 [tx-frames-high]=1 253 [tx-frames-irq]=1 254 [tx-frames-low]=1 255 [tx-usecs]=1 256 [tx-usecs-high]=1 257 [tx-usecs-irq]=1 258 [tx-usecs-low]=1 259 [tx-aggr-max-bytes]=1 260 [tx-aggr-max-frames]=1 261 [tx-aggr-time-usecs]=1 262 ) 263 264 case "$prev" in 265 adaptive-rx|\ 266 adaptive-tx) 267 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 268 return ;; 269 esac 270 271 if [ "${settings[$prev]+set}" ]; then 272 # Unsigned integer 273 return 274 fi 275 276 # Remove settings which have been seen 277 local word 278 for word in "${words[@]:3:${#words[@]}-4}"; do 279 unset "settings[$word]" 280 done 281 282 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 283} 284 285# Completion for ethtool --config-nfc <devname> flow-type 286_ethtool_config_nfc_flow_type() 287{ 288 if [ "$cword" -eq 4 ]; then 289 _ethtool_flow_type --spec 290 return 291 fi 292 293 case "$prev" in 294 context) 295 _ethtool_context 296 return ;; 297 dst|\ 298 dst-mac|\ 299 src) 300 # TODO: Complete only local for dst and remote for src 301 _mac_addresses 302 return ;; 303 dst-ip) 304 # Note: RX classification, so dst is usually local 305 case "${words[4]}" in 306 *4) _ip_addresses -4 return ;; 307 *6) _ip_addresses -6 return ;; 308 esac 309 return ;; 310 src-ip) 311 # Note: RX classification, so src is usually remote 312 # TODO: Remote IP addresses (ARP cache + /etc/hosts + ?) 313 return ;; 314 m|\ 315 *-mask) 316 # MAC, IP, or integer bitmask 317 return ;; 318 esac 319 320 local -A settings=( 321 [action]=1 322 [context]=1 323 [loc]=1 324 [queue]=1 325 [vf]=1 326 ) 327 328 if [ "${settings[$prev]+set}" ]; then 329 # Integer 330 return 331 fi 332 333 case "${words[4]}" in 334 ah4|\ 335 esp4) 336 local -A fields=( 337 [dst-ip]=1 338 [dst-mac]=1 339 [spi]=1 340 [src-ip]=1 341 [tos]=1 342 [user-def]=1 343 [vlan-etype]=1 344 [vlan]=1 345 ) 346 ;; 347 ah6|\ 348 esp6) 349 local -A fields=( 350 [dst-ip]=1 351 [dst-mac]=1 352 [spi]=1 353 [src-ip]=1 354 [tclass]=1 355 [user-def]=1 356 [vlan-etype]=1 357 [vlan]=1 358 ) 359 ;; 360 ether) 361 local -A fields=( 362 [dst]=1 363 [proto]=1 364 [src]=1 365 [user-def]=1 366 [vlan-etype]=1 367 [vlan]=1 368 ) 369 ;; 370 ip4) 371 local -A fields=( 372 [dst-ip]=1 373 [dst-mac]=1 374 [dst-port]=1 375 [l4data]=1 376 [l4proto]=1 377 [spi]=1 378 [src-ip]=1 379 [src-port]=1 380 [tos]=1 381 [user-def]=1 382 [vlan-etype]=1 383 [vlan]=1 384 ) 385 ;; 386 ip6) 387 local -A fields=( 388 [dst-ip]=1 389 [dst-mac]=1 390 [dst-port]=1 391 [l4data]=1 392 [l4proto]=1 393 [spi]=1 394 [src-ip]=1 395 [src-port]=1 396 [tclass]=1 397 [user-def]=1 398 [vlan-etype]=1 399 [vlan]=1 400 ) 401 ;; 402 sctp4|\ 403 tcp4|\ 404 udp4) 405 local -A fields=( 406 [dst-ip]=1 407 [dst-mac]=1 408 [dst-port]=1 409 [src-ip]=1 410 [src-port]=1 411 [tos]=1 412 [user-def]=1 413 [vlan-etype]=1 414 [vlan]=1 415 ) 416 ;; 417 sctp6|\ 418 tcp6|\ 419 udp6) 420 local -A fields=( 421 [dst-ip]=1 422 [dst-mac]=1 423 [dst-port]=1 424 [src-ip]=1 425 [src-port]=1 426 [tclass]=1 427 [user-def]=1 428 [vlan-etype]=1 429 [vlan]=1 430 ) 431 ;; 432 *) 433 return ;; 434 esac 435 436 if [ "${fields[$prev]+set}" ]; then 437 # Integer 438 return 439 fi 440 441 # If the previous 2 words were a field+value, suggest a mask 442 local mask= 443 if [ "${fields[${words[$cword-2]}]+set}" ]; then 444 mask="m ${words[$cword-2]}-mask" 445 fi 446 447 # Remove fields and settings which have been seen 448 local word 449 for word in "${words[@]:5:${#words[@]}-6}"; do 450 unset "fields[$word]" "settings[$word]" 451 done 452 453 # Remove mutually-exclusive options 454 if ! [ "${settings[action]+set}" ]; then 455 unset 'settings[queue]' 'settings[vf]' 456 fi 457 if ! [ "${settings[queue]+set}" ]; then 458 unset 'settings[action]' 459 fi 460 if ! [ "${settings[vf]+set}" ]; then 461 unset 'settings[action]' 462 fi 463 464 COMPREPLY=( $( compgen -W "$mask ${!fields[*]} ${!settings[*]}" -- "$cur" ) ) 465} 466 467# Completion for ethtool --config-nfc 468_ethtool_config_nfc() 469{ 470 if [ "$cword" -eq 3 ]; then 471 COMPREPLY=( $( compgen -W 'delete flow-type rx-flow-hash' -- "$cur" ) ) 472 return 473 fi 474 475 case "${words[3]}" in 476 delete) 477 # Unsigned integer 478 return ;; 479 flow-type) 480 _ethtool_config_nfc_flow_type 481 return ;; 482 rx-flow-hash) 483 case "$cword" in 484 4) 485 _ethtool_flow_type --hash 486 return ;; 487 5) 488 _ethtool_compgen_letterset m v t s d f n r e 489 return ;; 490 6) 491 COMPREPLY=( $( compgen -W context -- "$cur" ) ) 492 return ;; 493 7) 494 _ethtool_context 495 return ;; 496 esac 497 return ;; 498 esac 499} 500 501# Completion for ethtool --eeprom-dump 502_ethtool_eeprom_dump() 503{ 504 local -A settings=( 505 [length]=1 506 [offset]=1 507 [raw]=1 508 ) 509 510 if [ "$prev" = raw ]; then 511 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 512 return 513 fi 514 515 if [ "${settings[$prev]+set}" ]; then 516 # Unsigned integer argument 517 return 518 fi 519 520 # Remove settings which have been seen 521 local word 522 for word in "${words[@]:3:${#words[@]}-4}"; do 523 unset "settings[$word]" 524 done 525 526 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 527} 528 529# Completion for ethtool --features 530_ethtool_features() 531{ 532 local -A abbreviations=( 533 [generic-receive-offload]=gro 534 [generic-segmentation-offload]=gso 535 [large-receive-offload]=lro 536 [ntuple-filters]=ntuple 537 [receive-hashing]=rxhash 538 [rx-checksumming]=rx 539 [rx-vlan-offload]=rxvlan 540 [scatter-gather]=sg 541 [tcp-segmentation-offload]=tso 542 [tx-checksumming]=tx 543 [tx-vlan-offload]=txvlan 544 [udp-fragmentation-offload]=ufo 545 ) 546 547 local -A features=() 548 local feature status fixed 549 # shellcheck disable=SC2034 550 while read -r feature status fixed; do 551 if [ -z "$feature" ]; then 552 # Ignore blank line from empty expansion in here-document 553 continue 554 fi 555 556 if [ "$feature" = Features ]; then 557 # Ignore heading 558 continue 559 fi 560 561 if [ "$fixed" = '[fixed]' ]; then 562 # Fixed features can't be changed 563 continue 564 fi 565 566 feature=${feature%:} 567 if [ "${abbreviations[$feature]+set}" ]; then 568 features[${abbreviations[$feature]}]=1 569 else 570 features[$feature]=1 571 fi 572 done <<ETHTOOL_FEATURES 573$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \ 574 ethtool --show-features "${words[2]}" 2>/dev/null) 575ETHTOOL_FEATURES 576 577 if [ "${features[$prev]+set}" ]; then 578 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 579 return 580 fi 581 582 # Remove features which have been seen 583 local word 584 for word in "${words[@]:3:${#words[@]}-4}"; do 585 unset "features[$word]" 586 done 587 588 COMPREPLY=( $( compgen -W "${!features[*]}" -- "$cur" ) ) 589} 590 591# Complete the current word as a kernel firmware file (for request_firmware) 592# See https://www.kernel.org/doc/html/latest/driver-api/firmware/core.html 593_ethtool_firmware() 594{ 595 local -a firmware_paths=( 596 /lib/firmware/updates/ 597 /lib/firmware/ 598 ) 599 600 local release 601 if release=$( uname -r 2>/dev/null ); then 602 firmware_paths+=( 603 "/lib/firmware/updates/$release/" 604 "/lib/firmware/$release/" 605 ) 606 fi 607 608 local fw_path_para 609 if fw_path_para=$( cat /sys/module/firmware_class/parameters/path 2>/dev/null ) \ 610 && [ -n "$fw_path_para" ]; then 611 firmware_paths+=( "$fw_path_para" ) 612 fi 613 614 local -A firmware_files=() 615 616 local firmware_path 617 for firmware_path in "${firmware_paths[@]}"; do 618 local firmware_file 619 for firmware_file in "$firmware_path"*; do 620 if [ -f "$firmware_file" ]; then 621 firmware_files[${firmware_file##*/}]=1 622 fi 623 done 624 done 625 626 local IFS=' 627' 628 COMPREPLY=( $( compgen -W "${!firmware_files[*]}" -- "$cur" ) ) 629} 630 631# Completion for ethtool --flash 632_ethtool_flash() 633{ 634 if [ "$cword" -eq 3 ]; then 635 _ethtool_firmware 636 return 637 fi 638} 639 640# Completion for ethtool --get-dump 641_ethtool_get_dump() 642{ 643 case "$cword" in 644 3) 645 COMPREPLY=( $( compgen -W data -- "$cur" ) ) 646 return ;; 647 4) 648 # Output filename 649 local IFS=' 650' 651 COMPREPLY=( $( compgen -f -- "$cur" ) ) 652 return ;; 653 esac 654} 655 656# Completion for ethtool --get-phy-tunable 657_ethtool_get_phy_tunable() 658{ 659 if [ "$cword" -eq 3 ]; then 660 COMPREPLY=( $( compgen -W downshift -- "$cur" ) ) 661 return 662 fi 663} 664 665# Completion for ethtool --module-info 666_ethtool_module_info() 667{ 668 local -A settings=( 669 [hex]=1 670 [length]=1 671 [offset]=1 672 [raw]=1 673 ) 674 675 case "$prev" in 676 hex|\ 677 raw) 678 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 679 return ;; 680 esac 681 682 if [ "${settings[$prev]+set}" ]; then 683 # Unsigned integer argument 684 return 685 fi 686 687 # Remove settings which have been seen 688 local word 689 for word in "${words[@]:3:${#words[@]}-4}"; do 690 unset "settings[$word]" 691 done 692 693 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 694} 695 696# Completion for ethtool --pause 697_ethtool_pause() 698{ 699 local -A settings=( 700 [autoneg]=1 701 [rx]=1 702 [tx]=1 703 ) 704 705 if [ "${settings[$prev]+set}" ]; then 706 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 707 return 708 fi 709 710 # Remove settings which have been seen 711 local word 712 for word in "${words[@]:3:${#words[@]}-4}"; do 713 unset "settings[$word]" 714 done 715 716 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 717} 718 719# Completion for ethtool --per-queue 720_ethtool_per_queue() 721{ 722 local -a subcommands=( 723 --coalesce 724 --show-coalesce 725 ) 726 727 if [ "$cword" -eq 3 ]; then 728 COMPREPLY=( $( compgen -W "queue_mask ${subcommands[*]}" -- "$cur" ) ) 729 return 730 fi 731 732 local sc_start=3 733 if [ "${words[3]}" = queue_mask ] ; then 734 case "$cword" in 735 4) 736 # Hex number 737 return ;; 738 5) 739 COMPREPLY=( $( compgen -W "${subcommands[*]}" -- "$cur" ) ) 740 return ;; 741 esac 742 743 sc_start=5 744 fi 745 746 case "${words[$sc_start]}" in 747 --coalesce) 748 # Remove --per-queue args to match normal --coalesce invocation 749 local words=( 750 "${words[0]}" 751 --coalesce 752 "${words[2]}" 753 "${words[@]:$sc_start+1:${#words[@]}-$sc_start-1}" 754 ) 755 _ethtool_coalesce 756 return ;; 757 --show-coalesce) 758 # No args 759 return ;; 760 esac 761} 762 763# Completion for ethtool --register-dump 764_ethtool_register_dump() 765{ 766 local -A settings=( 767 [file]=1 768 [hex]=1 769 [raw]=1 770 ) 771 772 case "$prev" in 773 hex|\ 774 raw) 775 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 776 return ;; 777 file) 778 local IFS=' 779' 780 COMPREPLY=( $( compgen -f -- "$cur" ) ) 781 return ;; 782 esac 783 784 # Remove settings which have been seen 785 local word 786 for word in "${words[@]:3:${#words[@]}-4}"; do 787 unset "settings[$word]" 788 done 789 790 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 791} 792 793# Completion for ethtool --reset 794_ethtool_reset() 795{ 796 if [ "$prev" = flags ]; then 797 # Unsigned integer 798 return 799 fi 800 801 local -A flag_names=( 802 [ap]=1 803 [dma]=1 804 [filter]=1 805 [irq]=1 806 [mac]=1 807 [mgmt]=1 808 [offload]=1 809 [phy]=1 810 [ram]=1 811 ) 812 813 local -A all_flag_names=() 814 local flag_name 815 for flag_name in "${!flag_names[@]}"; do 816 all_flag_names[$flag_name]=1 817 all_flag_names[$flag_name-shared]=1 818 done 819 820 # Remove all_flag_names which have been seen 821 local any_dedicated= 822 local word 823 for word in "${words[@]:3:${#words[@]}-4}"; do 824 case "$word" in 825 all) 826 # Flags are always additive. 827 # Nothing to add after "all". 828 return ;; 829 dedicated) 830 any_dedicated=1 831 # "dedicated" sets all non-shared flags 832 for flag_name in "${!flag_names[@]}"; do 833 unset "all_flag_names[$flag_name]" 834 done 835 continue ;; 836 esac 837 838 if [ "${flag_names[$word]+set}" ]; then 839 any_dedicated=1 840 fi 841 842 unset "all_flag_names[$word]" 843 done 844 845 COMPREPLY=( $( compgen -W "${!all_flag_names[*]}" -- "$cur" ) ) 846 847 # Although it is permitted to mix named and un-named flags or duplicate 848 # flags with "all" or "dedicated", it's not likely intentional. 849 # Reconsider if a real use-case (or good consistency argument) is found. 850 if [ "$cword" -eq 3 ]; then 851 COMPREPLY+=( all dedicated flags ) 852 elif [ -z "$any_dedicated" ]; then 853 COMPREPLY+=( dedicated ) 854 fi 855} 856 857# Completion for ethtool --rxfh 858_ethtool_rxfh() 859{ 860 local -A settings=( 861 [context]=1 862 [default]=1 863 [delete]=1 864 [equal]=1 865 [hfunc]=1 866 [hkey]=1 867 [weight]=1 868 ) 869 870 case "$prev" in 871 context) 872 _ethtool_context 873 # "new" to create a new context 874 COMPREPLY+=( new ) 875 return ;; 876 equal) 877 # Positive integer 878 return ;; 879 hfunc) 880 # Complete available RSS hash functions 881 COMPREPLY=( 882 $(_ethtool_get_names_in_section 'RSS hash function' \ 883 --show-rxfh "${words[2]}") 884 ) 885 return ;; 886 hkey) 887 # Pairs of hex digits separated by : 888 return ;; 889 weight) 890 # Non-negative integer 891 return ;; 892 esac 893 894 local word 895 for word in "${words[@]:3:${#words[@]}-4}"; do 896 # Remove settings which have been seen 897 unset "settings[$word]" 898 899 # Remove settings which are mutually-exclusive with seen settings 900 case "$word" in 901 context) 902 unset 'settings[default]' 903 ;; 904 default) 905 unset \ 906 'settings[context]' \ 907 'settings[delete]' \ 908 'settings[equal]' \ 909 'settings[weight]' 910 ;; 911 delete) 912 unset \ 913 'settings[default]' \ 914 'settings[equal]' \ 915 'settings[hkey]' \ 916 'settings[weight]' 917 ;; 918 equal) 919 unset \ 920 'settings[default]' \ 921 'settings[delete]' \ 922 'settings[weight]' 923 ;; 924 hkey) 925 unset 'settings[delete]' 926 ;; 927 weight) 928 unset \ 929 'settings[default]' \ 930 'settings[delete]' \ 931 'settings[equal]' 932 ;; 933 esac 934 done 935 936 937 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 938} 939 940# Completion for ethtool --set-channels 941_ethtool_set_channels() 942{ 943 local -A settings=( 944 [combined]=1 945 [other]=1 946 [rx]=1 947 [tx]=1 948 ) 949 950 if [ "${settings[$prev]+set}" ]; then 951 # Unsigned integer argument 952 return 953 fi 954 955 # Remove settings which have been seen 956 local word 957 for word in "${words[@]:3:${#words[@]}-4}"; do 958 unset "settings[$word]" 959 done 960 961 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 962} 963 964# Completion for ethtool --set-eee 965_ethtool_set_eee() 966{ 967 local -A settings=( 968 [advertise]=1 969 [eee]=1 970 [tx-lpi]=1 971 [tx-timer]=1 972 ) 973 974 case "$prev" in 975 advertise|\ 976 tx-timer) 977 # Unsigned integer 978 return ;; 979 eee|\ 980 tx-lpi) 981 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 982 return ;; 983 esac 984 985 # Remove settings which have been seen 986 local word 987 for word in "${words[@]:3:${#words[@]}-4}"; do 988 unset "settings[$word]" 989 done 990 991 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 992} 993 994# Completion for ethtool --set-fec 995_ethtool_set_fec() 996{ 997 if [ "$cword" -eq 3 ]; then 998 COMPREPLY=( $( compgen -W encoding -- "$cur" ) ) 999 return 1000 fi 1001 1002 local -A modes=( 1003 [auto]=auto 1004 [rs]=RS 1005 [off]=off 1006 [baser]=BaseR 1007 ) 1008 1009 # Remove modes which have been seen 1010 local word 1011 for word in "${words[@]:3:${#words[@]}-4}"; do 1012 # ethtool recognizes modes case-insensitively 1013 unset "modes[${word,,}]" 1014 done 1015 1016 _ethtool_compgen_nocase "${modes[@]}" 1017} 1018 1019# Completion for ethtool --set-phy-tunable 1020_ethtool_set_phy_tunable() 1021{ 1022 case "$cword" in 1023 3) 1024 COMPREPLY=( $( compgen -W downshift -- "$cur" ) ) 1025 return ;; 1026 4) 1027 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 1028 return ;; 1029 5) 1030 COMPREPLY=( $( compgen -W count -- "$cur" ) ) 1031 return ;; 1032 esac 1033} 1034 1035# Completion for ethtool --set-priv-flags 1036_ethtool_set_priv_flags() 1037{ 1038 if [ $(( cword % 2 )) -eq 0 ]; then 1039 COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) ) 1040 return 1041 fi 1042 1043 # Get available private flags 1044 local -A flags=() 1045 local flag 1046 while IFS= read -r flag; do 1047 # Ignore blank line from empty here-document 1048 if [ -n "$flag" ]; then 1049 flags[$flag]=1 1050 fi 1051 done <<ETHTOOL_PRIV_FLAGS 1052$(_ethtool_get_names_in_section \ 1053 'Private flags for [[:graph:]]*' --show-priv-flags "${words[2]}") 1054ETHTOOL_PRIV_FLAGS 1055 1056 # Remove flags which have been seen 1057 local word 1058 for word in "${words[@]:3:${#words[@]}-4}"; do 1059 unset "flags[$word]" 1060 done 1061 1062 COMPREPLY=( $( compgen -W "${!flags[*]}" -- "$cur" ) ) 1063} 1064 1065# Completion for ethtool --set-ring 1066_ethtool_set_ring() 1067{ 1068 local -A settings=( 1069 [rx-jumbo]=1 1070 [rx-mini]=1 1071 [rx]=1 1072 [tx]=1 1073 ) 1074 1075 if [ "${settings[$prev]+set}" ]; then 1076 # Unsigned integer argument 1077 return 1078 fi 1079 1080 # Remove settings which have been seen 1081 local word 1082 for word in "${words[@]:3:${#words[@]}-4}"; do 1083 unset "settings[$word]" 1084 done 1085 1086 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 1087} 1088 1089# Completion for ethtool --show-nfc 1090_ethtool_show_nfc() 1091{ 1092 if [ "$cword" -eq 3 ]; then 1093 COMPREPLY=( $( compgen -W 'rule rx-flow-hash' -- "$cur" ) ) 1094 return 1095 fi 1096 1097 case "${words[3]}" in 1098 rule) 1099 if [ "$cword" -eq 4 ]; then 1100 COMPREPLY=( 1101 $(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \ 1102 ethtool --show-nfc "${words[2]}" 2>/dev/null | 1103 command sed -n 's/^Filter:[[:space:]]*\([0-9]*\)$/\1/p') 1104 ) 1105 fi 1106 return ;; 1107 rx-flow-hash) 1108 case "$cword" in 1109 4) 1110 _ethtool_flow_type --hash 1111 return ;; 1112 5) 1113 COMPREPLY=( $( compgen -W context -- "$cur" ) ) 1114 return ;; 1115 6) 1116 _ethtool_context 1117 return ;; 1118 esac 1119 ;; 1120 esac 1121} 1122 1123# Completion for ethtool --show-rxfh 1124_ethtool_show_rxfh() 1125{ 1126 case "$cword" in 1127 3) 1128 COMPREPLY=( $( compgen -W context -- "$cur" ) ) 1129 return ;; 1130 4) 1131 _ethtool_context 1132 return ;; 1133 esac 1134} 1135 1136# Completion for ethtool --test 1137_ethtool_test() 1138{ 1139 if [ "$cword" -eq 3 ]; then 1140 COMPREPLY=( $( compgen -W 'external_lb offline online' -- "$cur" ) ) 1141 return 1142 fi 1143} 1144 1145# Completion for ethtool --set-module 1146_ethtool_set_module() 1147{ 1148 local -A settings=( 1149 [power-mode-policy]=1 1150 ) 1151 1152 case "$prev" in 1153 power-mode-policy) 1154 COMPREPLY=( $( compgen -W 'high auto' -- "$cur" ) ) 1155 return ;; 1156 esac 1157 1158 # Remove settings which have been seen 1159 local word 1160 for word in "${words[@]:3:${#words[@]}-4}"; do 1161 unset "settings[$word]" 1162 done 1163 1164 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 1165} 1166 1167# Completion for ethtool --flash-module-firmware 1168_ethtool_flash_module_firmware() 1169{ 1170 local -A settings=( 1171 [file]=1 1172 [pass]=1 1173 ) 1174 1175 case "$prev" in 1176 file) 1177 _ethtool_firmware 1178 return ;; 1179 pass) 1180 # Number 1181 return ;; 1182 esac 1183 1184 # Remove settings which have been seen 1185 local word 1186 for word in "${words[@]:3:${#words[@]}-4}"; do 1187 unset "settings[$word]" 1188 done 1189 1190 COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) ) 1191} 1192 1193# Complete any ethtool command 1194_ethtool() 1195{ 1196 local cur prev words cword 1197 _init_completion || return 1198 1199 # Per "Contributing to bash-completion", complete non-duplicate long opts 1200 local -A suggested_funcs=( 1201 [--change-eeprom]=change_eeprom 1202 [--change]=change 1203 [--coalesce]=coalesce 1204 [--config-nfc]=config_nfc 1205 [--driver]=devname 1206 [--dump-module-eeprom]=module_info 1207 [--eeprom-dump]=eeprom_dump 1208 [--features]=features 1209 [--flash]=flash 1210 [--get-dump]=get_dump 1211 [--get-phy-tunable]=get_phy_tunable 1212 [--identify]=devname 1213 [--module-info]=module_info 1214 [--negotiate]=devname 1215 [--offload]=features 1216 [--pause]=pause 1217 [--per-queue]=per_queue 1218 [--phy-statistics]=devname 1219 [--register-dump]=register_dump 1220 [--reset]=reset 1221 [--set-channels]=set_channels 1222 [--set-dump]=devname 1223 [--set-eee]=set_eee 1224 [--set-fec]=set_fec 1225 [--set-phy-tunable]=set_phy_tunable 1226 [--set-priv-flags]=set_priv_flags 1227 [--set-ring]=set_ring 1228 [--set-rxfh-indir]=rxfh 1229 [--show-channels]=devname 1230 [--show-coalesce]=devname 1231 [--show-eee]=devname 1232 [--show-features]=devname 1233 [--show-fec]=devname 1234 [--show-nfc]=show_nfc 1235 [--show-offload]=devname 1236 [--show-pause]=devname 1237 [--show-permaddr]=devname 1238 [--show-priv-flags]=devname 1239 [--show-ring]=devname 1240 [--show-rxfh]=show_rxfh 1241 [--show-time-stamping]=devname 1242 [--statistics]=devname 1243 [--test]=test 1244 [--set-module]=set_module 1245 [--show-module]=devname 1246 [--flash-module-firmware]=flash_module_firmware 1247 ) 1248 local -A other_funcs=( 1249 [--config-ntuple]=config_nfc 1250 [--rxfh]=rxfh 1251 [--show-ntuple]=show_nfc 1252 [--show-rxfh-indir]=devname 1253 [-A]=pause 1254 [-C]=coalesce 1255 [-E]=change_eeprom 1256 [-G]=set_ring 1257 [-K]=features 1258 [-L]=set_channels 1259 [-N]=config_nfc 1260 [-P]=devname 1261 [-Q]=per_queue 1262 [-S]=devname 1263 [-T]=devname 1264 [-U]=config_nfc 1265 [-W]=devname 1266 [-X]=rxfh 1267 [-a]=devname 1268 [-c]=devname 1269 [-d]=register_dump 1270 [-e]=eeprom_dump 1271 [-f]=flash 1272 [-g]=devname 1273 [-i]=devname 1274 [-k]=devname 1275 [-l]=devname 1276 [-m]=module_info 1277 [-n]=show_nfc 1278 [-p]=devname 1279 [-r]=devname 1280 [-s]=change 1281 [-t]=test 1282 [-u]=show_nfc 1283 [-w]=get_dump 1284 [-x]=devname 1285 ) 1286 1287 if [ "$cword" -le 1 ]; then 1288 _available_interfaces 1289 COMPREPLY+=( 1290 $( compgen -W "--help --version ${!suggested_funcs[*]}" -- "$cur" ) 1291 ) 1292 return 1293 fi 1294 1295 local func=${suggested_funcs[${words[1]}]-${other_funcs[${words[1]}]-}} 1296 if [ "$func" ]; then 1297 # All sub-commands have devname as their first argument 1298 if [ "$cword" -eq 2 ]; then 1299 _available_interfaces 1300 return 1301 fi 1302 1303 if [ "$func" != devname ]; then 1304 "_ethtool_$func" 1305 fi 1306 fi 1307} && 1308complete -F _ethtool ethtool 1309 1310# ex: filetype=sh sts=8 sw=8 ts=8 noet 1311