Monday, August 15, 2011

Using Function getservent(3)


If you have used some of the password database functions like getpwent(3) before, the functions about to be described here will seem similar. The synopsis of the getservent(3) function is as
follows:

#include <netdb.h>

struct servent *getservent(void);

For each call to getservent(3), you are returned a pointer to a structure that represents one entry from the /etc/services file. When the end-of-file is reached, a NULL pointer is returned
(but see the caution that follows). If an error occurs, a NULL pointer is also returned, with the reason for the error posted to variable errno.

CAUTION
Even when the value of errno is zeroed prior to calling getservent(3), when end-of-file is reached and indicated by a NULL return pointer, the errno value for Red Hat Linux 6.0 is code ENOENT. Under other UNIX operating systems, such as HP-UX 10.2 and Sun Solaris 5.5.1, the errno value is left at zero when end-of-file is returned. This leads the author to speculate that this behavior is a bug, which might be corrected in a later release of Linux. When the pointer returned is not NULL, it points to the structure servent, as illustrated in Listing below

Example
The struct servent Structure

struct servent {
   char *s_name;     // official service name
   char **s_aliases; // alias list
   int s_port;       // port number
   char *s_proto;    // protocol to use
}

CAUTION
Be careful to note that the value in s_port is already in network byte order. To print this value in printf(3), for example, make sure you convert this value back to host order by using ntohs(sp->s_port), for example. When setting the port number in a socket address, you merely assign this value as-is, since the port number is expected to be in network byte order. Listing later in this post shows an example of this use.

The structure member s_aliases is actually an array of character pointers. If sp points to the structure, and x is an int subscript, then you can iterate through each alias sp->s_alias[x], until you reach a NULL pointer. A NULL pointer marks the end of this alias list. Listing 7.2 shows a simple program that lists all /etc/services entries and their aliases, if any.

/*
 * getservent.c:
 * Example getservent(3) program:
 */
  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <errno.h>
  #include <string.h>
  #include <time.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>


  int main(int argc, char **argv) {
     int x;
     struct servent *sp;

     for (;;) {
        errno = 0;
        if ( !(sp = getservent()) ) {
           break;
        }

        printf("%s:\n"
               "\tPort: %d\n"
               "\tProtocol: %s\n"
               "\tAliases: ",
               sp->s_name,
               ntohs(sp->s_port),
               sp->s_proto);
        for ( x=0; sp->s_aliases[x] != NULL; ++x ) {
           printf("%s ",sp->s_aliases[x]);
        }
        putchar('\n');
     }

     if ( errno != 0 && errno != ENOENT ) { /* For RH-6.0 */
        fprintf(stderr,
                "%s: getservent(3) %d\n",
                strerror(errno),errno);
     }
     return 0;
  }

/*
 * OUTPUT
 * 
[sgupta@rhel55x86 chap7]$ gcc -o getservent getservent.c
[sgupta@rhel55x86 chap7]$ ./getservent
tcpmux:
        Port: 1
        Protocol: tcp
        Aliases:
tcpmux:
        Port: 1
        Protocol: udp
        Aliases:
rje:
        Port: 5
        Protocol: tcp
        Aliases:
rje:
        Port: 5
        Protocol: udp
        Aliases:
echo:
        Port: 7
        Protocol: tcp
        Aliases:
echo:
        Port: 7
        Protocol: udp
        Aliases:
discard:
        Port: 9
        Protocol: tcp
        Aliases: sink null
 iqobject:
        Port: 48619
        Protocol: udp
        Aliases:
[sgupta@rhel55x86 chap7]$
 */

The error message ''Broken pipe" in Listing 7.3 is simply due to the head command being used (it closed the pipe early). There are some companions to the getservent(3) function, and these will be covered next.

No comments:

Post a Comment