Articles On Testing

Wecome to http://www.articlesontesting.com !!!

Articles On Testing

Wecome to http://www.articlesontesting.com !!!

Articles On Testing

Wecome to http://www.articlesontesting.com !!!

Articles On Testing

Wecome to http://www.articlesontesting.com !!!

Articles On Testing

Wecome to http://www.articlesontesting.com !!!

Showing posts with label File handling in Linux. Show all posts
Showing posts with label File handling in Linux. Show all posts

File Handling in Linux 12


Job Control example

/* functions to spawn foreground/background jobs */
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
 
/* Some of the functions below fail if the control tty can't be
* located, or if the calling process isn't in the foreground. In the
* first case, we are assuming that a foreground process will have the
* ctty open on either stdin, stdout or stderr, and we return ENOTTY
* if it isn't. In the second case, we return EPERM if a
* non-foreground process attempts to put something into the
* foreground (probably overly paranoid) except for the special case
* of foreground_self().
*/
 
/* assign the terminal (open on ctty) to a specific pgrp. This wrapper
* around tcsetpgrp() is needed only because of extreme bogosity on the
* part of POSIX; conforming systems deliver STGTTOU if tcsetpgrp is
* called from a non-foreground process (which it almost invariably is).
* A triumph of spurious consistency over common sense.
*/
 
int assign_terminal(int ctty, pid_t pgrp)
{
    sigset_t sigs;
    sigset_t oldsigs;
    int rc;
 
    sigemptyset(&sigs);
    sigaddset(&sigs,SIGTTOU);
    sigprocmask(SIG_BLOCK, &sigs, &oldsigs);
 
    rc = tcsetpgrp(ctty, pgrp);
 
    sigprocmask(SIG_SETMASK, &oldsigs, NULL);
 
    return rc;
}
 
/* Like fork(), but does job control. FG is true if the newly-created
* process is to be placed in the foreground. (This implicitly puts
* the calling process in the background, so watch out for tty I/O
* after doing this.) PGRP is -1 to create a new job, in which case
* the returned pid is also the pgrp of the new job, or specifies an
* existing job in the same session (normally used only for starting
* second or subsequent process in a pipeline).  */
 
pid_t spawn_job(int fg, pid_t pgrp)
{
    int ctty = -1;
    pid_t pid;
 
    /* If spawning a *new* foreground job, require that at least one
     * of stdin, stdout or stderr refer to the control tty, and that
     * the current process is in the foreground.
     * Only check for controlling tty if starting a new foreground
     * process in an existing job.
     * A session without a control tty can only have background jobs 
     */
    
    if (fg)
    {
        pid_t curpgrp;
 
        if ((curpgrp = tcgetpgrp(ctty = 2)) < 0
            && (curpgrp = tcgetpgrp(ctty = 0)) < 0
            && (curpgrp = tcgetpgrp(ctty = 1)) < 0)
            return errno = ENOTTY, (pid_t)-1;
 
        if (pgrp < 0 && curpgrp != getpgrp())
            return errno = EPERM, (pid_t)-1;
    }
 
    switch (pid = fork())
    {
        case -1: /* fork failure */
            return pid;
 
        case 0: /* child */
            
            /* establish new process group, and put ourselves in
             * foreground if necessary 
             * unclear what to do if setpgid fails ("can't happen")
             */
 
            if (pgrp < 0)
                pgrp = getpid();
 
            if (setpgid(0,pgrp) == 0 && fg)
                assign_terminal(ctty, pgrp);
 
            return 0;
 
        default: /* parent */
 
            /* establish child process group here too. */
 
            if (pgrp < 0)
                pgrp = pid;
 
            setpgid(pid, pgrp);
 
            return pid;
    }
 
    /*NOTREACHED*/
}
 
/* Kill job PGRP with signal SIGNO */
 
int kill_job(pid_t pgrp, int signo)
{
    return kill(-pgrp, signo);
}
 
/* Suspend job PGRP */
 
int suspend_job(pid_t pgrp)
{
    return kill_job(pgrp, SIGSTOP);
}
 
/* Resume job PGRP in background */
 
int resume_job_bg(pid_t pgrp)
{
    return kill_job(pgrp, SIGCONT);
}
 
/* resume job PGRP in foreground */
 
