Linux – fast file system search with locate and updatedb

Typically

find

command is the most commonly used search utility in Linux. GNU find searches the directory tree rooted at each given starting-point by evaluating the given expression from left to right, according to the rules of precedence.

There is an alternative and fast way of searching for files and directories in Linux though and that is the

locate

command, and it goes hand in had with the

updatedb

utility which keeps an indexed database of the files in your system. The locate tools simply reads the database created by updatedb.

Installation –

sudo apt-get -y install mlocate           [Debian/Ubuntu]
sudo yum -y install mlocate               [CentOS/Redhat]

updatedb is usually has a daily cron job to update the default database(‘/var/lib/mlocate/mlocate.db’). To manually update the database, you can manually run the ‘updatedb’ command first. That will take a while depending on the number of files you have on your system, the last time updatedb ran or other file related changes.

First time – update the default database, run any of the below command depending on your requirements. Most likely, the first and/or third command is what you need.

updatedb
updatedb -U /some/path      # if interested in indexing specific directory that you will search frequently.
updatedb -v                 # verbose mode

Time to search
locate command is the utility to search for entries in a mlocate database.

Some examples –

locate cron         # any file or directory with cron in its name
locate -i cron      # case insensitive
locate -c cron      # only print number of found entries
locate -r 'cron$'   # regex - only files or directories with names ending in cron.
locate -r '/usr/.*ipaddress.*whl$'   # regex for eg. /usr/share/python-wheels/ipaddress-0.0.0-py2.py3-none-any.whl

locate can also print the statistics on count of files, directories, size used by updatedb default directory.

root@cloudclient:/tmp# locate -S
Database /var/lib/mlocate/mlocate.db:
	28,339 directories
	185,661 files
	11,616,040 bytes in file names
	4,481,938 bytes used to store database

Customizing updatedb
updatedb can be customized to output the search database to a different file than the default db, in addition to this we can change the directory to index other than the default root tree. We can then tell locate to use the custom db.

In the below example, I am indexing the files under home directory in /tmp/home.db database, and then run locate to use this custom DB. As you can see the number of files and directories is way lower and thus the search much faster although since it has to scan specific directory.

$ updatedb -U ~ -o /tmp/home.db
$ locate -d /tmp/home.db cron
$ locate -d /tmp/home.db -S
Database /tmp/home.db:
	3,530 directories
	29,943 files
	2,635,675 bytes in file names
	762,621 bytes used to store database

References –

https://linux.die.net/man/8/updatedb

https://linux.die.net/man/1/locate

Infoblox dns management – using the REST api with Python

Infoblox provides a product to manage your DNS, DHCP and IPAM through a single management interface. In this short article, I will walk you through automating some of the day to day operations work in managing DNS using Infoblox REST API. The REST based api tool can be also used to manage DHCP and IPAM.

The Infoblox WAPI is the REST interface we will interact with. In a highly available DNS setup, the WAPI requests go to the HA Grid Master IP or hostname. The requests typically have arguments and body. A great resource that helped me get started is a github repo of Infoblox Api python modules.

Clone the Infoblox Python modules repo to get started –

cd /tmp
git clone https://github.com/Infoblox-Development/Infoblox-API-Python.git

The class initialization of infoblox api (infoblox.py ) holds certain parameters, including ones used for authentication. Set this values according to your environment.

        """ Class initialization method
        :param iba_ipaddr: IBA IP address of management interface
        :param iba_user: IBA user name
        :param iba_password: IBA user password
        :param iba_wapi_version: IBA WAPI version (example: 1.0)
        :param iba_dns_view: IBA default view
        :param iba_network_view: IBA default network view
        :param iba_verify_ssl: IBA SSL certificate validation (example: False)
        """

Once you have the right parameters, you can write scripts which utilize the infoblox.py module. Here is a simple python script to get A record record details, given an IP address and domain.

Make sure you work under the directory where you cloned the infoblox github repo –

Script path: /tmp/get_a_record.py
Usage example: python /tmp/get_a_record.py 192.168.100.2  mail-gateway.example.net

Script to pull A record details of a DNS zone –

#!/usr/bin/env python

import infoblox
import sys
import requests
import json
import socket

def Usage():
    print "{0} {1} {2}".format(sys.argv[0], 'IP-ADDRESS','FQDN')
    sys.exit(1)

if len(sys.argv)<3:
    Usage()

myip=sys.argv[1]
myfqdn=sys.argv[2].lower()
try:
    socket.inet_aton(myip)
except:
    print "Not valid IP."
    sys.exit(1)

# Create a session
ibx_server='grid-master.example.net'
ibx_username='dns-admin'
ibx_password='admin-secret'
ibx_version='1.6'
ibx_dns_view='default'
ibx_net_view='default'

ibx=infoblox.Infoblox(ibx_server, ibx_username, ibx_password, ibx_version, ibx_dns_view, ibx_net_view, iba_verify_ssl=False)

