#!/usr/bin/bash ########################################################################### # # # Linux pktcdvd Module Control Script # # # # Uses pktcdvd sysfs interface. # # # # Copyright (C) 2006 Thomas Maier # # # # May be copied or modified under the terms of the GNU General Public # # License. # # # # 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; # # # # 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. # ########################################################################### PKTCDVD_DIR="/sys/class/pktcdvd" PKTDEV_DIR="/dev/pktcdvd" usage() { echo "pktcdvd control script Version 1.0.0" >&2 echo "Copyright (C) 2006 Thomas Maier " >&2 echo "usage:" >&2 echo " # add new packet device for block device." >&2 echo " # a device node is created: /dev/pktcdvd/" >&2 echo " pktcdvd -a pktname blkdev" >&2 echo " # remove a packet device" >&2 echo " pktcdvd -r pktname|pktmajor:pktminor" >&2 echo " # show packet device stat infos" >&2 echo " pktcdvd -i pktname|pktmajor:pktminor" >&2 echo " # set write congestion marks for packet device" >&2 echo " pktcdvd -C pktname|pktmajor:pktminor on [off]" >&2 echo " # print write congestion marks for packet device" >&2 echo " pktcdvd -c pktname|pktmajor:pktminor" >&2 echo " # print device mapping" >&2 echo " pktcdvd -m" >&2 } exiterr() { [ -n "$1" ] && echo "error: $1" >&2 exit 1 } usage_error() { usage exiterr } # device file to device id (major:minor) dev_to_id() { if [[ "$1" == *:* ]] ; then echo "$1" return 0 elif [ -b "$1" ] ; then /bin/ls -l "$1" \ | awk '{print $5 ":" $6}' | tr -d ',' return 0 fi return 1 } # device file, device id or pktcdvd device name # to packet device id (major:minor) to_pktdev_id() { typeset name="$1" typeset devid="" if [ -b "$PKTDEV_DIR/$name" ] ; then devid="$(dev_to_id "$PKTDEV_DIR/$name")" else devid="$(dev_to_id "$name")" fi [ -z "$devid" ] && exiterr "can not get device id for $name" echo "$devid" } to_pkt_name() { typeset pktdev="$1" typeset pktdevid pktdevid="$(to_pktdev_id "$pktdev")" || exit 1 typeset pktname="$(awk '$2=="'"$pktdevid"'" {print $1}' "$PKTCDVD_DIR/device_map" )" [ -z "$pktname" ] && exiterr "device $pktdev is not an active pktcdvd device" echo "$pktname" } to_pkt_sdir() { typeset name name="$(to_pkt_name "$1")" || exit 1 echo "$PKTCDVD_DIR/$name" } check_root() { [ ! -w "$PKTCDVD_DIR/add" ] && exiterr "permission denied" } if [[ $# != 0 && ! -d "$PKTCDVD_DIR" ]] ; then exiterr "pktcdvd module not loaded or no sysfs available" fi case "$1" in -a) (( "$#" != 3 )) && usage_error pktname="$2" blkdev="$3" blkdevid="$(dev_to_id "$blkdev")" || exiterr "not a block device: $blkdev" pktdev="$PKTDEV_DIR/$pktname" m="$(grep " $blkdevid\$" "$PKTCDVD_DIR/device_map")" [ -n "$m" ] && exiterr "device $blkdev already mapped to: $m" check_root echo "$blkdevid" >"$PKTCDVD_DIR/add" || exiterr "unable to add new pktcdvd device" pktdevid="$(awk '$3=="'"$blkdevid"'" {print $2}' "$PKTCDVD_DIR/device_map" )" [ -z "$pktdevid" ] && exiterr "can not add new pktcdvd device" pktsysn="$(awk '$3=="'"$blkdevid"'" {print $1}' "$PKTCDVD_DIR/device_map" )" rm -f "$pktdev" "$PKTDEV_DIR/$pktsysn" mkdir -p "$PKTDEV_DIR" || exiterr major="$(echo "$pktdevid" | cut -f 1 -d ':')" minor="$(echo "$pktdevid" | cut -f 2 -d ':')" mknod "$PKTDEV_DIR/$pktsysn" b "$major" "$minor" \ || exiterr "failed to make device node "$PKTDEV_DIR/$pktsysn" for $major:$minor" chmod 644 "$PKTDEV_DIR/$pktsysn" # create hard link, so dev_to_id() can resolve it! [[ "$pktsysn" != "$pktname" ]] && ln -f "$PKTDEV_DIR/$pktsysn" "$pktdev" echo "ok: $pktdev ($pktsysn [$pktdevid] -> $blkdev [$blkdevid])" ;; -r) (( "$#" != 2 )) && usage_error pktdev="$2" pktdevid="$(to_pktdev_id "$pktdev")" || exit 1 pktsysn="$(awk '$2=="'"$pktdevid"'" {print $1}' "$PKTCDVD_DIR/device_map" )" [ -z "$pktsysn" ] && exiterr "device $pktdev is not an active pktcdvd device" check_root echo "$pktdevid" >"$PKTCDVD_DIR/remove" \ || exiterr "unable to remove pktcdvd device $pktdev ($pktdevid)" fgrep " $pktdevid " "$PKTCDVD_DIR/device_map" >/dev/null \ && exiterr "unable to remove pktcdvd device $pktdev ($pktdevid) or device busy" # use the inode number of $pktsysn to remove all names of the device inode="$(/bin/ls -i1 "$PKTDEV_DIR/$pktsysn" 2>/dev/null | awk '{print $1}')" [ -n "$inode" ] && find "$PKTDEV_DIR" -follow -inum "$inode" -exec rm {} \; ;; -i) (( "$#" != 2 )) && usage_error pktdev="$2" sdir="$(to_pkt_sdir "$pktdev")" || exit 1 for i in stat write_queue ; do ( cd "$sdir" && for f in "$i"/* ; do v="$(cat "$f" 2>/dev/null)" [ "$?" = 0 ] && echo "$f: $v" done ) done exit "$?" ;; -C) (( "$#" < 3 )) && usage_error pktdev="$2" valon="$3" valoff="$4" sdir="$(to_pkt_sdir "$pktdev")/write_queue" || exit 1 check_root echo "$valon" >"$sdir/congestion_on" [ -n "$valoff" ] && echo "$valoff" >"$sdir/congestion_off" echo "off=$(cat "$sdir/congestion_off") on=$(cat "$sdir/congestion_on")" ;; -c) (( "$#" != 2 )) && usage_error pktdev="$2" sdir="$(to_pkt_sdir "$pktdev")/write_queue" || exit 1 echo "off=$(cat "$sdir/congestion_off") on=$(cat "$sdir/congestion_on")" ;; -m) (( "$#" != 1 )) && usage_error cat "$PKTCDVD_DIR/device_map" exit "$?" ;; *) usage_error ;; esac exit 0