Linux DF Command Examples

Ever wondered how much space you have left on your hard drive? Cannot remember what file format your partitions are? You can use the Linux df command to get some of this data.

This article will give you the heads up on df.

1. Display Disk Usage Using df

erik@debian:~$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1              7850996   4116300   3335884  56% /
tmpfs                   258484         0    258484   0% /lib/init/rw
udev                     10240        52     10188   1% /dev
tmpfs                   258484         0    258484   0% /dev/shm

The example above shows the basic output of the df command. However, the output isn’t very readable.

2. Readable Disk Usage Using df -h

The df -h command will display the partition size in human readable form, G for gigabytes, M for megabytes, K for kilobytes.

erik@debian:~$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7.5G  4.0G  3.2G  56% /
tmpfs                 253M     0  253M   0% /lib/init/rw
udev                   10M   52K   10M   1% /dev
tmpfs                 253M     0  253M   0% /dev/shm

3. Display Partition Types Using df -Th

To display the partition type you can execute the command df -T (with the h for a more user friendly file size).

erik@debian:~$ df -Th
Filesystem    Type    Size  Used Avail Use% Mounted on
/dev/sda1     ext3    7.5G  4.0G  3.2G  56% /
tmpfs        tmpfs    253M     0  253M   0% /lib/init/rw
udev         tmpfs     10M   52K   10M   1% /dev
tmpfs        tmpfs    253M     0  253M   0% /dev/shm

4. Display Dummy File Systems Using df -ah

erik@debian:~$ df -ah
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7.5G  4.0G  3.2G  56% /
tmpfs                 253M     0  253M   0% /lib/init/rw
proc                     0     0     0   -  /proc
sysfs                    0     0     0   -  /sys
procbususb               0     0     0   -  /proc/bus/usb
udev                   10M   52K   10M   1% /dev
tmpfs                 253M     0  253M   0% /dev/shm
devpts                   0     0     0   -  /dev/pts
none                  0.0K  0.0K  0.0K   -  /proc/fs/vmblock/mountPoint

The Linux operating systems uses various virtual file systems shown here, including /proc /sys /dev. These will displayed when using the df -h command.

How To Split Files For Easy Transferring

I recently ran into the problem of having this very large file and no ‘fast’ way of transferring it to another computer. Over Wireless it was calculated to take upwards of four hours to transfer (due to weak signal etc.), but I had a 4 GB USB key that I could use. The problem was that my file was over 4 gigabytes and of course my key was only 4G, in fact only 3.9G of usable space. What to do?! My initial thought was to do some trickery using dd, where I could make two files with the first up to the 3.9G barrier and create the second file with the remainder then piece it back together. This is a feasible option. But I came across the split function in Linux.

Split allows you to, you guessed it, split a file into pieces and automatically increment the file name so you can keep track of the pieces. This was a perfect solution for my needs. I was transferring the file from a Linux machine to a Windows machine, so I also had to figure out how to piece the file back together in Windows. In Linux its just a matter of “catting” the files together, but in Windows you can actually do it using copy /b for binary.

Here I will outline the steps for you to split a file into chunks and reassemble it at the destination.

Split A File Into Pieces

The split program is quite handy and has various flags to play around with, the important ones are:

  • -a, –suffix-length=N – use suffixes of length N (default 2)
  • -b, –bytes=SIZE – put SIZE bytes per output file
  • -C, –line-bytes=SIZE – put at most SIZE bytes of lines per output file
  • -d, –numeric-suffixes – use numeric suffixes instead of alphabetic
  • -l, –lines=NUMBER – put NUMBER lines per output file
  • –verbose              print a diagnostic just before each output file is opened

SIZE may have a multiplier suffix: b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024, GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y

For example, I have a debian 5 ISO that’s 3.2 GB that I decided to split into 500MB files.

$ ls
debian5.iso
$ split -b 500M -d debian5.iso 
$ ls -l
total 6304488
-rw-r--r-- 1 erik erik 3224731648 2011-03-16 11:45 debian5.iso
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:52 x00
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:52 x01
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:53 x02
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:53 x03
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:54 x04
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:54 x05
-rw-r--r-- 1 erik erik   79003648 2011-03-16 11:54 x06

So now I can just transfer chunks at a time.

Okay, now the files are on my second machine, but how do I put them all back together again. Poor Humpty Dumpty!

Reassemble Split File In Linux

To reassemble the file in Linux is quite easy:

$ cat x0* > debian5.iso
$ ls -l
total 6304488
-rw-r--r-- 1 erik erik 3224731648 2011-03-16 11:45 debian5.iso
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:52 x00
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:52 x01
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:53 x02
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:53 x03
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:54 x04
-rw-r--r-- 1 erik erik  524288000 2011-03-16 11:54 x05
-rw-r--r-- 1 erik erik   79003648 2011-03-16 11:54 x06

cat will automatically combine all files into one binary file. We redirect the output using the Bash redirection symbol >. For more information on Bash redirection.

Reassemble Split File In Windows

Great, but I am running Windows! In fact I am running Windows on my other machine, unfortunately I am not running cygwin so I had to find an alternate method. It turns out you can use the copy command with the /b flags to copy a set of files into one. The /b informs copy that we are dealing with a binary file rather than ASCII.

Using the command prompt in Windows you can rebuild the files with:

E:\>copy /b x00 + x01 + x02 + x03 + x04 + x05 + x06 debian5.iso
x00
x01
x02
x03
x04
x05
x06

The computer chunked along spitting out the x0* on each line until finally my file was pieced back together. The plus sign indicates to copy that these are the files we need to concatenate together with the last argument the output file.

There you have it. This can be used to break down any file, and could be used to send multiple e-mails to yourself to get around an e-mail attachment limit.

Random Number Generation In C and Bash

Well that was random! Or was it? Maybe it was pseudo-random…who knows? Random number generation is an important part of cryptography when seeding a hash or creating a cipher. But how can you generate a random number from a computer, if a computer is deterministic? This is where pseudo-random and random numbers come in. They are referred to as pseudo random because a computer is deterministic, however, the Linux kernel has implemented the /dev/random and /dev/urandom options for number generation that uses environmental noise from the hardware in your computer via the device driver of the device as a seed. Awesome, wikipedia states for /dev/random, which provides the ‘most’ random values:

In this implementation, the generator keeps an estimate of the number of bits of noise in the entropy pool. From this entropy pool random numbers are created. When read, the /dev/random device will only return random bytes within the estimated number of bits of noise in the entropy pool. /dev/random should be suitable for uses that need very high quality randomness such as one-time pad or key generation. When the entropy pool is empty, reads from /dev/random will block until additional environmental noise is gathered.

The /dev/urandom is non-blocking and thus will re-use the pool even with low entropy. There is also the C function call random() that can be used for pseudo-random number generation.

Lets get to some examples!

Using /dev/random For A Random Number

To grab a random number from /dev/random we simply do a read on the file handle into an unsigned integer and voila.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#define RANDPATH "/dev/random"
 
int main()
{
	int fp, ret;
	unsigned int rand;
 
        // Open as read only
	fp = open(RANDPATH, O_RDONLY);
	if(fp < 0){
		fprintf(stderr, "Could not open -%s- for reading.\n",RANDPATH);
		return -1;
	}
 
	ret = read(fp, &rand, sizeof(rand));
        if(ret < 0){
                fprintf(stderr, "Could not read from -%s-.\n",RANDPATH);
                close(fp);
                return ret;
        }
 
	fprintf(stdout, "Random value: %u\n", rand % 10); // Range from 0 to 10
 
	close(fp);	
	return 0;
}

Easy as that, if you are planning to do many reads, take into account the /dev/random will block if the entropy is too low. If you require a large set of random numbers, use /dev/urandom but be aware you will retrieve more psuedo-random values than random.

Retrieve A Pseudo-Random Number With ‘random()’

Perhaps your kernel does not support /dev/random or /dev/urandom and you simply need a pseudo-random value. This can be achieved using the random() function call, providing an initial seed prior to calling random(). For example:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
 
int main()
{
	int j;
 
	srand((unsigned int)time(NULL));
 
	// Account for inherent flaws using Modulo use divisor instead
	j = 1 + (int)( 10.0 * random() / ( RAND_MAX + 1.0 ) );
 
	fprintf(stdout, "Random value: %u\n", j);
 
	return 0;
}

This will produce a random value between 1 and 10. If you require a larger value multiply random by 100 for 1 to 100 etc. srand() is used to seed the random number generator, in this case I pass in the current time as our seed. time() returns a value in seconds, if you need to retrieve a set of pseudo-random values quicker than once a second, pass in nanoseconds or microseconds as a new seed.

Generate A Random Number In Bash

In Bash we can utilize the /dev/random file handle, if present in your kernel, using hexdump to grab values as hexidecimal.

rand=$((0x$(hexdump -n 1 -ve '"%x"' /dev/random) % 100))

This will give us a value between 1 and 100. This can only be used for a 1 byte value (2^8), as our length is only 1 byte. If you require more, you must specify in hexdump as -n X where X is the length of bytes and update your modules.

There is also an internal random number that Bash populates, but provides a pseudo-random integer in the range 0 – 32767, and should never be used for encryption keys.
It is simply $RANDOM.

For example for a value between 0 – 32767

number=$RANDOM

You can also use modules to grab a value to a maximum size via $RANDOM % 100 for example.

Was that random after all?

Find Your Interface Index In C

Upon system boot, the kernel will assign an interface index to each new device added. There are various ways to get the interface index, including an ioctl call, using the C function if_nametoindex(), as well as the “/sys/class/net/eth0/ifindex”. I will explore these three options with examples here.

Get Interface Index Using An ioctl Call

To retrieve the interface index using an ioctl call we must create a socket and populate the ifreq structure, as I showed in my previous What Is My Interfaces MAC Address?. For example:

// Headers needed
#include <net/if.h>
#include<netinet/if_ether.h>
#include <net/if_arp.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>     /* the L2 protocols */
#include <asm/types.h>
#include <linux/sockios.h>
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
 
int get_interface_index(const char *interface_name)
{
      struct ifreq ifr;
      int fd;
 
      memset(&ifr, 0, sizeof(ifr));
 
      // setup ifr for ioctl 
      strncpy (ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name) - 1);
      ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
 
      // create socket
      fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
      if ( fd == -1) {
             fprintf(stderr," Could not create raw socket:  %s \n", strerror(errno));
             return -1;
      }
 
      // get index 
      if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1)
      {
              close(fd);
              return (-1);
      }
      // close socket if created locally
      close(fd);
 
      return ifr.ifr_ifindex;
}

To create the raw socket you have to run this binary as root. The output from using this function on my system is:

# ./get_index eth0
eth0
3
# ./get_index eth1
eth1
2

So on my system, eth0 is actually indexed at 3 and eth1 is indexed at 2. This may seem counter-intuitive but it is just based on how the kernel registers the devices, for instance eth1 may be an on board network card while eth0 is a PCI network card.

Get Interface Index Using ‘if_nametoindex()’

If you know the name of the interface you are trying to retrieve the index from, you can make a C call to if_nametoindex() and get that value. The functions definition is:

unsigned if_nametoindex(const char *ifname);

It is defined in <net/if.h>. It needs the name of the interface as a parameter and returns the index, or 0 upon failure.

Retrieve Index Using /sys/

The /sys/ or sysFS filesystem is a virtual filesystem that provides information about system devices and drivers to userspace. Some of that information is interface information, including the index. If you head over to “/sys/class/net/” you will see a directory containing all interfaces on your system. On my system:

/sys/class/net$ ls
eth0  eth1  lo  vmnet1  vmnet8

I have five interfaces including the loopback. Within each of these directories is the unique information related to that interface. For example:

$ ls -l eth0/
total 0
-r--r--r-- 1 root root 4096 2011-03-24 16:15 address
-r--r--r-- 1 root root 4096 2011-03-24 16:15 addr_len
-r--r--r-- 1 root root 4096 2011-03-24 16:15 broadcast
-r--r--r-- 1 root root 4096 2011-03-24 16:15 carrier
lrwxrwxrwx 1 root root    0 2011-03-24 16:15 device -> ../../../0000:00:14.0
-r--r--r-- 1 root root 4096 2011-03-24 16:15 dev_id
-r--r--r-- 1 root root 4096 2011-03-24 16:15 dormant
-r--r--r-- 1 root root 4096 2011-03-24 16:15 features
-rw-r--r-- 1 root root 4096 2011-03-24 16:15 flags
-rw-r--r-- 1 root root 4096 2011-03-24 16:15 ifalias
-r--r--r-- 1 root root 4096 2011-03-24 16:15 ifindex
-r--r--r-- 1 root root 4096 2011-03-24 16:15 iflink
-r--r--r-- 1 root root 4096 2011-03-24 16:15 link_mode
-rw-r--r-- 1 root root 4096 2011-03-24 16:15 mtu
-r--r--r-- 1 root root 4096 2011-03-24 16:15 operstate
drwxr-xr-x 2 root root    0 2011-03-24 16:15 power
drwxr-xr-x 2 root root    0 2011-03-24 16:15 statistics
lrwxrwxrwx 1 root root    0 2011-03-24 16:15 subsystem -> ../../../../../class/net
-rw-r--r-- 1 root root 4096 2011-03-24 16:15 tx_queue_len
-r--r--r-- 1 root root 4096 2011-03-24 16:15 type
-rw-r--r-- 1 root root 4096 2011-03-24 16:15 uevent