# Get address details
payload='{"ipv4addr": '  + json.JSONEncoder().encode(myip) + ',' + '"name": ' + json.JSONEncoder().encode(myfqdn) + '}'
my_url='https://' + ibx.iba_host + '/wapi/v' + ibx.iba_wapi_version + '/record:a'
r = requests.get(url=my_url, auth=(ibx.iba_user, ibx.iba_password), verify=ibx.iba_verify_ssl, data=payload)
data = r.json()
print data

You can also use the existing class methods defined in the infoblox module. In the below example, I am using the ‘create_cname_record’ method to create an Alias.

ibx=infoblox.Infoblox(ibx_server, ibx_username, ibx_password, ibx_version, ibx_dns_view, ibx_net_view, iba_verify_ssl=False)
canonical='www.example.net'
name='web-server1.example.net'
ibx.create_cname_record(canonical, name)

If you can’t find the particular method in the infoblox module, it should’t be difficult to write one. Follow the api reference documentation on the structure of the WAPI Api calls.

Note – in some cases, you have to make multiple api calls to perform certain tasks. One example is updating the TTL for a DNS entry. On the first call, you need to get the host reference id and on second call update the TTL. The below example shows a simple python script to update the TTL (in seconds) for an existing FQDN entry.

Usage example - python update_ttl.py mail-gateway.example.net 600

update_ttl.py script –

#!/usr/bin/env python

import infoblox
import sys
import json
import requests

def Usage():
    print "{0} {1} {2}".format(sys.argv[0], 'ExistingFQDN', 'TTL')
    sys.exit(1)

if len(sys.argv)<3:
    Usage()

oldname=sys.argv[1].lower()
newttl=int(sys.argv[2])

# Create a session
ibx_server='grid-master.example.net'
ibx_username='dns-admin'
ibx_password='admin-secret'
ibx_version='1.6'
ibx_dns_view='default'
ibx_net_view='default'
ibx=infoblox.Infoblox(ibx_server, ibx_username, ibx_password, ibx_version, ibx_dns_view, ibx_net_view, iba_verify_ssl=False)
# Validate oldname exists
ibxhost=ibx.get_host(oldname)
if ibxhost['name'] != oldname:
    print oldname + " does not exist."
    sys.exit(1)
# update data
host_ref=ibxhost['_ref']
payload=json.dumps({'ttl':newttl})
my_url = 'https://' + ibx.iba_host + '/wapi/v' + ibx.iba_wapi_version + '/' + host_ref
r = requests.put(url=my_url, auth=(ibx.iba_user, ibx.iba_password), verify=ibx.iba_verify_ssl, data=payload)
if r.ok:
    print("TTL updated successfully.")
else:
    print("Error - {}".format(r.content))

References –

Products page – https://www.infoblox.com/products/dns/

Rest API documentation – https://www.infoblox.com/wp-content/uploads/infoblox-deployment-infoblox-rest-api.pdf

HA GRID MASTER – https://docs.infoblox.com/display/NAG8/Chapter+5+Deploying+a+Grid#Chapter5DeployingaGrid-bookmark587

C programming Language – Code snippets

C Programming Language, 2nd Edition

Compiling and running the sample codes using gcc :

gcc sample.c -o sample
./sample

Chapter 1 – Introductory tutorial : Input/output, characters, strings

0. Hello World!

#include<stdio.h>

int main()

{

  printf("Hello World\n");
  return 0;
}

1. Word counter


/* word counter */
#include<stdio.h>

#define  IN 1  //inside a word
#define  OUT   0  //outside a word

int main()

{
  int c,nl,nw,nc,state;
  state=OUT;
  nl=nw=nc=0;

  while((c=getchar())!=EOF)
   {
      ++nc;
      if(c=='\n') ++nl;
      if (c==' ' || c == '\n' || c=='\t') state=OUT;
      else if (state==OUT)
         {
           state=IN;
           ++nw;
          }
        }
      printf("lines=%d words=%d characters=%d\n",nl,nw,nc);
 return 0;
}

2. Convert Fahrenheit to Celsius


#include<stdio.h>

#define  LOWER 0
#define  UPPER 300
#define  STEP  20

int main()

  {
     int fahr;
     for (fahr = LOWER; fahr <= UPPER; fahr=fahr + STEP)
         printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
     return 0;
 }


3. Count characters


/* character counter */
#include<stdio.h>

int main()

{
   short int nc;
   for(nc=0; getchar()!=EOF ; ++nc);
   printf("%d\n",nc);
   return 0;
}

4. Count characters by type – digits, white spaces etc.


/* count digits, white space, others */
#include<stdio.h>

