Author Archive


July 9th, 2009 3 comments

Just read this mail in the coreutils-bugs mailing-list:


There appears to be a bug in coreutils. The –inverse flag appears to
be missing or broken from most utils.

$ ps –inverse
— ERROR: Unknown gnu long option.
$ ls –inverse
ls: unrecognized option `–inverse’
$ rm –inverse foo
rm: unrecognized option `–inverse’
$ echo –inverse “hello”
–inverse hello

Clearly this is not whats expected..
I would expect to receive a list of all processes currently not
, all files not in the current working directory, delete all
files not named foo in the current working directory and echo all text
besides “hello”

Is this bug fix on the current roadmap? When can I expect it to be fixed?

Thanks very much!

PS: highlighting by me

Categories: Uncategorized Tags:

ssh-argv0: for the lazzy ‘ssh’ typer

June 9th, 2009 1 comment

Those of us who often use often ssh to login or start remote commands will find this useful:

$ ln -s /usr/bin/ssh-argv ~/bin/$HOST

You can use the FQDN of the host of course, but a short alias is even more shorter. Put this in your .ssh/config and use the alias for the link:

  HostName $FQDN

And yes, you want to put both $FQDN and $ALIAS in the Host line. If you ever add more options to this Host entry you want to apply it to both $FQDN and $ALIAS. If you omit $FQDN the options will only apply to the $ALIAS.

Categories: linux, software Tags:

Home Project

June 9th, 2009 2 comments
Categories: Uncategorized Tags:

DOS – The Default Option Set Series: Front Page

May 28th, 2009 No comments
Categories: DOS Tags:

DOS – The Default Option Set Series #1: GNU grep

May 27th, 2009 3 comments

With this post I will start an article series about default options for popular shell tools. And I would like to invite all of you to participate in this process to find a profound default option set for these tools. I will provide my current DOS as a discussion base and extend these by user comments.

In this first DOS its all about GNU grep.


Some fundamental information about the considered tool.

Name: GNU grep
Version: 2.5.3

How to set default options:

This section will describe how to set the Default Option Set. For grep its the environmental variable GREP_OPTIONS.

Default Option Set:

In this section comes a descriptive list of the options.

  • ignore binary files
  • use colored output in terminals
  • ignore special files like fifos, char and block devices
  • exclude patch *.rej and *.orig files
  • exclude common scm directories
  • exclude build directories


And here is a ready-to-use version of the option set.

export GREP_OPTIONS="--binary-files=without-match \
--color=auto \
--devices=skip \
--exclude='*.rej' \
--exclude='*.orig' \
--exclude-dir=.git \
--exclude-dir=.svn \
--exclude-dir=CVS \
--exclude-dir=patches \
--exclude-dir=.pc \
--exclude-dir=.libs \

Categories: bashism, DOS, linux Tags: , ,

Connection sharing with OpenSSH – 3rd Update

May 26th, 2009 No comments

Want to speed up your svn/cvs operations? Want fast path completions for scp commands? Than you should enable the connection sharing feature from OpenSSH.

The essence is, that your first connection to a remote host acts as a master connection. All subsequent connection attempts will use the master connection to re-use the connection of the master.

What you save is the repeated authentication procedure, especially if you use passwd authentication.

First you need to create a directory where all master connections create a socket so that other clients can find already established connections and communicate with the master.

$ mkdir -p ~/.ssh/masters
$ chmod 0700 ~/.ssh/masters

Next we need to enable the feature in your ~/.ssh/config:

ControlMaster auto
ControlPath "~/.ssh/masters/%r@%h:%p"

The ControlPath is a format string where %r is the remote user name, %h the remote host, and %p the port. If your ~/.ssh directory is on a mounted share, you should also include a %l for the local host. So that you can connect to a remote from multiple hosts.

ControlPath "~/.ssh/masters/%l -> %r@%h:%p"

It would be nice to put these into separate directories, but OpenSSH does not create directories.

If you try this out you will probably encounter a problem. If your master is a interactive shell and you close it, ssh will not return to the console if other clients still use this shared connection.

To circumvent this you can start a ssh process into the back ground:

$ ssh -nNf host

You can also use sshfs to act as the master:

$ sshfs host: mntpoint

