
--------------------------------------------------------------------------------
dish (v. 1.19.1): executes commands on several hosts via ssh/rsh/telnet
--------------------------------------------------------------------------------
Usage: dish [option]... -e command {-g hosts_file | host_1 host_2 ...}
   or: dicp {-g hosts_file | -g "user@host_1 ..."} local_file :remote_file
   or: dicp {-g hosts_file | -g "user@host_1 ..."} :remote_file local_file

Options:
  -h          - Print help message describing shortly all command-line options
  -H, --help  - Comprehensive help including examples
  --version   - Print program version and copyright message, then exit
  -V          - Display the version number and exit
  -C <dir>    - Configuration directory - $HOME/.dish is default;
                In this directory are located following configuration files:
                'hosts', 'rests', 'pass', and 'options'. When used, this option
                must be the first argument in the command line string, or be
                the second one if `-D' chosen! Alternatively, one can specify
                the configuration directory by defining the environment
                variable DISH_CONF.
  -CC <dir>   - Same as `-C' with fallback to default if local config not found;
                This means that, in case the files 'pass', 'options' or 'rests'
                are absent in the given directory, but such files exist in
                $HOME/.dish, the latter will be considered. The only exception
                is '$HOME/.dish/hosts' which will be ignored. Using this option
                is equivalent to changing directory to the opted one and then
                executing `dish'.
  -c <name>   - Program (alias "connector") and its options used for connecting
                to the remote host(s) - for example `rsh', whereas the spawned
                process will be "rsh $host <cmd>". Your default connector is
                `ssh'. Furthermore, by using a relevant text-based client
                as connector, one can access various kinds of hosts - switches,
                databases, and so on.
  -e <cmd>    - Remote command to execute;
                It can be also set by the environment variable DISH_CMD.
  -E <cmd>    - Execute command where also the connection part is specified
                e.g. "-E 'ssh $host date'" which is equal to "-e date".
                This option is incompatible with `-c' and `-e'. It can be also
                set by the environment variable DISH_FUEXE.
  -t          - Force pseudo-tty allocation in ssh;
                This happens automatically in case of password change.
  -T <time>   - Timeout for command execution - default 30s (per host)
  -TT <time>  - Total timeout for command execution - default 300s (all hosts);
                This option is useful only when hosts are processed in sequence
                and the total processing time should not exceed the specified
                upper bound.
  -x <regex>  - Regular expression for the shell prompt;
                This value specifies which prompt is to be expected in the
                program's shell after login into a system by `telnet', `mysql',
                `sqlplus' or other interactive command-line clients (see `-c').
                The default value is `(%|\$|#|\>) ?$'.
  -X <regex>  - Regular expression for the password prompt;
                It is case-insensitive with default value `Password: *$'.
  -AD <regex> - Regular expression for the ssh-prompt to add a new host key
                - `connecting (yes/no)?.*' is default
  -AC <str>   - String with the answer to the ssh-prompt to add a new host key
                - `yes' is default
  -g <file>   - File with list of hosts/ip's/accounts to target;
                The command will be executed on these targets. The default
                host file is '$HOME/.dish/hosts' - normally per line one
                account of the form "user@host" (if ssh is your choice for
                connector). In order to join lists use the option repeatedly.
                Alternatively, the environment variable DISH_HOSTS could be
                used to define the target hosts whereas in the specified string
                they have to be separated by blanks. By combining this option
                with `-r' or `-i' you can define various subsets of targeted
                hosts/accounts.
  -r <file>   - File with list of resting hosts/accounts to exclude;
                The default one is '$HOME/.dish/rests'. A "resting host"
                means one which will be excluded from the targets. The list of
                resting hosts or the file name could be specified also by the
                environment variable DISH_RESTS.
  -i <file>   - File with list of hosts/accounts to overlap with targeted hosts;
                There is no default file. Only overlapping hosts, such included
                in this list and at the same time defined as targets, will be
                processed.
  -u <name>   - User name - default is your local user name;
                It can be defined also by the environment variable DISH_USER.
                Internally the value is accessible by the variable $user (see
                examples). Further, it is irrelevant in case that accounts of
                the form "user@host" are processed since they include already
                the user name.
  -p <passwd> - Login password (-p "" = -pp = -a0)
                - alias "login authentic" or "a0"; If no authentication for
                login is required (no user- and no password-prompt appear), then
                use `/dev/null' as password. If the user name is requested, yet
                the password is an empty string, then `/dev/empty' has to be
                given as password. The value of this option could be also
                a password file (see `-P'). Eventually, one can define the
                password by the environment variable DISH_PASS.
  -a <passwd> - Additional password for authentication (-a "" = -aa = -a1)
                - alias "first authentic" or "a1"; Inside the spawn process,
                if a program like `smbmount', `su', `ssh', etc. asks for
                authentication, the a1-password is passed to it. This password
                can be also set by the environment variable DISH_PASS1.
  -A <passwd> - One more password for authentication (-A "" = -AA = -a2)
                - alias "second authentic" or "a2"; When a spawned process,
                after one authentication by the a1-password, asks again for
                a password, then a2 is sent. This password can be also set by
                the environment variable DISH_PASS2.
  -n <passwd> - New password in case of password change (-n "" = -nn = -ne)
  -p0         - Login without authentication - the same as `-p /dev/null'
  -p1         - Set the a1-password to be the same as the login password;
                This option should not be used together with `-p0' and `-a1'.
                See example d) bellow.
  -P <file>   - File with password(s);
                The default password file is '$HOME/.dish/pass'.
                It must be readable only for the user (file mode 600 or 700),
                otherwise the program exits with error, but see also next
                option. Every line in the file can hold a password entry of
                the form:
                "password:username:hostname", alternatively
                "password:::username:::hostname", or
                "password;;;username;;;hostname".
                One can specify a list of hosts separated by the `,' or `;'
                characters. Regular expressions for hostnames are also allowed
                (see the example configuration files in the distribution).
  -m          - Ignore the access permissions of the password file
  -s [<time>] - Sequential processing of hosts (default mode);
                If a time interval (measured in floating seconds) is specified,
                then the program is waiting this amount of time before starting
                to process the next host in the sequence.
  -F          - Spawn processes in background - fork and disconnect;
                This way all hosts are processed essentially in parallel!
                It's a very powerful option - depending on you RAM size and
                memory utilization, it shouldn't be a problem to process a few
                hundreds of hosts in parallel. Anyway, be careful - if you have
                too many hosts on the list, your could put your system under
                load. The stdout's of the background processes are redirected
                to '/dev/null', however you can use `-l' or `-L' to write the
                output to files. See also 'bugs and known problems' in the
                manual page.
  -f          - Spawn processes in background without disconnecting from tty;
                It's the same as `-F' whereas the stdout's of the spawned
                processes are sent to the terminal. Also the parent process
                waits for his children to finish. See also 'bugs and known
                problems' in the manual page.
  -q          - Be quiet - skip output from spawn and login;
                When working with the secure shell, it is also convenient to
                use `ssh' with the `-q' option.
  -Q          - Be QUIET - skip any output
  -v          - Be verbose (default) - overrides `-q' and `-Q'
  -l <file>   - Log command output to file;
                The output of the spawned processes is appended to the file.
  -L <name>   - Write a separate log for every host
                where <name> denotes the base name of the log file. The full
                name of a log file is defined as "<name>_<user@host>.log".
  -j          - Record the invoked command into a journal file
                with the name '$HOME/.dish/journal'; It keeps the history of
                the executed commands and their time of execution. An unique
                identifier is associated with every command.
  -J          - Record the invoked command and the spawned processes as well;
                Write into the journal file the executed command as well as
                the single processes spawned and their time of execution.
  -o <file>   - File with command line options passed to the program
                - default is '$HOME/.dish/options'; The options must be written
                in the file separated - one per line. By means of this file,
                one can modify the standard configuration: set up fork mode to
                be default, change the default connector, and so forth. When
                working in "copy mode", i.e. by invoking the program as 'dicp',
                '$HOME/.dish/options.dicp' is considered to be the default
                options file.
  -d          - enable expect's diagnostic output (look at `man expect')
  -D          - Debug mode (dry-run);
                Print out environment variables, config file names, and
                commands to execute, then exit. This option should be used
                as first in the command line.