Hey! There is a file called ifindex! I wonder what that is for? Lets output its values:

$ cat eth0/ifindex 
3

Well look at that, it matches our earlier output from the ioctl call. What are the odds?! You will also notice files such as ‘broadcast’, ‘address’, that provide the broadcast address and MAC address respectively.

Display, Add, Flush arpcache In Linux With ‘arp’

The arp table or arp cache keeps track of all devices on your network that your computer is capable of communicating with. It stores the Layer 2 data ( MAC addresses ) as well as the interface in which the device is connected through (i.e. which interface the traffic came in on ). This table can be viewed, modified, flushed using the arp command in Linux. To view this table you can be running as a normal user, but to make modifications to this table you must be running as a super user aka root because it interfaces with the kernel. The options the arp command provides are:

$ arp --help
Usage:
  arp [-vn]  [<HW>] [-i <if>] [-a] [<hostname>]             <-Display ARP cache
  arp [-v]          [-i <if>] -d  <host> [pub]               <-Delete ARP entry
  arp [-vnD] [<HW>] [-i <if>] -f  [<filename>]            <-Add entry from file
  arp [-v]   [<HW>] [-i <if>] -s  <host> <hwaddr> [temp]            <-Add entry
  arp [-v]   [<HW>] [-i <if>] -Ds <host> <if> [netmask <nm>] pub          <-''-
 
        -a                       display (all) hosts in alternative (BSD) style
        -s, --set                set a new ARP entry
        -d, --delete             delete a specified entry
        -v, --verbose            be verbose
        -n, --numeric            do not resolve names
        -i, --device             specify network interface (e.g. eth0)
        -D, --use-device         read <hwaddr> from given device
        -A, -p, --protocol       specify protocol family
        -f, --file               read new entries from file or from /etc/ethers

Lets look at viewing the current arp cache entries.

View Arp Cache Entries

There are at least two ways to view the current arp cache entries. Using the arp utility we can view the current arp entries. I prefer to use the -n option to view the results immediately. The -n will stop the name resolution and just simply display the IP address, otherwise the system tries to identify the actual name (if specified by dns) of the IP.

$ arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.16.35             ether   00:0e:22:8b:2e:60   C                     eth0
192.168.16.174            ether   00:bb:23:11:13:33   C                     eth0
192.168.16.199            ether   00:1b:24:aa:22:fc   C                     eth0
192.168.16.32             ether   00:30:48:59:6b:48   C                     eth0
192.168.16.1              ether   00:11:39:af:aa:4a   C                     eth0
192.168.16.160            ether   00:26:b9:2c:7a:53   C                     eth0
192.168.16.165            ether   00:1a:a4:1f:b6:7b   C                     eth0

Chatty network. These are all the machines my computer has communicated with. This table is used when sending traffic out, it can identify which interface to send traffic out on. With multiple interfaces this makes more sense.

We can also view the arp entries using /proc/net/arp, doing a cat on that file will produce the same output as running through the arp command.

Perhaps you want to add a static arp entry.

Add Static Arp Entry

To add an arp entry we simply take advantage of the options that the arp command provides. Lets add an arbitrary entry.

# arp -i eth0 -s 10.11.12.13 de:ad:be:ef:fe:ed

Note, I am running as root to add this entry. Lets have a look at the table now:

# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.16.35             ether   00:0e:22:8b:2e:60   C                     eth0
192.168.16.174            ether   00:bb:23:11:13:33   C                     eth0
10.11.12.13              ether   de:ad:be:ef:fe:ed   CM                    eth0
192.168.16.199            ether   00:1b:24:aa:22:fc   C                     eth0
192.168.16.32             ether   00:30:48:59:6b:48   C                     eth0
192.168.16.1              ether   00:11:39:af:aa:4a   C                     eth0
192.168.16.160            ether   00:26:b9:2c:7a:53   C                     eth0
192.168.16.165            ether   00:1a:a4:1f:b6:7b   C                     eth0

Notice line 5 is where my entry landed. Also notice the additional M under the Flags column. Voila, you now have an entry for 10.11.12.13 using interface eth0. If you wanted a different interface simply replace the value from my above example.

Perhaps over time you become sick of the new entry, it doesn’t pay rent or keep the place clean so its time to get rid of it!

Remove Entry From Arp Cache