I still haven’t found a nice way to make this somehow automatic. My wish would be a hook into the NetworkManager to get notified when a network connection is established. With this one can automatically connect to predefined hosts.

A second problem, which most of you will only notice if your computer hangs-up periodically and you try to reconnect after the restart, is that ssh complains that it can not use the still existing socket in the masters directories. The problem was more on my side and the solution is obvious:

Set the ControlMaster to no in the ~/.ssh/config file.

In this mode (which is the default) the client tries to connect to a master and fallbacks to a normal connection if it fails.

Now you need to start your master connection explicitly with the ControlMaster=yes option:

$ ssh -nNf -o ControlMaster=yes host


$ sshfs -o ControlMaster=yes host: mntpoint


Supplement 1:

To close a master connection initiated with ssh -nNf ... run this:

$ ssh -O exit host

Supplement 2:

Now to the fun part:

I just hacked a formidable solution to the problem, when to start the master control. And by hacked I mean it.

Get the latest OpenSSH portable package and extract it:

$ wget
$ tar xf openssh-5.2p1.tar.gz
$ cd openssh-5.2p1

Now safe the following patch as controlcommand.patch and apply it to the source:

diff --git a/mux.c b/mux.c
index 79f8376..1b07bab 100644
--- a/mux.c
+++ b/mux.c
@@ -518,6 +518,9 @@ muxclient(const char *path)
+		debug("command-mux: Start control command");
+		break;
@@ -534,13 +537,22 @@ muxclient(const char *path)
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
fatal("%s socket(): %s", __func__, strerror(errno));

