Hiding MySQL/PostgreSQL password from the “ps” command

If you want to run a database tool for MySQL from the command line it would seem you cannot avoid including the password using a –password argument. The problem is that the whole command line while the command is being run will be visible to any other user of the same server using the “ps” command.

The solution is to specify the password in a “option” file (as MySQL calls it). This is a file named .my.cnf (note the dot at the beginning) in your account’s root folder (ie: /home/myname/ or /root/ for the root user) with the following contents:

[client]
password=password

Of course replace the “password” with your real password. You should als make this file only readable by yourself with the following command:

chmod 600 .my.cnf

That ensures that nobody else can open the file (well except root if you are not an admin, but the root user would have access to everything anyway).

Now whenever you run a MySQL tool (mysql, mysqldump, etc) the password from the option file will be automatically used. If your username matches the MySQL username you also don’t need to specify a username. This can be very useful especially as root, when you need to do daily backups using mysqldump for example.

This tricks works in a similar way for PostgreSQL: put a file named .pgpass with the following contents:

hostname:port:database:username:password

You can use an asterisk (*) to match “any” value (wildcard), for example for port or database.

Arrays in Linux shell scripting

For a script I want to build for maintaining WordPress themes & plugins a bit easier I wanted to basically loop through a list of locations of WordPress installations on a single server. This basically means I need to be able to create an “array”.

I knew that you could use arrays in a shell script as I was using it in another script to automatically make a backup of all databases in a MySQL or PostgreSQL database, however that script gets the list from the output of an application: how do you define them yourself?

First thing to know is that array support differs by which shell you use. I prefer simply “/bin/sh”, but that only has extremely basic array support. Bash (and others) have better support. Fortunately the array support in “/bin/sh” is sufficient in my case.

Anyway, on to the solution. In “/bin/sh” you define an array as a list of strings separated by spaces (as such, I’m not sure if you can include strings with spaces) and use a very simple “for” loop to iterate through them:

#!/bin/sh

ARRAY="Hello World"

for WORD in $ARRAY
do
  echo $WORD
done

This script will display each word from the array on a different line. Note that there is no way to refer to a specific member of the array (you can’t use an index).

In Bash you can use arrays in a more advanced way:

#!/bin/bash

ARRAY=("Hello" "World")
ARRAY[2]="In Bash"
LENGTH=${#ARRAY[@]}

for ((i = 0; i < $LENGTH; i++))
do
  echo ${ARRAY[i]}
done

Now as you can see you can easily define a list of strings (with spaces if you want), refer to specific members of the array using an index and get the length of the array.

Configure exim4 to send mail to other hosts

If you have just installed Debian (or other Linux) you might be stumped as to why sending e-mails from web software (such as forum activation e-mails) is not working. The reason is that by default the exim4 mail software is setup not to forward any mail to any remote hosts. This of course is an excellent anti-spam measure, but not very useful if you really need a server to send mail out to the world.

The solution is really simple. Edit the file /etc/exim4/update-exim4.conf.conf and change the following line:

dc_eximconfig_configtype='local'

into:

dc_eximconfig_configtype='internet'

Then restart exim4 and you’re done! To test if it really works, first create a file called “testmail” that looks like this:

Subject: exim4 mail test
Testing...
(blank line)

The “(blank line)” must obviously be a real blank line. Just press enter a few times and save the file. Then try to send it with the following command:

sendmail -v you@workingemail.com < testmail

Change the e-mail address into your own working e-mail address (like a Gmail account or something). The output of the sendmail command will give you a very detailed overview on how the e-mail was sent (or not). If the test was successful you’ll find the mail in your mailbox in a few minutes.

Solving “IPv6 addrconf: prefix with wrong length 48” permanently

If you have a recent distribution of Linux, you might find the message “IPv6 addrconf: prefix with wrong length 48” repeated a lot in syslog. If you Google this error message you’ll quickly find that this is because IPv6 auto configuration (sort of like DHCP) is failing. Now if you don’t want to bother with IPv6 yet or if you use static IPv6 (like my servers do) you don’t need IPv6 auto configuration.

A quick fix to solve the problem (as mentioned on sites like these) is to run the following commands:

echo 0 > /proc/sys/net/ipv6/conf/eth0/autoconf
echo 0 > /proc/sys/net/ipv6/conf/eth0/accept_ra

And yes, that solves the problem – until the next reboot that is. The permanent solution mentioned on that site however, does not work (as also confirmed by this IPv6 howto). The reason is that referring to all network interfaces using “all” in the following lines in /etc/sysctl.conf somehow doesn’t work:

net.ipv6.conf.all.autoconf = 0
net.ipv6.conf.all.accept_ra = 0

The simple solution is to refer to each network interface specifically. My servers have both eth0 and eth1 (2 NICs) so I setup /etc/sysctl.d/ipv6.conf as follows:

net.ipv6.conf.default.autoconf = 0
net.ipv6.conf.default.accept_ra = 0
net.ipv6.conf.all.autoconf = 0
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.eth0.autoconf = 0
net.ipv6.conf.eth0.accept_ra = 0
net.ipv6.conf.eth1.autoconf = 0
net.ipv6.conf.eth1.accept_ra = 0

If you have only one network interface, you can omit the “eth1” lines. Alternatively you can use pre-up commands as described in the IPv6 howto, though I think my solution is prettier.

How to prevent cron & PowerDNS clogging syslog

On a default Debian installation both cron and PowerDNS will log into /varlog/syslog. If you are running very frequent cron jobs (like every 5 minutes) or an active PowerDNS server (or recursor), you’ll find syslog will be completely clogged with mostly unimportant messages. The solution of course, is to have these two services output log messages to their own log files.

In Debian Linux, you’ll need to change a few configuration files. First in open /etc/rsyslog.conf and change the following line:

*.*;auth,authpriv.none          -/var/log/syslog

into this (basically add local0 and cron to the list of things not to log into syslog):

*.*;local0,cron,auth,authpriv.none          -/var/log/syslog

Then uncomment the line just below that (remove # sign):

cron.*                         -/var/log/cron.log

If you do not run PowerDNS you can skip to the end of this post. If you do run PowerDNS (server or recursor) create the file /etc/rsyslog.d/pdns.conf (for example using the command nano -w /etc/rsyslog.d/pdns.conf) with the following contents:

local0.* -/var/log/pdns.log

Then update your PowerDNS configuration to make use of this file by changing the following section in either /etc/powerdns/pdns.conf and/or /etc/powerdns/recursor.conf

#################################
# logging-facility      Facility to log messages as. 0 corresponds to local0
#
logging-facility=0

As you can see, uncomment the logging-facility line and set it to 0. After this reboot PowerDNS.

In order for the PowerDNS log file not to grow out of control, you might want to add it to the list of log files that should be rotated by editing /etc/logrotate.d/rsyslog and adding /var/log/pdns.log to the list of log files (I typically add this line below /var/log/messages just before the opening { bracket):

/var/log/messages
/var/log/pdns.log
{

Finally restart rsyslog by running /etc/init.d/rsyslog restart