int resume_job_fg(pid_t pgrp)
{
    pid_t curpgrp;
    int ctty;
 
    if ((curpgrp = tcgetpgrp(ctty = 2)) < 0
        && (curpgrp = tcgetpgrp(ctty = 0)) < 0
        && (curpgrp = tcgetpgrp(ctty = 1)) < 0)
        return errno = ENOTTY, (pid_t)-1;
 
    if (curpgrp != getpgrp())
        return errno = EPERM, (pid_t)-1;
 
    if (assign_terminal(ctty, pgrp) < 0)
        return -1;
 
    return kill_job(pgrp, SIGCONT);
}
    
 
/* put ourselves in the foreground, e.g. after suspending a foreground
* job
*/
 
int foreground_self()
{
    pid_t curpgrp;
    int ctty;
 
    if ((curpgrp = tcgetpgrp(ctty = 2)) < 0
        && (curpgrp = tcgetpgrp(ctty = 0)) < 0
        && (curpgrp = tcgetpgrp(ctty = 1)) < 0)
        return errno = ENOTTY, (pid_t)-1;
 
    return assign_terminal(ctty, getpgrp());
}
 
/* closeall() - close all FDs >= a specified value */
 
void closeall(int fd)
{
    int fdlimit = sysconf(_SC_OPEN_MAX);
 
    while (fd < fdlimit)
        close(fd++);
}
 
/* like system(), but executes the specified command as a background
* job, returning the pid of the shell process (which is also the pgrp
* of the job, suitable for kill_job etc.)
* If INFD, OUTFD or ERRFD are non-NULL, then a pipe will be opened and
* a descriptor for the parent end of the relevent pipe stored there.
* If any of these are NULL, they will be redirected to /dev/null in the
* child.
* Also closes all FDs > 2 in the child process (an oft-overlooked task)
*/
 
pid_t spawn_background_command(const char *cmd,
                               int *infd, int *outfd, int *errfd)
{
    int nullfd = -1;
    int pipefds[3][2];
    int error = 0;
 
    if (!cmd)
        return errno = EINVAL, -1;
 
    pipefds[0][0] = pipefds[0][1] = -1;
    pipefds[1][0] = pipefds[1][1] = -1;
    pipefds[2][0] = pipefds[2][1] = -1;
 
    if (infd && pipe(pipefds[0]) < 0)
        error = errno;
    else if (outfd && pipe(pipefds[1]) < 0)
        error = errno;
    else if (errfd && pipe(pipefds[2]) < 0)
        error = errno;
 
    if (!error && !(infd && outfd && errfd))
    {
        nullfd = open("/dev/null",O_RDWR);
        if (nullfd < 0)
            error = errno;
    }
 
    if (!error)
    {
        pid_t pid = spawn_job(0, -1);
        switch (pid)
        {
            case -1: /* fork failure */
                error = errno;
                break;
                
            case 0: /* child proc */
                
                dup2(infd ? pipefds[0][0] : nullfd, 0);
                dup2(outfd ? pipefds[1][1] : nullfd, 1);
                dup2(errfd ? pipefds[2][1] : nullfd, 2);
                closeall(3);
                
                execl("/bin/sh","sh","-c",cmd,(char*)NULL);
 
                _exit(127);
 
            default: /* parent proc */
 
                close(nullfd);
                if (infd)
                    close(pipefds[0][0]), *infd = pipefds[0][1];
                if (outfd)
                    close(pipefds[1][1]), *outfd = pipefds[1][0];
                if (errfd)
                    close(pipefds[2][1]), *errfd = pipefds[2][0];
 
                return pid;
        }
    }
 
    /* only reached if error */
 
    {
        int i,j;
        for (i = 0; i < 3; ++i)
           for (j = 0; j < 2; ++j)
                if (pipefds[i][j] >= 0)
                    close(pipefds[i][j]);
    }
    
    if (nullfd >= 0)
        close(nullfd);
 
    return errno = error, (pid_t) -1;
}
 
/*--------------------------------------------------------------------*/
/* This bit is a somewhat trivial example of using the above.         */
 
pid_t bgjob = -1;
volatile int signo = 0;
 
#ifndef WCOREDUMP
/* If WCOREDUMP is missing, you might want to supply a correct 
  * definition for your platform (this is usually (status & 0x80) but
  * not always) or punt (as in this example) by assuming no core dumps.
  */
# define WCOREDUMP(status) (0)
 
 To Look for similar posts on File handling in Linux explore the following links from the same blog as well.
 


File Handling in Linux 11


Reading the process table -- SUNOS 4 version

#define _KMEMUSER
#include <sys/proc.h>
#include <kvm.h>
#include <fcntl.h>

char regexpstr[256];
#define INIT            register char *sp=regexpstr;
#define GETC()          (*sp++)
#define PEEKC()         (*sp)
#define UNGETC(c)       (--sp)
#define RETURN(pointer) return(pointer);
#define ERROR(val)
#include <regexp.h>

pid_t
getpidbyname(char *name,pid_t skipit)
{
    kvm_t *kd;
    char **arg;
    int error;
    char *p_name=NULL;
    char expbuf[256];
    char **freeme;
    int curpid;
    struct user * cur_user;
    struct user myuser;
    struct proc * cur_proc;

 
    if((kd=kvm_open(NULL,NULL,NULL,O_RDONLY,NULL))==NULL){
        return(-1);
    }
    sprintf(regexpstr,"^.*/%s$",name);
    compile(NULL,expbuf,expbuf+256,'\0');

    while(cur_proc=kvm_nextproc(kd)){
        curpid = cur_proc->p_pid;
        if((cur_user=kvm_getu(kd,cur_proc))!=NULL){
            error=kvm_getcmd(kd,cur_proc,cur_user,&arg,NULL);
            if(error==-1){
                if(cur_user->u_comm[0]!='\0'){
                    p_name=cur_user->u_comm;
                }
            }
            else{
                p_name=arg[0];
            }
        }
        if(p_name){
            if(!strcmp(p_name,name)){
                if(error!=-1){
                    free(arg);
                }
                if(skipit!=-1 && ourretval==skipit){
                    ourretval=-1;
                }
                else{
                    close(fd);
                    break;
                }
                break;
            }
            else{
                if(step(p_name,expbuf)){
                    if(error!=-1){
                        free(arg);
                    }
                    break;
                }
            }
        }
        if(error!=-1){
            free(arg);
        }
        p_name=NULL;
    }
    kvm_close(kd);
    if(p_name!=NULL){
        return(curpid);
    }
    return (-1);
}

Reading the process table -- SYSV version

pid_t
getpidbyname(char *name,pid_t skipit)
{
    DIR  *dp;
    struct dirent *dirp;
    prpsinfo_t retval;
    int fd;
    pid_t ourretval=-1;

    if((dp=opendir("/proc"))==NULL){
        return -1;
    }
    chdir("/proc");
    while((dirp=readdir(dp))!=NULL){
        if(dirp->d_name[0]!='.'){
            if((fd=open(dirp->d_name,O_RDONLY))!=-1){
                if(ioctl(fd,PIOCPSINFO,&retval)!=-1){
                    if(!strcmp(retval.pr_fname,name)){
                        ourretval=(pid_t)atoi(dirp->d_name);
                        if(skipit!=-1 && ourretval==skipit){
                            ourretval=-1;
                        }
                        else{
                            close(fd);
                            break;
                        }
                   }
                }
                close(fd);
            }
        }
    }
    closedir(dp);
    return ourretval;
}

Reading the process table -- AIX 4.2 version

#include <stdio.h>
#include <procinfo.h>
 
int getprocs(struct procsinfo *, int, struct fdsinfo *,
             int, pid_t *, int);
 
pid_t getpidbyname(char *name, pid_t *nextPid)
{
  struct procsinfo  pi;
  pid_t             retval = (pid_t) -1;
  pid_t             pid;
 
  pid = *nextPid;
 
  while(1)
  {
    if(getprocs(&pi, sizeof pi, 0, 0, &pid, 1) != 1)
      break;
    
    if(!strcmp(name, pi.pi_comm))
    {
      retval = pi.pi_pid;
      *nextPid = pid;
      break;
    }
  }
  
  return retval;
}
 
int main(int argc, char *argv[])
{
  int   curArg;
  pid_t pid;
  pid_t nextPid;
 
  if(argc == 1)
  {
    printf("syntax: %s <program> [program ...]\n",argv[0]);
    exit(1);
  }
 
  for(curArg = 1; curArg < argc; curArg++)
  {
    printf("Process IDs for %s\n", argv[curArg]);
 
    for(nextPid = 0, pid = 0; pid != -1; )
      if((pid = getpidbyname(argv[curArg], &nextPid)) != -1)
        printf("\t%d\n", pid);
  }
}

Reading the process table using popen and ps