if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
if (muxclient_command != SSHMUX_COMMAND_OPEN) {
fatal("Control socket connect(%.100s): %s", path,
if (errno == ENOENT)
-			debug("Control socket \"%.100s\" does not exist", path);
+			if (options.control_master != SSHCTL_MASTER_COMMAND ||
+			    options.control_command == NULL) {
+				debug("Control socket \"%.100s\" does not exist", path);
+			} else {
+				int rc = ssh_local_cmd(options.control_command);
+				debug("Executing control command: %.500s: %d", options.control_command, rc);
+				if (!rc)
+					goto retry;
+			}
else {
error("Control socket connect(%.100s): %s", path,
diff --git a/readconf.c b/readconf.c
index 53fc6c7..f2be9c5 100644
--- a/readconf.c
+++ b/readconf.c
@@ -128,8 +128,9 @@ typedef enum {
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
-	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
-	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
+	oSendEnv, oControlPath, oControlMaster, oControlCommand,
+	oHashKnownHosts, oTunnel, oTunnelDevice,
+	oLocalCommand, oPermitLocalCommand,
oVisualHostKey, oZeroKnowledgePasswordAuthentication,
oDeprecated, oUnsupported
} OpCodes;
@@ -222,6 +223,7 @@ static struct {
{ "sendenv", oSendEnv },
{ "controlpath", oControlPath },
{ "controlmaster", oControlMaster },
+	{ "controlcommand", oControlCommand },
{ "hashknownhosts", oHashKnownHosts },
{ "tunnel", oTunnel },
{ "tunneldevice", oTunnelDevice },
@@ -856,6 +858,8 @@ parse_int:
else if (strcmp(arg, "autoask") == 0)
+		else if (strcmp(arg, "command") == 0)
fatal("%.200s line %d: Bad ControlMaster argument.",
filename, linenum);
@@ -863,6 +867,10 @@ parse_int:
*intptr = value;

+	case oControlCommand:
+		charptr = &options->control_command;
+		goto parse_string;
case oHashKnownHosts:
intptr = &options->hash_known_hosts;
goto parse_flag;
@@ -1057,6 +1065,7 @@ initialize_options(Options * options)
options->num_send_env = 0;
options->control_path = NULL;
options->control_master = -1;
+	options->control_command = NULL;
options->hash_known_hosts = -1;
options->tun_open = -1;
options->tun_local = -1;
diff --git a/readconf.h b/readconf.h
index 8fb3a85..93255a0 100644
--- a/readconf.h
+++ b/readconf.h
@@ -112,6 +112,7 @@ typedef struct {

char	*control_path;
int	control_master;
+	char	*control_command;

int	hash_known_hosts;

@@ -130,6 +131,7 @@ typedef struct {

void     initialize_options(Options *);
void     fill_default_options(Options *);
diff --git a/ssh.c b/ssh.c
index 9d43bb7..02f1960 100644
--- a/ssh.c
+++ b/ssh.c
@@ -212,6 +212,7 @@ main(int ac, char **av)
extern char *optarg;
struct servent *sp;
Forward fwd;
+	char *host_arg;

/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@@ -547,6 +548,9 @@ main(int ac, char **av)
if (!host)

+	/* safe the hostname given on the command-line */
+	host_arg = host;

@@ -622,6 +626,9 @@ main(int ac, char **av)
&options, 0);

+	if (options.hostname != NULL)
+		host = options.hostname;
/* Fill configuration defaults. */

@@ -651,15 +658,12 @@ main(int ac, char **av)
cp = options.local_command;
options.local_command = percent_expand(cp, "d", pw->pw_dir,
"h", options.hostname? options.hostname : host,
-                    "l", thishost, "n", host, "r", options.user, "p", buf,
+                    "l", thishost, "n", host_arg, "r", options.user, "p", buf,
"u", pw->pw_name, (char *)NULL);
debug3("expanded LocalCommand: %s", options.local_command);

-	if (options.hostname != NULL)
-		host = options.hostname;
/* force lowercase for hostkey matching */
if (options.host_key_alias != NULL) {
for (p = options.host_key_alias; *p; p++)
@@ -672,12 +676,12 @@ main(int ac, char **av)
options.proxy_command = NULL;
if (options.control_path != NULL &&
strcmp(options.control_path, "none") == 0) {
options.control_path = NULL;
if (options.control_path != NULL) {
char thishost[NI_MAXHOST];

@@ -691,6 +695,32 @@ main(int ac, char **av)
"r", options.user, "l", thishost, (char *)NULL);
+	if (options.control_command != NULL &&
+	    strcmp(options.control_command, "none") == 0) {
+		xfree(options.control_command);
+		options.control_command = NULL;
+	}
+	if (options.control_command != NULL && options.control_path != NULL) {
+		char thishost[NI_MAXHOST];
+		if (gethostname(thishost, sizeof(thishost)) == -1)
+			fatal("gethostname: %s", strerror(errno));
+		snprintf(buf, sizeof(buf), "%d", options.port);
+		cp = options.control_command;
+		options.control_command = percent_expand(cp,
+		    "l", thishost,
+		    "h", options.hostname ?: host,
+		    "p", buf,
+		    "r", options.user,
+		    "n", host_arg,
+		    "u", pw->pw_name,
+		    "d", pw->pw_dir,
+		    "s", options.control_path,
+		    (char *)NULL);
+		xfree(cp);
+	}
if (muxclient_command != 0 && options.control_path == NULL)
fatal("No ControlPath specified for \"-O\" command");
if (options.control_path != NULL)
diff --git a/sshconnect.c b/sshconnect.c
index c04aa10..9d6e6c2 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1155,8 +1155,7 @@ ssh_local_cmd(const char *args)
pid_t pid;
int status;

-	if (!options.permit_local_command ||
-	    args == NULL || !*args)
+	if (args == NULL || !*args)
return (1);

if ((shell = getenv("SHELL")) == NULL)
$ patch -p1 < controlcommand.patch

configure and build openssh with --bindir=$HOME/bin and use $DESTDIR to install the complete package:

$ make DESTDIR=$PWD/root install-nosysconf

Copy the binaries into your PATH:

$ cp $PWD/root$HOME/bin/{ssh,scp,sftp} $HOME/bin

Change your ~/.ssh/config:

ControlMaster command
ControlCommand " %h"

Finally put this script as somewhere into your PATH:

ssh -nNf -o ControlMaster=yes "$1"

I used a script to put some sshfs mounts into this.

To be sure your tools use the new ssh command add something like this into a proper file:

export GIT_SSH=$HOME/bin/ssh
export CVS_RSH=$HOME/bin/ssh
export RSYNC_RSH=$HOME/bin/ssh
export SVN_SSH=$HOME/bin/ssh

Categories: linux, software Tags: