Cygwin 1.7.x, mounts and /etc/fstab

Sunrise Heron Silhouette on FlickrSunrise Heron Silhouette by Brandon Godfrey

A few days I installed Cygwin on a new laptop.  I saw the warnings that Cygwin 1.7.x is new but I chose to ignore it for now.

I soon noticed that Cygwin was not remembering my mounts.  After reading this on the Cygwin front page I realized I needed to do some more research.

… the mount point storage has been moved out of the registry into files. User mount points are NOT copied into the new user-specific /etc/fstab.d/$USER file. Rather, every user has to call the /bin/copy-user-registry-fstab shell script once after the update.

Next I looked at the /etc/fstab file which pointed me to the Cygwin Mount Table documentation.  Using this documentation I did the following steps so that my mounts are always remembered.

  1. Manually mounted the C: drive.
    $ mount c: /c
  2. Ran mount to determine what to add to my /etc/fstab.
    $ mount
    C:/cygwin/bin on /usr/bin type ntfs (binary,auto)
    C:/cygwin/lib on /usr/lib type ntfs (binary,auto)
    C:/cygwin on / type ntfs (binary,auto)
    C: on /c type ntfs (binary,user)
  3. Based on the output of mount I added this line to my /etc/fstab.
    C: /c ntfs binary,user
  4. Closed the Cygwin shell, opened a new one and verified the C: drive was properly mounted.

Update 06-15-2010: I should have just followed Cygwin’s directions and ran /bin/copy-user-registry-fstab.

Moving Your Cygwin Installation

I was running out of space on one drive so I decided to move my Cygwin installation to another drive.

It turned out not to be too difficult thanks to this article Hints for Setting up Cygwin.  This is how I did it though there might be a simpler way.

  1. In a bash shell save the mount points as a batch script.
    $ mount -m > /c/cygwin-mount.bat
  2. Close the bash shell.
  3. Move the cygwin folder from one drive to the other.  In my case that was from C:\cygwin to D:\cygwin.
  4. Update all the short cuts for Cygwin in the Start Menu to use the new drive.
  5. Update  cygwin.bat, which is in the top level of your Cygwin installation, to use the new drive.
  6. Update your Windows environment variable to use the new Cygwin bin path, e.g. D:\cygwin\bin.
  7. Open a DOS cmd prompt.  Run umount to unmount the old Cygwin mounts.
    > umount
  8. Next run the mount points script.
    > C:\cygwin-mount.bat
  9. Open a Cygwin bash shell to make sure everything is working correctly.

Cygwin Bash Scripts and Java

Running Java scripts in Cygwin bash scripts becomes a little tricky because you want to treat most paths in Cygwin as normal UNIX paths but Java expects DOS paths.  Therefore to get around this you can use the mixed option for cygpath.

For example:

if [ -e /usr/bin/cygpath ] || [ -e /bin/cygpath ]
then
  export FOO=`cygpath --mixed "e:\work\betweengo/target/foo"`
else
  export FOO="e:\work\betweengo/target/foo"
fi

The result on Cygwin is that FOO will be set to “e:/work/betweengo/target/foo” which will work both in DOS and UNIX.

Maven Assembly Convert Shell Scripts to use UNIX LF’s

In a previous post, Shell Scripts with Windows LF’s Fail in Latest Cygwin, I wrote about how to use Perforce to check out all files in UNIX format. However if you use Eclipse then this solution will not work because Eclipse always inserts Windows LF’s in any line you insert into a file leading to a mess with files that have both UNIX and Windows LF’s.

However if you happen to use Maven to generate / copy your shell scripts to their target directories you can take advantage of the lineEnding property in the Assembly Director. If you specify the lineEnding property to be “unix” then the outputted shell scripts will be in UNIX format. For example:

<file>
  <source>src/main/scripts/foo.sh</source>
  <outputDirectory>bin</outputDirectory>
  <lineEnding>unix</lineEnding>
</file>

Shell Scripts with Windows LF’s Fail in Latest Cygwin

I am not sure when this happened but now in Cygwin shell scripts with Windows LF’s (the infamous control M’s) fail, i.e. Cygwin fails to run them because it will complain about the ‘\r’ character.

The simple way to fix this is to change your scripts to use UNIX LF’s by calling dos2unix or “conv -U”.

If you are using Perforce on Windows and seeing this problem then you can change your client to use “share” for the LineEnd option. Since Perforce stores all its text files in UNIX format on the server then it will write them out locally on your Windows machine in UNIX format. See the Perforce Knowledge Base article, CR/LF Issues and Text Line-endings. Fortunately Windows batch scripts with UNIX LF’s still run properly.

Note that when you make this change from the “local” LineEnd option then text files you already checked out will have the Windows LF’s. You will need to do a p4 sync -f on the files you want updated to have UNIX LF’s. Also when do you a p4 diff on your opened text files it will look like the whole file has changed. Again this is because of line feed issues. Doing a dos2unix on those opened text files will solve the problem.

Setting up cygwin users and groups

Whenever I start my bash shell I get this annoying message.

Your group is currently “mkgroup”.  This indicates that
the /etc/group (and possibly /etc/passwd) files should be rebuilt.
See the man pages for mkpasswd and mkgroup then, for example, run
mkpasswd -l [-d] > /etc/passwd
mkgroup  -l [-d] > /etc/group
Note that the -d switch is necessary for domain users.

I tried doing what the documentation but I still kept getting that message.  I then tried one of the suggestions in the comments of this post, Cygwin users and groups « sinewalker.

$ mkpasswd -l -p /home/ -c > /etc/passwd
$ mkgroup -l -c> /etc/group

I then got this message.

Copying skeleton files.
These files are for the user to personalise
their cygwin experience.

These will never be overwritten.

`./.bashrc’ -> `/home/fkim//.bashrc’
`./.bash_profile’ -> `/home/fkim//.bash_profile’
`./.inputrc’ -> `/home/fkim//.inputrc’
Your group name is currently “mkgroup_l_d”. This indicates that not
all domain users and groups are listed in the /etc/passwd and
/etc/group files.
See the man pages for mkpasswd and mkgroup then, for example, run
mkpasswd -l -d > /etc/passwd
mkgroup  -l -d > /etc/group

This message is only displayed once (unless you recreate /etc/group)
and can be safely ignored.

I am not sure what it means but it was only displayed once.  Now that I am not seeing it anymore I’m happy. 🙂

Perforce and Cygwin

To get Perforce to work with Cygwin is not too difficult. One just has to make an alias for p4 like this (thanks to this excellent Perforce FAQ).

if [ -e /bin/cygpath ]; then
  alias p4='p4 -d `cygpath -w $PWD`'
fi

This alias works all the time except I think when you are in a directory you accessed via a link.

Note you don’t need to go such lengths as described in this post.

Save the Output in a Shell Script Array

I wanted to do some shell processing on the contents of a directory. To do this I needed to put the contents of the directory in an array. Fortunately this is not difficult with bash.

  1. First capture the output.

    ls_output=$(ls /images)

  2. Next declare an array and reference the output with this array.

    declare -a img_files
    img_files=($ls_output)

  3. Now you can access the array directly or loop through it.

    echo ${img_files[0]}
    for img_file in ${img_files[@]}
    do
      ...
    done

Thanks O’Reilly’s Bash Cookbook.

Save the Output in a Shell Script Variable

I was counting how many times a file was referenced by other files. I then wanted to do some processing based on this number.

To do this I saved the output of this count in a variable which I was then able to reference later in the shell script.

num_files=`find . -type f -name '*.html' | xargs grep $img_file | wc -l`

# delete this file if it is not referenced
if [ "0" = $num_files ]
then
  rm $IMAGE_DIR/$img_file
fi

Cygwin Bash cannot execute DOS formatted scripts

As of bash 3.2.9-10, bash no longer executes DOS formatted scripts as detailed in this announcement. I understand the reasoning for this is that:

  1. cygwin is supposed to mimic Linux, not Windows
  2. it is faster to assume that the scripts are in UNIX format

To get around this restriction I did what was recommended in this bug report, i.e. I created a Windows user environment variable named “SHELLOPTS” with the value “igncr”.