To remove an entry we can refer to the initial help output I pasted above.

  arp [-v]          [-i <if>] -d  <host> [pub]               <-Delete ARP entry

So in our case, we will be removing 10.11.12.13 from the arp cache.

# arp -i eth0 -d 10.11.12.13

That entered without a hitch, lets verify that it is now gone:

# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.16.35             ether   00:0e:22:8b:2e:60   C                     eth0
192.168.16.174            ether   00:bb:23:11:13:33   C                     eth0
192.168.16.199            ether   00:1b:24:aa:22:fc   C                     eth0
192.168.16.32             ether   00:30:48:59:6b:48   C                     eth0
192.168.16.1              ether   00:11:39:af:aa:4a   C                     eth0
192.168.16.160            ether   00:26:b9:2c:7a:53   C                     eth0
192.168.16.165            ether   00:1a:a4:1f:b6:7b   C                     eth0

Excellent! Unfortunately, the Linux arp command has no global flush option. But wait! You saw how basic the line for a delete is. Lets just make a simple shell script to remove multiple entries.

Flush Arp Cache With This Shell Script

To flush our arp cache we just need to construct a basic shell script to do so. Of course we will have to run as root when executing the command! Here is a simple script to flush the arp cache. Depending on how large your arp cache is, is related to how fast/slow it takes to remove all entries. Also remember that once your system receives a packet from any other host computer, the entry will be added back into the arp cache. The interface entry is optional, arp requires only the IP address during removal.

#!/bin/sh
 
for i in `awk -F ' ' '{ if ( $1 ~ /[0-9{1,3}].[0-9{1,3}].[0-9{1,3}].[0-9{1,3}]/ ) print $1 }' /proc/net/arp` ; 
do 
    arp -d $i 
done

This example takes advantage of the /proc/net/arp file to grab all IP addresses. We could also call arp -n and parse its output for the IP addresses. It just makes more sense to read from a file rather than spawning a shell command to execute arp.

What Is My Interfaces MAC Address?

A MAC address is the unique identifier that is assigned to a network interface to communicate on your physical network. A MAC address consists of 48 bits and is usually displayed as 6 octets. I won’t get into all the grimy details of network topology and the 7 layer OSI model, that’s what Wikipedia is for! Instead I will give you a few examples of how to display your MAC address in Linux, in Windows, and from a C program using ioctl calls.

In Linux we can use the ifconfig command and grep for HW.

Display MAC Address In Linux

To grab the MAC address of an interface in Linux, simply execute your ifconfig command and do a grep for HW.

$ /sbin/ifconfig | grep HW
eth0      Link encap:Ethernet  HWaddr 00:1a:92:1d:dc:9b  
eth1      Link encap:Ethernet  HWaddr 00:1b:21:0a:d2:cf

In this case my MAC address for eth0 is 00:1a:92:1d:dc:9b and for eth1 is 00:1b:21:0a:d2:cf.

Voila, if you wanted to find it for eth0 specifically, just do a “ifconfig eth0 | grep HW”.

Display MAC Address In Windows

In Windows to quickly find the MAC address of your interface, you can bring up a console Windows. Start > Type “cmd” In the Search programs and Files. This will bring up a the command prompt. Enter the command ipconfig /all This will display ethernet information for all interfaces on your windows machine.

C:\Users\Erik> ipconfig /all
Ethernet adapter Local Area Connection:
 
        Connection-specific DNS Suffix  . : localdomain
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter
        Physical Address. . . . . . . . . : 00-0C-29-2B-3E-6D
        Dhcp Enabled. . . . . . . . . . . : Yes
        Autoconfiguration Enabled . . . . : Yes
        IP Address. . . . . . . . . . . . : 192.168.2.104
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.2.1

As shown in the third line, the MAC / Physical address of my virtual interface.

Retrieve MAC Address In C Using A Socket And Ioctl Call

There are a few methods to grab the MAC address of an interface in C. You could actually just do a system or popen call and execute the command I mentioned above (ifconfig | grep HW) and parse the reply. But that’s too easy…and less efficient. Here is a function that takes two parameters as input, the first is the interface name we want to retrieve the MAC address for, and the second is the buffer where we will store the data.