#include <stdio.h>      /* FILE, sprintf, fgets, puts */
#include <stdlib.h>     /* atoi, exit, EXIT_SUCCESS */
#include <string.h>     /* strtok, strcmp */
#include <sys/types.h>  /* pid_t */
#include <sys/wait.h>   /* WIFEXITED, WEXITSTATUS */
 
char *procname(pid_t pid)
{
   static char line[133], command[80], *linep, *token, *cmd;
   FILE *fp;
   int status;
 
   if (0 == pid) return (char *)0;
 
   sprintf(command, "ps -p %d 2>/dev/null", pid);
   fp = popen(command, "r");
   if ((FILE *)0 == fp) return (char *)0;
 
   /* read the header line */
   if ((char *)0 == fgets(line, sizeof line, fp))
   {
      pclose(fp);
      return (char *)0;
   }
 
   /* figure out where the command name is from the column headings.
    * (BSD-ish machines put the COMMAND in the 5th column, while SysV
    * seems to put CMD or COMMAND in the 4th column.)
    */
   for (linep = line; ; linep = (char *)0)
   {
      if ((char *)0 == (token = strtok(linep, " \t\n")))
      {
         pclose(fp);
         return (char *)0;
      }
      if (0 == strcmp("COMMAND", token) || 0 == strcmp("CMD", token))
      { /*  we found the COMMAND column */
         cmd = token;
         break;
      }
   }
 
   /* read the ps(1) output line */
   if ((char *)0 == fgets(line, sizeof line, fp))
   {
      pclose(fp);
      return (char *)0;
   }
 
   /* grab the "word" underneath the command heading... */
   if ((char *)0 == (token = strtok(cmd, " \t\n")))
   {
      pclose(fp);
      return (char *)0;
   }
 
   status = pclose(fp);
   if (!WIFEXITED(status) || 0 != WEXITSTATUS(status)) 
     return (char *)0;
 
   return token;
}
 
int main(int argc, char *argv[])
{
   puts(procname(atoi(argv[1])));
   exit(EXIT_SUCCESS);
}

Daemon utility functions

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
 
/* closeall() -- close all FDs >= a specified value */
 
void closeall(int fd)
{
    int fdlimit = sysconf(_SC_OPEN_MAX);
 
    while (fd < fdlimit)
      close(fd++);
}
 
/* daemon() - detach process from user and disappear into the background
* returns -1 on failure, but you can't do much except exit in that case
* since we may already have forked. This is based on the BSD version,
* so the caller is responsible for things like the umask, etc.
*/
 
/* believed to work on all Posix systems */
 
int daemon(int nochdir, int noclose)
{
    switch (fork())
    {
        case 0:  break;
        case -1: return -1;
        default: _exit(0);          /* exit the original process */
    }
 
    if (setsid() < 0)               /* shoudn't fail */
      return -1;
 
    /* dyke out this switch if you want to acquire a control tty in */
    /* the future -- not normally advisable for daemons */
 
    switch (fork())
    {
        case 0:  break;
        case -1: return -1;
        default: _exit(0);
    }
 
    if (!nochdir)
      chdir("/");
 
    if (!noclose)
    {
        closeall(0);
        open("/dev/null",O_RDWR);
        dup(0); dup(0);
    }
 
    return 0;
}
 
/* fork2() -- like fork, but the new process is immediately orphaned
*            (won't leave a zombie when it exits)                 
 * Returns 1 to the parent, not any meaningful pid.               
 * The parent cannot wait() for the new process (it's unrelated).
*/
 
/* This version assumes that you *haven't* caught or ignored SIGCHLD. */
/* If you have, then you should just be using fork() instead anyway.  */
 
int fork2()
{
    pid_t pid;
    int rc;
    int status;
 
    if (!(pid = fork()))
    {
        switch (fork())
        {
          case 0:  return 0;
          case -1: _exit(errno);    /* assumes all errnos are <256 */
          default: _exit(0);
        }
    }
 
    if (pid < 0 || waitpid(pid,&status,0) < 0)
      return -1;
 
    if (WIFEXITED(status))
      if (WEXITSTATUS(status) == 0)
        return 1;
      else
        errno = WEXITSTATUS(status);
    else
      errno = EINTR;  /* well, sort of :-) */
 
    return -1;
}
An example of using the above functions:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
 
int daemon(int,int);
int fork2(void);
void closeall(int);
 
#define TCP_PORT 8888
 
void errexit(const char *str)
{
    syslog(LOG_INFO, "%s failed: %d (%m)", str, errno);
    exit(1);
}
 
void errreport(const char *str)
{
    syslog(LOG_INFO, "%s failed: %d (%m)", str, errno);
}
 
/* the actual child process is here. */
 
void run_child(int sock)
{
    FILE *in = fdopen(sock,"r");
    FILE *out = fdopen(sock,"w");
    int ch;
 
    setvbuf(in, NULL, _IOFBF, 1024);
    setvbuf(out, NULL, _IOLBF, 1024);
 
    while ((ch = fgetc(in)) != EOF)
      fputc(toupper(ch), out);
 
    fclose(out);
}
 
/* This is the daemon's main work -- listen for connections and spawn */
 
void process()
{
    struct sockaddr_in addr;
    int addrlen = sizeof(addr);
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    int flag = 1;
    int rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                        &flag, sizeof(flag));
 
    if (rc < 0)
      errexit("setsockopt");
 
    addr.sin_family = AF_INET;
    addr.sin_port = htons(TCP_PORT);
    addr.sin_addr.s_addr = INADDR_ANY;
 
    rc = bind(sock, (struct sockaddr *) &addr, addrlen);
    if (rc < 0)
      errexit("bind");
 
    rc = listen(sock, 5);
    if (rc < 0)
      errexit("listen");
 
    for (;;)
    {
        rc = accept(sock, (struct sockaddr *) &addr, &addrlen);
 
        if (rc >= 0)
          switch (fork2())
          {
            case 0:  close(sock); run_child(rc); _exit(0);
            case -1: errreport("fork2"); close(rc); break;
            default: close(rc);
          }
    }
}
 
int main()
{
    if (daemon(0,0) < 0)
    {
        perror("daemon");
        exit(2);
    }
 
    openlog("test", LOG_PID, LOG_DAEMON);
 
    process();
 
    return 0;
}

Modem handling example

/* issue some simple modem commands
* requires the name of a serial device (preferably a dial-out device,
* or a non-modem-control device) as its only parameter.
* If you don't have functional dial-out devices, then move CLOCAL
* to CFLAGS_TO_SET instead.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>   /* maybe; system-dependent */
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
 
#define CFLAGS_TO_SET (CREAD | HUPCL)
#define CFLAGS_TO_CLEAR (CSTOPB | PARENB | CLOCAL)
 
enum flowmode { NoFlow, HardFlow, SoftFlow };
 
/* system-dependent */
#define CFLAGS_HARDFLOW (CRTSCTS)
 
#define EXAMPLE_BAUD B19200
#define EXAMPLE_FLOW HardFlow
 
static void die(const char *msg)
{
    fprintf(stderr, "%s\n", msg);
    exit(1);
}
 
static int close_and_complain(int fd, const char *msg, int err)
{
    fprintf(stderr, "%s: %s\n", msg, strerror(err));
    if (fd >= 0)
        close(fd);
    errno = err;
    return -1;
}
 