Examples:
---------
You should consider that the variables $host and $user are evaluated. Thus
$host changes dynamically its value to the actual host/account name before
a new process is spawned. The same is true for $user.

a) Check the date and uptime on hosts 192.168.0.1 and 192.168.0.2

   dish -e 'date \; uptime' root@192.168.0.1 root@192.168.0.2

b) Distribute '.profile' and '.bashrc' to guest accounts on 'host1' and 'host2'

   dish -E "scp $HOME/.profile $HOME/.bashrc guest@\$host:" host1 host2

   or

   dicp -e "$HOME/.profile $HOME/.bashrc guest@:" host1 host2

   or

   dicp -g "host1 host2" $HOME/.profile $HOME/.bashrc guest@:

   or

   dicp -g "guest@host1 guest@host2" $HOME/.profile $HOME/.bashrc :

c) Copy remote '.profile' files into the local directory on localhost

   dicp -g "guest@host1 guest@host2 admin@host2" :.profile .profile.\$host

   Here, the name of the target file (local file) will include the remote
   account name in order that the local files have unique names.

d) Use `ssh' to login on 'host1' and copy from there '.profile' to 'host2'

   Since the list of hosts can not be empty, a dummy host is used to initiate
   the process. The `-t' option is necessary to force pseudo-tty allocation
   in `ssh', otherwise `ssh' will fail with error on login. A second password
   (a1-password) is required for scp-authentication on 'host2':

   dish -a '' -E 'ssh -t user1@host1 scp .profile user2@host2:' dummy_host

   In case the password of 'user1' and 'user2' is the same, you will be asked
   only once for a login password for user1@host1 if you use `-p1':

   dish -p1 -E 'ssh -t user1@host1 scp .profile user2@host2:' dummy_host

   Or equivalently, and more simple:

   dish -p1 -t -e 'scp .profile user2@host2:' user1@host1

e) Substitute lines with `START_XNTPD=' by `START_XNTPD="yes"' in /etc/rc.config

   This command is executed as root user on every host listed in 'Hosts.root':

   dish -u root -E 'ssh $user@$host "perl -pi -e \"s/^START_XNTPD=.*\$/START_XNTPD=\\\"yes\\\"/g;\" /etc/rc.config"' -g Hosts.root