/**
*  get_mac_str()
* interface_name        the name of the interface we want the MAC of
* mac_str               the buffer we will store the result in
* RETURNS: 0 on success; -1 on error.
*/
int get_mac_str(const char *interface_name, char *mac_str) 
{
        int ioctl_data = 0;
        struct ifreq ifr;
 
        // If either pointer is NULL
        if (!ifName || !macAddrStr) return(-1);
 
        // Setup our socket 
        if ( (ioctl_data = socket(PF_INET, SOCK_STREAM, 0)) == -1 ){
                fprintf(stderr, "Could not setup socket.\n");
                return(-1);
        }
 
        // Clear the IFREQ structure
        memset(&ifr, 0, sizeof(ifr));
 
        // Store our interface name in the structure for lookup
        strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name));
        if ( ioctl(ioctl_sid, SIOCGIFHWADDR, &ifr) < 0) 
        {
                fprintf(stderr, "Could not execute ioctl call.\n");
                close(ioctl_data);
                return(-1);
        }
        close(ioctl_data);
 
        // Ensure we are dealing with an Ethernet device
        if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) 
        {
                fprintf(stderr, "Not an ethernet device.\n");
                return(-1);
        }
        // C function to convert address to octet colon form
        ether_ntoa_r((const struct ether_addr *)&(ifr.ifr_hwaddr.sa_data), 
                        mac_str);
        return(0);
}

This last example is much more efficient than executing a system or popen call. A drawback is you must know what the interface name is you are looking for.

Using The Bash Shell Environment

The Bash shell (bourne-again shell) is the most common default shell on most Linux distributions. Having a working knowledge of the environment is useful for any novice Linux user. This article will outline how to view, set, change, and retain environment variables in your shell.

Out-of-the-box Linux installs have a somewhat long list of environment variables that are set for various programs to use, so do not be alarmed by the amount of output.

1. How To View Bash Shell Environment Variables Using env

To view all the variables currently set in your Bash environment you can enter the command env. This will output all variables currently set in your environment. For example:

erik@debian:~$ env
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=X.X.X.X 51688 22
SSH_TTY=/dev/pts/2
USER=erik
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35:*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35:
SSH_AUTH_SOCK=/tmp/ssh-Hdelx27792/agent.27792
MAIL=/var/mail/erik
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
PWD=/home/erik
LANG=en_CA.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/home/erik
LOGNAME=erik
SSH_CONNECTION=X.X.X.X 51688 X.X.X.X 22
LESSOPEN=| /usr/bin/lesspipe %s
DISPLAY=localhost:11.0
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/usr/bin/env

As you can see by the output, there are a large set of values. Some of which make logical sense. For instance, HOME=/home/erik is my home directory upon login. My current working directory of PWD=/home/erik. An interesting variable is the _=/usr/bin/env displays the last command executed by me.

2. Display Specific Environment Variable In Bash Using echo $VAR

Lets say there is a specific variable that you want to view instead of displaying the whole set and grepping for that variable. You can just enter the command echo $VAR where $VAR is the environment variable you want to view.

erik@debian:~$ echo $SHELL
/bin/bash

3. Create Environment Variable Temporarily In Bash

To temporarily create a variable in Bash you can simply enter erik=”hi” . Then doing a echo $erik the prompt will display “hi”. However, in doing so, the variable will not show up in a env output. To modify the variable you can:

erik@debian:~$ echo $erik
hi
erik@debian:~$ erik="no"
erik@debian:~$ echo $erik
no

These methods of creating variables is local only to this shell and will not be seen to child shells.

4. Creating Environment Variable In Bash Using export

For a Bash variable to persist to a child shell, and also show up during an env output, the user must use the export feature.

erik@debian:~$ data=hi
erik@debian:~$ echo $data
hi
erik@debian:~$ env | grep data
erik@debian:~$ export data
erik@debian:~$ env | grep data
data=hi

In this example I have created an environment variable called data in which a child shell could use. Keep in mind that this variable is only present in this session. If you were to logout, then log back in, the data variable would disappear.

5. Removing Environment Variable In Bash Using unset

At this point we now have the data variable in our environment. But perhaps we want to remove it because it smells bad. Its actually quite easy to do so.

erik@debian:~$ echo $data
hi
erik@debian:~$ env | grep data
data=hi
erik@debian:~$ unset data
erik@debian:~$ echo $data
 
erik@debian:~$ env | grep data
erik@debian:~$

So in this example I showed the data variable is set, and can be found in our environment. I then ran the unset command to remove the variable. I then tried to display the contents of our variable, and as you can see it no longer has a value and is no longer part of our environment.

Set File Permissions With chmod In Linux

If you have ever needed to protect your files, or set a directory to read only in Linux, you have probably used chmod. If you didn’t, then you probably wished that you had heard of chmod. Chmod stands for change mode and allows the user to modify access permissions to specific files.

