#!/bin/bash # Edit iothrottle.sh - not iothrottle : <<=cut =pod =head1 NAME iothrottle - Limit IO to a given speed =head1 SYNOPSIS B [-i read-speed] [-o write-speed] I =head1 DESCRIPTION B limits B(2) and B(2) to a given speed. =head1 OPTIONS =over 4 =item B<-i> I Throttle B(2) to I bytes per second. To I you can append k, K, m, M, g, G to multiply by 1000, 1024, 1000000, 1048576 respectively. =item B<--io> I Shorthand for B<-i> I B<-o> I =item B<-o> I Throttle B(2) to I bytes per second. To I you can append k, K, m, M, g, G to multiply by 1000, 1024, 1000000, 1048576 respectively. =back =head1 EXAMPLE Copy mydir at 1MB/s: iothrottle -i 1M cp -a mydir/ /other/filesystem/ =head1 LIMITATIONS B intercepts calls to B(2) and B(2). If too much is read/written it inserts a pause for each call. This means the speed can go over the limit for a single call. Thus if the limit is 400 bytes/sec, but the call moves 4096 bytes, there will be a pause of 10 secs. If the program spawns processes, each child will get the limit. In other words: two children each with a limit of 1M may produce 2MB/s. Not all programs use B(2) and B(2) for I/O, so B tries to intercept other relevant calls, too. Tested: curl, wget, ssh, ffmpeg, cat, cp These programs use other methods: cp (to same filesystem) Statically linked programs will also not work. File a bug report when you find programs that fail. =head1 BUGS File bugs at: https://git.data.coop/tange/tangetools/issues =head1 ENVIRONMENT VARIABLES =over 9 =item $IOTHROTTLE_DEBUG=1 Turn on debugging. =back =head1 AUTHOR Copyright (C) 2024 Ole Tange, http://ole.tange.dk and Free Software Foundation, Inc. =head1 LICENSE Copyright (C) 2012 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or at your option any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . =head1 DEPENDENCIES B uses B. =head1 SEE ALSO B, B =cut _hex() { # hex encoded iothrottle.so local hex=dummy echo $hex } _hex_to_bin() { LC_ALL=C awk '{for (i=1; i<=length($0); i+=2) printf "%c", strtonum("0x" substr($0, i, 2))}' } _iothrottle.so() { local iothrottleso=$(mktemp -t iotrottle.XXXXX) _hex | _hex_to_bin > "$iothrottleso" echo "$iothrottleso" } # Default values for input and output limits INPUT_LIMIT="" OUTPUT_LIMIT="" # Parse command-line arguments while [[ $# -gt 0 ]]; do case "$1" in -i) INPUT_LIMIT="$2" shift 2 ;; -o) OUTPUT_LIMIT="$2" shift 2 ;; --io) INPUT_LIMIT="$2" OUTPUT_LIMIT="$2" shift 2 ;; *) break ;; esac done # Convert limits to bytes convert_to_bytes() { local value="$1" if [[ "$value" =~ ^[0-9]+K$ ]]; then value=$(( ${value%K*} * 1024 )) fi if [[ "$value" =~ ^[0-9]+k$ ]]; then value=$(( ${value%k*} * 1000 )) fi if [[ "$value" =~ ^[0-9]+M$ ]]; then value=$(( ${value%M*} * 1024 * 1024 )) fi if [[ "$value" =~ ^[0-9]+m$ ]]; then value=$(( ${value%m*} * 1000 * 1000 )) fi echo "$value" } IOTHROTTLE_READ=$(convert_to_bytes "$INPUT_LIMIT") IOTHROTTLE_WRITE=$(convert_to_bytes "$OUTPUT_LIMIT") # Export environment variables export IOTHROTTLE_READ=${IOTHROTTLE_READ:-0} export IOTHROTTLE_WRITE=${IOTHROTTLE_WRITE:-0} # Preload the library and execute the remaining command _so=$(_iothrottle.so) if [ IOTHROTTLE_DEBUG = 1 ] ; then echo LD_PRELOAD=$_so LD_PRELOAD=$_so "$@" else cleanup() { # if parent is dead: remove tmpfile ppid=$1 while kill -0 $ppid 2>/dev/null; do sleep 1; done rm $_so } cleanup $$ & LD_PRELOAD=$_so "$@" fi