f) Freeze accounts of users on a termination list

   By using a script called `FreezeUser.sh', all accounts of users found on
   'Terminate.User.lst' will be frozen today at 24:00 o'clock on both server
   groups as defined in files 'Hosts.1' and 'Hosts.2':

   dish -E 'ssh root@$host "cat Terminate.User.lst | while read UN; do echo \"su - admin -c \\\$HOME/bin/FreezeUser.sh \$UN\" | at 24:00 ; done"' -g Hosts.1 -g Hosts.2

g) Print out remote configuration file of an automounter

   Login as 'admin' user on host 192.168.0.1, switch to 'root', then cat
   the file '/etc/auto.net' and print out the date. The `-a' option causes
   the program to ask you for the root-password on remote host:

   dish -u admin -a '' -E 'rsh -l $user $host su - root -c \"cat /etc/auto.net\; date\"' 192.168.0.1

h) Install a package on Debian GNU/Linux hosts 

   After mounting a fileserver over samba, install from there a debian
   dish-package on all running servers, yet skip hosts on maintenance.
   Three different passwords are needed for authentication - one for login,
   next for su-root, and the last for mounting the fileserver:

   dish -a0 -a1 -a2 -g Debian.up -r Debian.maint -e 'su - -c \"mount -t smbfs //FILESERVER/Packages.Dir /mnt/smb ; dpkg -i /mnt/smb/dish_1.19.1_all.deb\"'

i) Check for system load >2 using default 'hosts' and 'pass' config files

   dish '(uptime |egrep \" (\[2-9\]|1\[0-9\])\\.\" && hostname) |paste - -'

j) Query a MySQL database on remote host 10.0.0.1
   dish -pp -c 'mysql -p -u $user -h' -e 'use mysql; show tables; describe user;' -u root 10.0.0.1

k) Change password concurrently on all hosts/accounts

   We assume that the list of user accounts is contained in file 'Accounts.lst',
   whereas an entry in the list is of the form "user@hostname". After command
   execution, you will be asked first for the login password (old password),
   and then for the new password which eventually have to retyped correctly:

   dish -p '' -n '' -e passwd -g Accounts.lst

   Or alternatively, processing concurrently and quietly all hosts:

   dish -pp -nn -f -Q -e passwd -g Accounts.lst

   When you want to change password and use `-nn', then the a1-password is
   implicitly set equal to the login password (a0-password).

l) Change password from 'root' account (don't use the `-a0' option)
   
   If you are going to change the root-password on 'remotehost', then try:

   dish -nn -e passwd root@remotehost

   The same as previous, but login as user 'admin' (login password), then
   switch to 'root' (a1-password), and finally update the root-password:

   dish -a1 -nn -e 'su -c passwd' admin@remotehost

   Changing the password for 'admin' on 'localhost', after login as 'root' via
   `telnet', is done by:

   dish -nn -c telnet -u root -e 'passwd admin' localhost

Notice that for password change, when `-p ""' (or equivalently `-a0' or `-pp')
is not explicitly used, the assumption is made that `passwd' will not ask for
the old password, as in case of a password change by 'root'. The same is true
also if you can login into an account without typing a password, but then
`passwd' prompts you to type the old one - this situation occurs when one is
using a ssh-key for login without password-authentication. For such scenario
the correct choice of options is `-p0 -aa -nn'.

---------
In case of properly prepared configuration files in '$HOME/.dish',
one can use dish as a distributed shell for a virtual cluster of hosts,
and run it without specifying any program parameters but merely issuing a
command, as for instance `dish df -k /' or `dicp .profile :'.

As a very last note, one should be aware that in case of authentication by
password, dish's automated login process is based on the expectation that
the login prompt send to the terminal will include the case-insensitive
regex-string `Password: *$' (but see also `-X'). Otherwise the authentication
procedure will fail.

Report bugs to <gnu@mirendom.net>