To display a file or directories current permissions you can use the ls command. For example:

$ ls -l
-rw-r--r--  1 erik erik       1014 2010-10-28 13:30 taps.sh

The first column of -rw-r–r– is actually showing you the current file permission for taps.sh . The output is actually broken into four parts.

-| rw- | r– | r– . The first column is used to identify:

  • – denotes a regular file
  • d denotes a directory
  • b denotes a block special file
  • c denotes a character special file
  • l denotes a symbolic link
  • p denotes a named pipe
  • s denotes a domain socket

The second column outlines what the current users permissions are, the third column outlines what group members are allowed to do, and the forth column outlines what other users may do. The following table outlines in detail the column information. The chmod functions as:

$ chmod [Reference][Operator][Mode] file1 file2 etc.

ReferenceClassDescription
uuserthe current file owner
ggroupthe file group members
oothersgeneric users who are not part of the group or owner of the file
aallugo is equivalent to the ‘a’

The chmod command will use the following operations to modify the user, group, and other fields. For example:

OperatorDescription
+the addition sign tells chmod to add the value
the dash will remove the modes from the class we specify
=this sets the exact mode for the file

The modes indicate which permissions are to be set for read, write, execute. For example:

ModeNameDescription
rreadsets the read permission
wwriteuse to write to a file or directory
xexecuteuse to set the execute for a file or directory

Here are some examples using the symbolic notation of changing the file permissions.

Add Read and Write Permissions to User and Group classes

For example:

$ ls -l taps.sh
-rw-r--r-- 1 erik erik 1014 2010-10-28 13:30 taps.sh
$ chmod ug+rw taps.sh
$ ls -l taps.sh
-rw-rw-r-- 1 erik erik 1014 2010-10-28 13:30 taps.sh

Notice in this example, only the group class (third column) changed because I already had write permissions as the current user.

Add Read, Write, Execute to User and Group

Lets say we want taps.sh to have all permissions to those who are lucky enough to be in our group, or be us. To do so:

$ chmod +rwx taps.sh
$ ls -l taps.sh
-rwxrwxr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh

Using the chmod +rwx command, we ‘add’ the read, write, and execute option to our file.

Well that is all great, but for me I usually want to other make a file read only for myself, or executable for anyone. This can be done using numerics rather than using these symbolic notations mentioned above.

Numeric Example For Read-Only

The numeric’s group values together, for example:

#Permission
7full
6read and write
5read and execute
4read only
3write and execute
2write only
1execute only
0none

I use chmod 644 filename quite often. This sets the permissions to read only for group and other, i.e. only the user may read or write to the file.

$ ls -l taps.sh
-rwxr-xr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh
$ chmod 644 taps.sh 
$ ls -l taps.sh
-rw-r--r-- 1 erik erik 1014 2010-10-28 13:30 taps.sh

Numeric Example For Execute

Another favourite of mine is execute by anyone. This comes in the form of 755.

$ ls -l taps.sh
-rw-r--r-- 1 erik erik 1014 2010-10-28 13:30 taps.sh
$ chmod 755 taps.sh 
$ ls -l taps.sh
-rwxr-xr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh

So the 755, referring to the table means. User = 7 = all, Group = 5 = read and execute, Other = 5 = read and execute, as shown in the ls output above. This way you can mix and match the numerics, if you want it open to everyone you can use 777.

Change Permissions Recursively With ‘chmod -R’

If you want to set the permissions for all files under a directory to the same setting, you can pass the -R command in front of the permission you would like to use.

$ chmod -R 777 /home/erik/

This will set every file under my home directory to ‘all’, i.e. read, write, execute by anyone.

Hopefully this makes sense to you. Rather than giving you a huge set of examples, I hope I have taught you how to fish!

Change File Owner and Group With chown

Every file on a Linux system has an owner and is associated with a group. Yesterday I talked about setting file permissions on your Linux system, I will now discuss the basics of owner and group permissions. These modifications can be done using the chown command while running as the root user.

To view a file’s current owner and group you can use the ls -l command.

$ ls -l taps.sh 
-rwxr-xr-x 1 erik users 1014 2010-10-28 13:30 taps.sh

In the above example, ‘erik’ is the owner and ‘users’ is the group that the file is currently within. This means that any other user that is part of the group ‘users’ will also have r-x access.

What Does chown Do?