int main()
 {
   int c,i,nwhite,nother;
   int ndigit[10];

   nwhite=nother=0;
   for(i=0; i < 10; ++i)  ndigit[i]=0;

   while((c=getchar())!=EOF)
     if(c>='0' && c<='9') ++ndigit[c-'0'];
     else if (c==' ' || c=='\n' || c=='\t') ++nwhite;
     else  ++nother;

   printf("digits=");
   for(i=0;i<10;++i) printf(" %d",ndigit[i]);
   printf(",white space=%d, other=%d\n",nwhite,nother);

return 0;
}

5. Copy input to output terminal


/* copy input to output 1 */
#include<stdio.h>

int main()

{
   int c;
   c = getchar();
   while ( c!=EOF)
     {
       putchar(c);
       c = getchar();
     }
 return 0;
}

6. Copy input to output terminal (shorter version)

/* copy input to output */
#include<stdio.h>

int main()
{
   int c;
   while((c=getchar())!=EOF)
     putchar(c);
   return 0;
}

7. Print longest line


#include<stdio.h>

#define  MAXLINE  1000  /* maximum input line length */

int getline(char line[], int maxline);
void copy(char to[], char from[]);

/* print the longest input line */

int main()

{
  int len;  /* current line length */
  int max;  /* maximum length seen so far */
  char line[MAXLINE];   /* current input line */
  char longest[MAXLINE];   /*longest line saved here */

  max=0;
  while((len=getline(line,MAXLINE))>0)
    if(len>max)
       { max=len;
         copy(longest,line);
       }
 if(max>0)  /*there was a line*/
  printf("Longest Line from input is:\n%s\n",longest);
  printf("Line length is: %d characters\n",max);

return 0;
}


/*getline: read a line into s, return length */

int getline(char s[], int lim)
{
  int c,i;
  for(i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
   s[i]=c;
 if(c=='\n') {
  s[i]=c;
  ++i;
  }
 s[i]='\0';
 return i;
}

/*copy: copy 'from' into 'to'; assume 'to' is big enough */

void copy(char to[], char from[])
{
  int i;
  i=0;
  while((to[i]=from[i]) != '\0')
    ++i;
}

8. Print longest line – improved


#include<stdio.h>

#define  MAXLINE  1000  /* maximum input line length */

int max;
char line[MAXLINE];
char longest[MAXLINE];

int getline(char line[], int maxline);
void copy(char to[], char from[]);

/* print the longest input line */

int main()

{
  int len;  /* current line length */
  extern int max; /* maximum length seen so far */
  extern char longest[MAXLINE];  /*longest line saved here */

  max=0;
  while((len=getline(line,MAXLINE))>0)
    if(len>max)
       { max=len;
         copy(longest,line);
       }
 if(max>0)  /*there was a line*/
  printf("Longest Line from input is:\n%s\n",longest);
  printf("Line length is: %d characters\n",max);

return 0;
}


/*getline: read a line into s, return length */

int getline(char s[], int lim)
{
  int c,i;
  extern char line[];
  for(i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
   s[i]=c;
 if(c=='\n') {
  s[i]=c;
  ++i;
  }
 s[i]='\0';
 return i;
}

/*copy: copy 'from' into 'to'; assume 'to' is big enough */

void copy(char to[], char from[])
{
  int i;
  extern char line[], longest[];
  i=0;
  while((to[i]=from[i]) != '\0')
    ++i;
}

9. Power function


#include<stdio.h>

int power(int m, int n);

/* test power function */

int main()

{
  int i;
  for(i=0; i<10; ++i)
   printf("%d %d %d\n",i,power(2,i),power(-3,i));
 return 0;
}

int power(int base, int n)
 {
   int i,p=1;
   for(i=1;i<=n;++i)
     p*=base;
   return p;
 }

10. Reverse string


#include<stdio.h>

#define  MAXLINE  1000

int size=0;
void reverse(char line[], int lim);
int main()

{ extern int size;
  char line[MAXLINE];
  reverse(line,MAXLINE);
  while(size) putchar(line[--size]);
  printf("\n");
  return 0;
}

void reverse(char line[], int lim)

{
 extern int size;
 int c;
 while((c=getchar())!=EOF ) line[size++]=c;
 line[size]='\0';

}

11. Get digits only


#include<stdio.h>

int atoi(char s[]);

int main()

{
  char str[]="12a4c5 ";
  int i=0,n=0;

 while(str[i]!='\0')
   {
      if(str[i]>='0' && str[i]<='9') { n=10*n+(str[i]-'0'); i++; }
      else
       { i++; continue; }
   }
 printf("number=%d\n",n);
 return 0;

 }

12. Fahrenheit to Celsius table

/* print Fahrenheit-Celsius table for fahr =0,20,40,....,300 */

#include<stdio.h>

int main()

{
  int fahr, celsius;
  int lower, upper, step;
  lower = 0;
  upper = 300;
  step = 20;

  fahr = lower;
  while( fahr <= upper)
   {
      celsius = 5 * (fahr - 32) / 9;
      printf("%d\t%d\n", fahr, celsius);
      fahr = fahr + step;
   }

return 0;
}

Reference –

https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628#reader_0131103628