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