Excerpt from the chown manual page:
chown changes the user and/or group ownership of each given file. If only an owner (a user name or numeric user ID) is given, that user is made the owner of each given file, and the files’ group is not changed. If the owner is followed by a colon and a group name (or numeric group ID), with no spaces between them, the group owner‐ship of the files is changed as well. If a colon but no group name follows the user name, that user is made the owner of the files and the group of the files is changed to that user’s login group. If the colon and group are given, but the owner is omitted, only the group of the files is changed; in this case, chown performs the same function as chgrp. If only a colon is given, or if the entire operand is empty, neither the owner nor the group is changed.

To better understand that here are a few examples:

# chown erik:cdrom taps.sh 
# ls -l taps.sh 
-rwxr-xr-x 1 erik cdrom 1014 2010-10-28 13:30 taps.sh
# chown erik:erik taps.sh 
# ls -l taps.sh 
-rwxr-xr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh

As you can see I changed the group to ‘cdrom’ then changed it back to ‘erik’. In doing so, none of my file permissions changed, but I did become part of the cdrom group, which means I may have gained access to other files that were also part of the ‘cdrom’ group.

If I only specify the colon after the user setting, then the file will automatically take use the users login group as the default. For example:

# ls -l taps.sh 
-rwxr-xr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh
# chown erik:cdrom taps.sh 
# ls -l taps.sh 
-rwxr-xr-x 1 erik cdrom 1014 2010-10-28 13:30 taps.sh
# chown erik: taps.sh 
# ls -l taps.sh 
-rwxr-xr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh

You can also set the file to a group that does not even necessarily exist.

# chown erik:1234 taps.sh 
# ls -l taps.sh 
-rwxr-xr-x 1 erik 1234 1014 2010-10-28 13:30 taps.sh
# chown erik: taps.sh 
# ls -l taps.sh 
-rwxr-xr-x 1 erik erik 1014 2010-10-28 13:30 taps.sh

As you can see the 1234 in yellow identifying my group.

Recursive Group Change

To recursively change all files within a directory you may use the -R before setting the user:group option.

# chown -R erik:1234 /home/erik/

This will change all files within my home directory to now become part of the 1234 group. Yay.

The purpose for group association permits certain users the ability to use devices or see certain files on a computer. For instance, I am currently associated with a set of groups:

$ groups
erik adm dialout cdrom plugdev lpadmin admin sambashare

Thus, I have access to certain files or devices because I am now part of that group.

Utilize Bash Aliases for Quicker SSH Connects

If you find yourself constantly connecting and disconnecting to different computers using SSH it is useful to setup aliases to speed up this process. There are a few ways of doing this, including creating a config file within your .ssh directory and using the .bashrc file to create aliases on boot-up. Okay, lets get down to the nitty – gritty.

1. Setup A ‘config’ File In Your .ssh Directory

For those computers that you plan to connect to quite often, create a config file in ~/.ssh. Otherwise known as your home directories .ssh folder.

:~/.ssh$ cat config 
Host data
    User erik
    HostName 192.168.12.45
    Port 22
    ForwardX11 yes
 
Host htpc
    User erik
    HostName 123.17.51.92
    Port 22
    ForwardX11 yes
 
Host orion
   User gregor
   HostName 192.16.22.134
   Port 22
   ForwardX11 yes

Take note of the Host name. These will be used as aliases to the HostName IP address, so rather than typing the IP address you can simply type the name.

2. Add Bash Code To Create Aliases on Boot

Now lets head over to your .bashrc file and add a simple line which will use the config file above to create aliases for quick ssh usage. At the end of your .bashrc file add this line:

for name in `sed -n "/^Host/s/^Host //p" ~/.ssh/config`; do alias $name="ssh $name"; done

Breaking this down, we cycle through the config file from the .ssh directory and create an alias for each pairing. So each alias will be orion=ssh orion. Lets check the aliases:

alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias data='ssh data'
alias grep='grep --color=auto'
alias htpc='ssh htpc'
alias ls='ls --color=auto'
alias orion='ssh orion

This simple substitution will replace orion with the ssh orion. In doing so, SSH will check the config file within the .ssh directory and substitute the HostName with the actual IP address, and voila.

3. Execute SSH

Now executing the command:

$ htpc erik@123.17.51.92’s password:

If I had already copied my authorized key to the server, then I would not even be prompted for the password. This simple setup saves a lot of time, especially if you find yourself constantly connecting and disconnecting from remote servers, or have to copy files back and forth a lot. You can simple run commands like:

$ scp data.txt htpc:/tmp/

This is a lot nicer than having to remember the IP address and which username is for that server.