int open_port(const char *name, speed_t baud, enum flowmode flow)
{
    int flags;
    struct termios attr;
 
    int fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY);
 
    if (fd < 0)
        return close_and_complain(-1, "open", errno);
 
    /* set vaguely sensibe settings */
 
    if (tcgetattr(fd, &attr) < 0)
        return close_and_complain(fd, "tcgetattr", errno);
        
    /* no special input or output processing */
 
    attr.c_iflag = (flow == SoftFlow) ? (IXON | IXOFF) : 0;
    attr.c_oflag = 0;
 
    /* set 8-bit character size and miscellanous control modes */
 
    attr.c_cflag &= ~(CSIZE | CFLAGS_TO_CLEAR | CFLAGS_HARDFLOW);
    attr.c_cflag |= (CS8 | CFLAGS_TO_SET);
    if (flow == HardFlow)
        attr.c_cflag |= CFLAGS_HARDFLOW;
    
    /* local modes */
 
    attr.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ISIG);
 
    /* special characters -- most disabled by prior settings anyway */
 
    {
        int i;
#ifdef _POSIX_VDISABLE
        attr.c_cc[0] = _POSIX_VDISABLE;
#else
        attr.c_cc[0] = fpathconf(fd, _PC_VDISABLE);
 
 
To Look for similar posts on File handling in Linux explore the following links from the same blog as well.
 
 

File Handling in Linux 10


6.1 How can I debug the children after a fork?

Depending on the tools available there are various ways:
Your debugger may have options to select whether to follow the parent or the child process (or both) after a fork(), which may be sufficient for some purposes.
Alternatively, your debugger may have an option which allows you to attach to a running process. This can be used to attach to the child process after it has been started. If you don't need to examine the very start of the child process, this is usually sufficient. Otherwise, you may wish to insert a sleep() call after the fork() in the child process, or a loop such as the following:
{
    volatile int f = 1;
    while(f);
}
which will hang the child process until you explicitly set f to 0 using the debugger.
Remember, too, that actively using a debugger isn't the only way to find errors in your program; utilities are available to trace system calls and signals on many unix flavours, and verbose logging is also often useful.

6.2 How to build library from other libraries?

Assuming we're talking about an archive (static) library, the easiest way is to explode all the constituent libraries into their original objects using `ar x' in an empty directory, and combine them all back together. Of course, there is the potential for collision of filenames, but if the libraries are large, you probably don't want to be combining them in the first place....

6.3 How to create shared libraries / dlls?

The precise method for creating shared libraries varies between different systems. There are two main parts to the process; firstly the objects to be included in the shared library must be compiled, usually with options to indicate that the code is to be position-independent; secondly, these objects are linked together to form the library.
Here's a trivial example that should illustrate the idea:
/* file shrobj.c */
 
const char *myfunc()
{
    return "Hello World";
}
 
/* end shrobj.c */
 
/* file hello.c */
 
#include <stdio.h>
 
extern const char *myfunc();
 
main()
{
    printf("%s\n", myfunc());
    return 0;
}
 
/* end hello.c */
 
$ gcc -fpic -c shrobj.c
$ gcc -shared -o libshared.so shrobj.o
$ gcc hello.c libshared.so
$ ./a.out
Hello World
 
By far the best method if you want the library and build procedure to be anything approaching portable is to use GNU Libtool. This is a small suite of utilities which know about the platform-dependent aspects of building shared libraries; you can distribute the necessary bits with your program, so that when the installer configures the package, he or she can decide what libraries to build. Libtool works fine on systems which do not support shared libraries. It also knows how to hook into GNU Autoconf and GNU Automake (if you use those tools to manage your program's build procedure).
If you don't want to use Libtool, then for compilers other than gcc, you should change the compiler options as follows:
AIX 3.2 using xlc (unverified)
Drop the `-fpic', and use `-bM:SRE -bE:libshared.exp' instead of `-shared'. You also need to create a file `libshared.exp' containing the list of symbols to export, in this case `myfunc'. In addition, use `-e _nostart' when linking the library (on newer versions of AIX, I believe this changes to `-bnoentry').
SCO OpenServer 5 using the SCO Development System (unverified)
Shared libraries are only available on OS5 if you compile to ELF format, which requires the `-belf' option. Use `-Kpic' instead of `-fpic', and `cc -belf -G' for the link step.
Solaris using SparcWorks compilers
Use `-pic' instead of `-fpic', and use `ld -G' instead of `gcc -shared'.
(Submission of additional entries for the above table is encouraged.)
Other issues to watch out for:
  • AIX and (I believe) Digital Unix don't require the -fpic option, because all code is position independent.
  • AIX normally requires that you create an `export file', which is a list of symbols to be exported from the shared library. Some versions of the linker (possibly only the SLHS linker, svld?) have an option to export all symbols.
  • If you want to refer to your shared library using the conventional `-l' parameter to the linker, you will have to understand how shared libraries are searched for at runtime on your system. The most common method is by using the LD_LIBRARY_PATH environment variable, but there is usually an additional option to specify this at link time.
  • Most implementations record the expected runtime location of the shared library internally. Thus, moving a library from one directory to another may prevent it from working. Many systems have an option to the linker to specify the expected runtime location (the `-R' linker option on Solaris, for example, or the LD_RUN_PATH environment variable).
  • ELF and a.out implementations may have a linker option `-Bsymbolic' which causes internal references within the library to be resolved. Otherwise, on these systems, all symbol resolution is deferred to the final link, and individual routines in the main program can override ones in the library.

6.4 Can I replace objects in a shared library?

Generally, no.
On most systems (except AIX), when you link objects to form a shared library, it's rather like linking an executable; the objects don't retain their individual identity. As a result, it's generally not possible to extract or replace individual objects from a shared library.

6.5 How can I generate a stack dump from within a running program?

Some systems provide library functions for unwinding the stack, so that you can (for example) generate a stack dump in an error-handling function. However, these are highly system-specific, and only a minority of systems have them.
A possible workaround is to get your program to invoke a debugger on itself -- the details still vary slightly between systems, but the general idea is to do this:
void dump_stack(void)
{
    char s[160];
 
    sprintf(s, "/bin/echo 'where\ndetach' | dbx -a %d", getpid());
    system(s);
        
    return;
}
You will need to tweak the commands and parameters to dbx according to your system, or even substitute another debugger such as gdb, but this is still the most general solution to this particular problem that I've ever seen. Kudos to Ralph Corderoy for this one :-)
Here's a list of the command lines required for some systems:
Most systems using dbx
"/bin/echo 'where\ndetach' | dbx /path/to/program %d"
AIX
"/bin/echo 'where\ndetach' | dbx -a %d"
IRIX
"/bin/echo 'where\ndetach' | dbx -p %d"
Go to the first, previous, next, last section, table of contents.

Examples

Catching SIGCHLD

#include <sys/types.h>  /* include this before any other sys headers */
#include <sys/wait.h>   /* header for waitpid() and various macros */
#include <signal.h>     /* header for signal functions */
#include <stdio.h>      /* header for fprintf() */
#include <unistd.h>     /* header for fork() */
 
void sig_chld(int);     /* prototype for our SIGCHLD handler */
 
int main() 
{
    struct sigaction act;
    pid_t pid;
 
    /* Assign sig_chld as our SIGCHLD handler */
    act.sa_handler = sig_chld;
 
    /* We don't want to block any other signals in this example */
    sigemptyset(&act.sa_mask);
 
    /*
     * We're only interested in children that have terminated, not ones
     * which have been stopped (eg user pressing control-Z at terminal)
     */
    act.sa_flags = SA_NOCLDSTOP;
 
    /*
     * Make these values effective. If we were writing a real 
     * application, we would probably save the old value instead of 
     * passing NULL.
     */
    if (sigaction(SIGCHLD, &act, NULL) < 0) 
    {
        fprintf(stderr, "sigaction failed\n");
        return 1;
    }
 
    /* Fork */
    switch (pid = fork())
    {
    case -1:
        fprintf(stderr, "fork failed\n");
        return 1;
 
    case 0:                         /* child -- finish straight away */
        _exit(7);                   /* exit status = 7 */
 
    default:                        /* parent */
        sleep(10);                  /* give child time to finish */
    }
 
    return 0;
}
 
/*
* The signal handler function -- only gets called when a SIGCHLD
* is received, ie when a child terminates
*/
void sig_chld(int signo) 
{
    int status, child_val;
 
    /* Wait for any child without blocking */
    if (waitpid(-1, &status, WNOHANG) < 0) 
    {
        /*
         * calling standard I/O functions like fprintf() in a 
         * signal handler is not recommended, but probably OK 
         * in toy programs like this one.
         */
        fprintf(stderr, "waitpid failed\n");
        return;
    }
 
    /*
     * We now have the info in 'status' and can manipulate it using
     * the macros in wait.h.
     */
    if (WIFEXITED(status))                /* did child exit normally? */
    {
        child_val = WEXITSTATUS(status); /* get child's exit status */
        printf("child's exited normally with status %d\n", child_val);
    }
 
 
 
 
 To Look for similar posts on File handling in Linux explore the following links from the same blog as well.

File Handling in Linux 9


5.2.2.1 Supplying the envelope explicitly

The recipients of a message can simply be specified on the command line. This has the drawback that mail addresses can contain characters that give system() and popen() considerable grief, such as single quotes, quoted strings etc. Passing these constructs successfully through shell interpretation presents pitfalls. (One can do it by replacing any single quotes by the sequence single-quote backslash single-quote single-quote, then surrounding the entire address with single quotes. Ugly, huh?)
Some of this unpleasantness can be avoided by eschewing the use of system() or popen(), and resorting to fork() and exec() directly. This is sometimes necessary in any event; for example, user-installed handlers for SIGCHLD will usually break pclose() to a greater or lesser extent.
Here's an example:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sysexits.h>
/* #include <paths.h> if you have it */
 
#ifndef _PATH_SENDMAIL
#define _PATH_SENDMAIL "/usr/lib/sendmail"
 
 To Look for similar posts on File handling in Linux explore the following links from the same blog as well.
 

File Handling in Linux 8

5.1 How do I compare strings using wildcards?
The answer to that depends on what exactly you mean by `wildcards'.
There are two quite different concepts that qualify as `wildcards'. They are:
Filename patterns
These are what the shell uses for filename expansion (`globbing').
Regular Expressions
These are used by editors, grep, etc. for matching text, but they normally aren't applied to filenames.

5.1.1 How do I compare strings using filename patterns?

Unless you are unlucky, your system should have a function fnmatch() to do filename matching. This generally allows only the Bourne shell style of pattern; i.e. it recognises `*', `[...]' and `?', but probably won't support the more arcane patterns available in the Korn and Bourne-Again shells.
If you don't have this function, then rather than reinvent the wheel, you are probably better off snarfing a copy from the BSD or GNU sources.
Also, for the common cases of matching actual filenames, look for glob(), which will find all existing files matching a pattern.

5.1.2 How do I compare strings using regular expressions?

There are a number of slightly different syntaxes for regular expressions; most systems use at least two: the one recognised by ed, sometimes known as `Basic Regular Expressions', and the one recognised by egrep, `Extended Regular Expressions'. Perl has it's own slightly different flavour, as does Emacs.
To support this multitude of formats, there is a corresponding multitude of implementations. Systems will generally have regexp-matching functions (usually regcomp() and regexec()) supplied, but be wary; some systems have more than one implementation of these functions available, with different interfaces. In addition, there are many library implementations available. (It's common, BTW, for regexps to be compiled to an internal form before use, on the assumption that you may compare several separate strings against the same regexp.)
One library available for this is the `rx' library, available from the GNU mirrors. This seems to be under active development, which may be a good or a bad thing depending on your point of view :-)

5.2 What's the best way to send mail from a program?

There are several ways to send email from a Unix program. Which is the best method to use in a given situation varies, so I'll present two of them. A third possibility, not covered here, is to connect to a local SMTP port (or a smarthost) and use SMTP directly; see RFC 821.

5.2.1 The simple method: /bin/mail

For simple applications, it may be sufficient to invoke mail (usually `/bin/mail', but could be `/usr/bin/mail' on some systems).
WARNING: Some versions of UCB Mail may execute commands prefixed by `~!' or `~|' given in the message body even in non-interactive mode. This can be a security risk.
Invoked as `mail -s 'subject' recipients...' it will take a message body on standard input, and supply a default header (including the specified subject), and pass the message to sendmail for delivery.
This example mails a test message to root on the local system:
#include <stdio.h>
 
#define MAILPROG "/bin/mail"
 
int main()
{
    FILE *mail = popen(MAILPROG " -s 'Test Message' root", "w");
    if (!mail)
    {
        perror("popen");
        exit(1);
    }
 
    fprintf(mail, "This is a test.\n");
 
    if (pclose(mail))
    {
        fprintf(stderr, "mail failed!\n");
        exit(1);
    }
}
If the text to be sent is already in a file, then one can do:
    system(MAILPROG " -s 'file contents' root </tmp/filename");
These methods can be extended to more complex cases, but there are many pitfalls to watch out for:
  • If using system() or popen(), you must be very careful about quoting arguments to protect them from filename expansion or word splitting
  • Constructing command lines from user-specified data is a common source of buffer-overrun errors and other security holes
  • This method does not allow for CC: or BCC: recipients to be specified (some versions of /bin/mail may allow this, some do not)

5.2.2 Invoking the MTA directly: /usr/lib/sendmail

The mail program is an example of a Mail User Agent, a program intended to be invoked by the user to send and receive mail, but which does not handle the actual transport. A program for transporting mail is called an MTA, and the most commonly found MTA on Unix systems is called sendmail. There are other MTAs in use, such as MMDF, but these generally include a program that emulates the usual behaviour of sendmail.
Historically, sendmail has usually been found in `/usr/lib', but the current trend is to move library programs out of `/usr/lib' into directories such as `/usr/sbin' or `/usr/libexec'. As a result, one normally invokes sendmail by its full path, which is system-dependent.
To understand how sendmail behaves, it's useful to understand the concept of an envelope. This is very much like paper mail; the envelope defines who the message is to be delivered to, and who it is from (for the purpose of reporting errors). Contained in the envelope are the headers, and the body, separated by a blank line. The format of the headers is specified primarily by RFC 822; see also the MIME RFCs.
There are two main ways to use sendmail to originate a message: either the envelope recipients can be explicitly supplied, or sendmail can be instructed to deduce them from the message headers. Both methods have advantages and disadvantages.


To Look for similar posts on File handling in Linux explore the following links from the same blog as well.