Unix Lab Programs

Download as pdf or txt
Download as pdf or txt
You are on page 1of 36

USP PROGRAMS UNIX AND ANSI STANDARDS

PROG 1: To illustrate the use of cpp symbols


#include<stdio.h> #include<unistd.h> int main() { #if __STDC__==0 printf("cc is not ancic compliant\n"); #else printf("%s compiled at %s:%s.this statement is at line %d\n",__FILE__,__DATE__,__TIME__,__LINE__); #endif return 0; } OUTPUT: unix1.c compiled at May 19 2011:08:46:43.this statement is at line 8

PROG 2: To show posix version


#include<iostream> #include<unistd.h> #define _POSIX_SOURCE #define _POSIX_C_SOURCE 199309l using namespace std; int main() { #ifdef _POSIX_VERSION cout<<"system confirms to posix:"<< _POSIX_VERSION<<"\n"; #else cout<<"_POSIX_VERSION is undefined\n"; #endif return 0; } OUTPUT: system confirms to posix:200809

PROG3: To show test macros:


#define _POSIX_SOURCE #define _POSIX_C_SOURCE 199309L #include<iostream> #include<unistd.h> using namespace std;

int main() { #ifdef _POSIX_JOB_CONTROL cout<<"sys control job support\n"; #else cout<"sys does not support job control\n"; #endif #ifdef _POSIX_SAVED_IDS cout<<"sys support saved set_uid and saved set_gid\n"; #else cout<<"sys does not support saved set_uid and saved set_gid\n"; #endif #ifdef _POSIX_CHOWN_RESTRICTED cout<<"sys does not support chown_restricted option\n"; #endif #ifdef _POSIX_NO_TRUNC cout<<"path name trunc option is:"<<_POSIX_NO_TRUNC<<endl; #else cout<<"sys does not suport sys-wide path name trunc option\n"; #endif #ifdef _POSIX_VDISABLE cout<<"distance char for terminal files is,"<<_POSIX_VDISABLE<<Thnx\n #else cout<<"sys does not support_POSIX_VDISABLE\n"; #endif return 0; } OUTPUT: sys control job support sys support saved set_uid and saved set_gid sys does not support chown_restricted option path name trunc option is:1 distance char for terminal files is,Thnx

PROG 4: Use of sysconf,pathconf and fpathconf:


#define _POSIX_SOURCE #define _POSIX_C_SOURCE 199309L #include<stdio.h> #include<iostream> #include<unistd.h> using namespace std; int main() { int res; if((res=sysconf(_SC_OPEN_MAX))==-1) perror("sysconf"); else cout<<"OPEN_MAX:"<<res<<endl; if((res==pathconf("/",_PC_PATH_MAX))==-1) perror("pathconf"); else

} OUTPUT:

cout<<"Max path name:"<<(res+1)<<endl; if((res=fpathconf(0,_PC_CHOWN_RESTRICTED))==-1) perror("fpathconf"); else cout<<"Chown_restricted for stdin:"<<res<<endl; return 0;

OPEN_MAX:1024 Max path name:1025 Chown_restricted for stdin:1

PROG 5: Use of setlocale function:


#include <stdio.h> #include <time.h> #include <locale.h> int main () { time_t rawtime; struct tm * timeinfo; char buffer [80]; struct lconv * lc; time ( &rawtime ); timeinfo = localtime ( &rawtime ); int twice=0; do { printf ("Locale is: %s\n", setlocale(LC_ALL,NULL) ); strftime (buffer,80,"%c",timeinfo); printf ("Date is: %s\n",buffer); lc = localeconv (); printf ("Currency symbol is: %s\n-\n",lc->currency_symbol); setlocale (LC_ALL,""); }while (!twice++); return 0; } OUTPUT: Locale is: C Date is: 01/15/07 13:33:47 Currecy symbol is: Locale is: English_United States.1252

Date is: 1/15/07 1:33:47 PM Currency symbol is: $ -

UNIX FILE APIs


Prog 1: To show the use of open,read,write and close Apis
#include<stdio.h> #include<sys/types.h> #include<fcntl.h> #include<unistd.h> #include<string.h> #include<stdlib.h> int main(int argc,char *argv[]) { int fdesc; char buf[256],*buf1; if(argc !=3) { printf("Usage: ./a.out<readfile><writefile>\n"); exit(0); } fdesc=open(argv[1],O_RDONLY); printf("CONTENTS OF FILE IS:\n"); while(read(fdesc,buf,sizeof(buf)) > 0); printf("%s",buf); close(fdesc); fdesc=open(argv[2],O_WRONLY|O_APPEND|O_CREAT); buf1=(char *)malloc(1024*sizeof(char)); printf("Enter the data to be updated to the file:\n"); scanf("%s",buf1); size_t length=strlen(buf1); if(write(fdesc,buf1,length)==-1) printf("Write error\n"); close(fdesc); return 0;

OUTPUT: ./a.out read.txt write.txt Contents of read.txt is: This is a read file Enter the data to be updated to writefile: Hai, have a nice day

Prog 2: Use of fcntl api

#include<sys/types.h> #include<stdio.h> #include<fcntl.h> #include<unistd.h> int main(int argc,char **argv) { int fdesc=open(argv[1],O_RDONLY); close(0); int cur_flags=fcntl(fdesc,F_GETFL); printf(" %d %d \n",fdesc,cur_flags); printf("close on exec= %d\n", fcntl(fdesc,F_GETFD)); (void)fcntl(fdesc,F_SETFD,1); printf("close on exec= %d", fcntl(fdesc,F_GETFD)); if(fcntl(fdesc,F_DUPFD,0)==-1) perror("fcntl"); char buf[256]; int rc=read(0,buf,256); printf("rc=%d\n\n",rc);

Prog 3: Use of lseek Api


#include<stdio.h> #include<unistd.h> #include<fcntl.h> #include<sys/types.h> int main(int argc,char *argv[]) { char buf[256]; int fdesc,len; while(--argc > 0) { if(access(*++argv,F_OK)) { fdesc=open(*argv,O_WRONLY|O_CREAT,0744); write(fdesc,"HELLO WORLD\n",12); } else { fdesc=open(*argv,O_RDONLY); while(len=read(fdesc,buf,256)) write(1,buf,len); } close(fdesc); } }

Prog 4: Use of link Api


#include<stdio.h> #include<unistd.h> int main(int argc,char *argv[]) {

if(argc!=3) { }

printf("Usage: ./a.out <srcfile> <dest_file>\n"); return 0;

if(link(argv[1],argv[2])==-1) { perror("link"); return 1; } return 2;

Prog 5: Use of unlink Api


#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<string.h> int main(int argc,char *argv[]) { if(argc!=3 || !strcmp(argv[1],argv[2])) printf("Usage: ./a.out <old_link> <new_link>\n"); else if(link(argv[1],argv[2])==0) return unlink(argv[1]); return -1; }

Prog 6: Use of stat Api


#include<sys/types.h> #include<sys/stat.h> #include<unistd.h> void change_mode() { struct stat statv; int flag=(S_IWGRP|S_IROTH|S_IXOTH); if(stat("/usr/games/gbrainy",&statv)) perror("stat"); else { flag=(statv.st_mode & ~flag)|S_ISUID; if(chmod("/usr/games/gbrainy",flag)) perror("chmod"); } } int main()

{ change_mode(); return 0; }

Prog 7: Use of access Api


#include <sys/types.h> #include <unistd.h> #include <fcntl.h> int main(int argc, char * argv[]) { char buf[256]; int fdesc,len; while(--argc > 0) { if(access(*++argv,F_OK)) { // a brand new file fdesc = open(*argv, O_WRONLY | O_CREAT, 0744); write(fdesc, "Hello world \n", 12); } else { fdesc = open(*argv, O_RDONLY); while(len = read(fdesc, buf, 256)) write(1, buf, len); } close(fdesc); } }

Prog 8: Use of chmod Api


#include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdio.h> int main() { struct stat statv; mode_t flag1=S_IRWXU|S_IWGRP|S_IROTH|S_IWOTH|S_IXOTH; if(stat("/home/nithish/time.c",&statv)) perror("stat"); else { printf("%d\n",flag1); if(chmod("/home/nithish/time.c",flag1)) perror("chmod"); } }

Prog 9: Use of chown Api


#include <iostream> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <pwd.h> #include <stdio.h> using namespace std; int main(int argc, char * argv[]) { if(argc < 3) { cerr << "usage:"<<argv[0] << " <usr_name> <files> \n"; return 1; } struct passwd *pwd = getpwuid (argv[1]); //convert uid_t UID = pwd ? pwd->pw_uid:-1; struct stat statv; if(UID == (uid_t) -1) cerr << "invalid user name \n"; else for(int i = 2; i < argc; i++) //do for each file specified if(stat(argv[i] & statv) == 0) { if(chown(argv[i],UID,statv.st_gid)) perror("chown"); } else perror("stat"); return 0; } user name to UID

Prog 10: Use of utime Api


#include<sys/types.h> #include<unistd.h> #include<utime.h> #include<stdio.h> int main(int argc,char *argv[]) { struct utimbuf times; int offset,i; if(argc<3 || sscanf(argv[1],"%d",&offset) != 1) printf("Usage: ./a.out <offset> <filenames>\n"); else { times.actime=times.modtime=time(0)+offset; for(i=2;i<argc;i++) { if(utime(argv[i],&times) == -1) perror("utime"); } return 0;

} return 1; } Prog 11: Illustrate file locking: #include #include #include #include #include <iostream> <stdio.h> <sys/types.h> <fcntl.h> <unistd.h>

out

using namespace std; int main(int argc, char *argv[]) { struct flock fvar; int temp; int fdesc; while(--argc > 0) { if((fdesc = open(*++argv, O_RDWR)) == -1) { perror("open"); continue; } fvar.l_type = F_WRLCK; fvar.l_whence = SEEK_SET; fvar.l_start = 0; fvar.l_len = 0; temp = fcntl(fdesc,F_SETLKW,&fvar); cout <<temp; temp = fcntl(fdesc, F_GETLK,&fvar); cout <<endl<<temp<<endl<<endl; cout <<*argv<< " \nlocked by : " << fvar.l_pid <<"\nfrom :"<< fvar.l_start<<"\tfor"<<fvar.l_len<<"\tbyte for\t"<<(fvar.l_type==F_WRLCK?'w':'r')<<endl; //set lock fails, find who has locked the file */ /* Attempt to set an exclusive (write) lock on the entire file */ while(fcntl(fdesc, F_SETLK,&fvar) == -1) { cout<<"enter the loop"; //set lock fails find out who has locked the file */ while(fcntl(fdesc,F_GETLK, &fvar)!= -1 && fvar.l_type != F_UNLCK){ cout << "argv"<< "locked by" << fvar.l_pid <<"from "<< fvar.l_start<<"for"<<fvar.l_len<<"byte for"<<(fvar.l_type==F_WRLCK?'w':'r')<<endl; if(!fvar.l_len) break; fvar.l_start += fvar.l_len; fvar.l_len = 0; } }

fvar.l_type = F_UNLCK; fvar.l_whence = SEEK_SET; fvar.l_start = 0; fvar.l_len = 0; if(fcntl(fdesc, F_SETLKW, &fvar) == -1) perror("fcntl"); }

return 0; }

Prog 12: Directory file APIs


#include<iostream> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<pwd.h> #include<utime.h> #include<time.h> #include<error.h> #include<stdio.h> #include<fcntl.h> #include<string.h> using namespace std; #if defined(BSO) && !_POSIX_SOURCE #include<sys/dir.h> typedef struct direct Dirent; #else #include<dirent.h> typedef struct dirent Dirent; #endif int main(int argc,char*argv[]) { Dirent* dp; DIR *dir_fdesc; while(--argc>0) { if(!(dir_fdesc==opendir(*++argv))) { if(mkdir(*argv,S_IRWXU|S_IRWXG|S_IRWXO)==-1) perror("opendir"); continue; } for(int i=0;i<2;i++) { for(int cnt=0;dp=readdir(dir_fdesc);) { if(i) cout<<dp->d_name<<endl; if(strcmp(dp->d_name,",") && strcmp(dp->d_name,"...")) cnt++; } if(!cnt) {rmdir(*argv);break;} rewinddir(dir_fdesc); } closedir(dir_fdesc); } }

Prog 13: Device file API


#include<iostream> #include <stdio.h>

#include <sys/types.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> using namespace std; int main(int argc, char *argv[]) { if(argc != 4) { cout <<"usage: " <<argv[0]<<" <file><major no><minor no>\n"; return 0; } int major = atoi(agrv[2]), minor = atoi(argv[3]); (void)mknod(argv[1],S_IFCHR|S_IRWXU|S_IRWXG|S_IRWXO,(major << 8) | minor); int rc = 1, fd = open(argv[1], O_RDWR|O_NOBLOCK|O_NOCTTY); char buf[256]; while ( rc && fd != -1) if((rc= read(fd,buf,sizeof(buf)))<0) perror("read"); else if(rc) cout<<buf<<endl; close(fd); }

Prog 14: Fifo file API


#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/stat.h> #include<fcntl.h> #include<string.h> #include<errno.h> int main(int argc,char **argv) { if(argc!=2 && argc!=3) { printf("\n usage: %s <file> [<arg>] \n",argv[0]); return 0; } int fd; char buf[256]; (void)mkfifo(argv[1],S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO); if(argc==2) { fd=open(argv[1],O_RDONLY|O_NONBLOCK); while(read(fd,buf,sizeof(buf))==-1 && errno==EAGAIN) sleep(1); while(read(fd,buf,sizeof(buf)) > 0) printf("\n %s \n",buf); } else

{ fd=open(argv[1],O_WRONLY); write(fd,argv[2],strlen(argv[2])); } close(fd); }

Prog 15: Symbolic file API


#include<iostream> #include<sys/types.h> #include<unistd.h> #include<string.h> using namespace std; int main(int argc,char **argv) { char *buf[256],tname[256]; if((argc<3 && argc>4)||(argc==4 && strcmp(argv[1],"-s"))) { cout<<"usage:" <<argv[0]<<" [-s] <orig file> <newlink>"; return 1; } if(argc==4) return symlink(argv[2],argv[3]); else return link(argv[1],argv[2]); }

PROCESS ENVIRONMENT:
Prog 1: Atexit function and exit functions
#include<stdio.h> #include<stdlib.h> #include<unistd.h> static void my_exit1(void) { printf("\nfirst exit handler"); } static void my_exit2(void) { printf("\nsecond exit handler"); } int main(void) { if(atexit(my_exit2)!=0) printf("\ncan't register my_exit2"); if(atexit(my_exit1)!=0) printf("\ncan't register my_exit1"); if(atexit(my_exit1)!=0)

printf("\ncan't register my_exit1"); printf("\nmain is done"); exit(0); } OUTPUT: main is done first exit handler first exit handler second exit handler

Prog 2: Command-Line Arguments


#include<stdio.h> int main(int argc,char **argv) { int i; for(i=0;i<argc;i++) { printf("\nargv[%d]: %s",i,argv[i]) } } OUTPUT: ./a.out read.txt argv[0]: ./a.out argv[1]: read.txt

Prog 3: getenv() and setenv() functions


#include<stdio.h> #include<stdlib.h> void main() { printf("\nPATH= %s\n",getenv("PATH")); setenv("PATH","D:/",1); printf("\nPATH= %s\n",getenv("PATH")); } OUTPUT: PATH=/home/nithish/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin :/usr/games PATH= D:/

Prog 4: getjmp() and setjmp() functions


#include<stdio.h> #include<iostream> #include<setjmp.h> #include<stdlib.h> using namespace std;

int c=1; main() { jmp_buf env; int i; i = setjmp(env); printf("i = %d\n", i); if (i ==5) exit(0); longjmp(env, c++); printf("Does this line get printed?\n"); } OUTPUT: i i i i i i = = = = = = 0 1 2 3 4 5

Prog 5: getrlimit() and setrlimit() functions


#include #include #include #include <stdlib.h> <stdio.h> <string.h> <sys/resource.h> /* /* /* /* Standard Lib I/O lib Strings limits ISOC ISOC ISOC SUS */ */ */ */

int main(int argc, char *argv[]); void printLimit(int theLimitNum, char *theLimitStr); int main(int argc, char *argv[]) { #ifdef RLIMIT_CPU printLimit(RLIMIT_CPU, "RLIMIT_CPU (cpu time)"); #endif #ifdef RLIMIT_FSIZE printLimit(RLIMIT_FSIZE, "RLIMIT_FSIZE (file size)"); #endif #ifdef RLIMIT_DATA printLimit(RLIMIT_DATA, "RLIMIT_DATA (data seg size)"); #endif #ifdef RLIMIT_STACK printLimit(RLIMIT_STACK, "RLIMIT_STACK (stack size)"); #endif #ifdef RLIMIT_CORE printLimit(RLIMIT_CORE, "RLIMIT_CORE (core file size)"); #endif #ifdef RLIMIT_AS printLimit(RLIMIT_AS, "RLIMIT_AS (resident set size)"); #endif #ifdef RLIMIT_RSS printLimit(RLIMIT_RSS, "RLIMIT_RSS (resident set size)"); #endif #ifdef RLIMIT_MEMLOCK

printLimit(RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK (locked memory)"); #endif #ifdef RLIMIT_NPROC printLimit(RLIMIT_NPROC, "RLIMIT_NPROC (user processes)"); #endif #ifdef RLIMIT_NOFILE printLimit(RLIMIT_NOFILE, "RLIMIT_NOFILE (open files)"); #endif return 0; } /* end func main */ void printLimit(int theLimitNum, char *theLimitStr) { struct rlimit rlimitStruct; if(getrlimit(theLimitNum, &rlimitStruct) == -1) { printf("ERROR: getrlimit failure %s\n", theLimitStr); return; } /* end if */ printf("%-32s ", theLimitStr); if(rlimitStruct.rlim_cur == RLIM_INFINITY) printf("cur: %15s ", "INFINITY"); else printf("cur: %15lld ", (long long)rlimitStruct.rlim_cur); if(rlimitStruct.rlim_max == RLIM_INFINITY) printf("max: %15s ", "INFINITY"); else printf("max: %15lld ", (long long)rlimitStruct.rlim_max); printf("\n"); } /* end func printLimit */ PROCESS CONTROL:

Prog 1: fork function


#include <iostream> #include <string> #include<stdio.h> #include <sys/types.h> #include <unistd.h> #include<stdlib.h> using namespace std; int globalVariable = 2; main() { string sIdentifier; int iStackVariable = 20; pid_t pID = fork(); if (pID == 0) // child { // Code only executed by child process sIdentifier = "Child Process: "; globalVariable++;

} else if (pID < 0) // failed to fork { cerr << "Failed to fork" << endl; exit(1); // Throw exception } else // parent { // Code only executed by parent process sleep(1); sIdentifier = "Parent Process:"; } // executed only by parent

iStackVariable++; cout << sIdentifier; cout<<" PID: " << getpid(); cout << " Global variable: " << globalVariable; cout << " Stack variable: " << iStackVariable << endl; _exit(0);

cout << sIdentifier; cout<<" PID: " << getpid(); cout << " Global variable: " << globalVariable; cout << " Stack variable: " << iStackVariable << endl; exit(0); } OUTPUT: Child Process: PID: 2447 Global variable: 3 Stack variable: 21 Parent Process: PID: 2446 Global variable: 2 Stack variable: 20 prog 2: vfork function

#include<iostream>
#include <string> #include<stdio.h> #include <sys/types.h> #include <unistd.h> #include<stdlib.h> using namespace std; int globalVariable = 2; main() { string sIdentifier; int iStackVariable = 20; pid_t pID = fork(); if (pID == 0) // child { // Code only executed by child process sIdentifier = "Child Process: ";

globalVariable++; iStackVariable++; cout << sIdentifier; cout<<" PID: " << getpid(); cout << " Global variable: " << globalVariable; cout << " Stack variable: " << iStackVariable << endl; _exit(0); } else if (pID < 0) // failed to fork { cerr << "Failed to fork" << endl; exit(1); // Throw exception } else // parent { // Code only executed by parent process sleep(1); sIdentifier = "Parent Process:"; } // executed only by parent cout << sIdentifier; cout<<" PID: " << getpid(); cout << " Global variable: " << globalVariable; cout << " Stack variable: " << iStackVariable << endl; exit(0);

} OUTPUT:

Child Process: PID: 2447 Global variable: 3 Stack variable: 21 Parent Process: PID: 2446 Global variable: 3 Stack variable: 21 Prog 3: exec functions /*Main function*/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/wait.h> char *envinit[] = {"USER=unknown", "PATH=/tmp",NULL}; int main() { pid_t pid; if((pid=fork()) < 0) { printf("Fork error\n"); exit(0); } else if(pid==0) { if(execle("/home/nithish/bin/echoall","only one arg","my arg2", (char *) 0,envinit) < 0) {

} }

printf("Execle error\n"); exit(0);

if(waitpid(pid,NULL,0) < 0) printf("Wait error\n"); exit(0);

/*target code for execle*/ #include<stdio.h> #include<stdlib.h> int main(int argc,char *argv[],char *envp[]) { int i; char **ptr; extern char **environ; for(i=0;i<argc;i++) printf("argv[%d]: %s\n",i,argv[i]); for(ptr=envp;*ptr !=0; ptr++) printf("%s\n",*ptr); exit(0); }

OUTPUT: argv[0]: only one arg argv[1]: my arg2 USER=unknown PATH=/tmp

Prog 4: wait functions


#include<sys/types.h> #include<sys/wait.h> #include<stdio.h> #include<stdlib.h> int main(void) { pid_t pid; int status; if ( (pid = fork()) < 0) perror("fork error"); else if (pid == 0) exit(7);

/* child */

if (wait(&status) != pid) /* wait for child */ perror("wait error"); /* and print its status */

if ( (pid = fork()) < 0) perror("fork error"); else if (pid == 0) abort(); if (wait(&status) != pid) perror("wait error"); if ( (pid = fork()) < 0) perror("fork error"); else if (pid == 0) status /= 0; if (wait(&status) != pid) perror("wait error"); exit(0); }

/* child */ /* generates SIGABRT */ /* wait for child */

/* child */ /* divide by 0 generates SIGFPE */ /* wait for child */

Process Relationships
1. Creating

an orphaned process group

#include "apue.h" #include <errno.h> static void sig_hup(int signo) { printf("SIGHUP received, pid = %d\n", getpid()); } static void pr_ids(char *name) { printf("%s: pid = %d, ppid = %d, pgrp = %d, tpgrp = %d\n", name, getpid(), getppid(), getpgrp(), tcgetpgrp(STDIN_FILENO)); fflush(stdout); } int main(void) { char c; pid_t pid; pr_ids("parent"); if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid > 0) { /* parent */ sleep(5); /*sleep to let child stop itself */

exit(0); /* then parent exits */ } else { /* child */ pr_ids("child"); signal(SIGHUP, sig_hup); /* establish signal handler */ kill(getpid(), SIGTSTP); /* stop ourself */ pr_ids("child"); /* prints only if we're continued */ if (read(STDIN_FILENO, &c, 1) != 1) printf("read error from controlling TTY, errno = %d\n", errno); exit(0); } } }

Signals
2.

Call a non reentrant function from a signal handler


#include "apue.h" #include <pwd.h> static void my_alarm(int signo) { struct passwd *rootptr; printf("in signal handler\n"); if ((rootptr = getpwnam("root")) == NULL) err_sys("getpwnam(root) error"); alarm(1); } int main(void) { struct passwd *ptr; signal(SIGALRM, my_alarm); alarm(1); for ( ; ; ) { if ((ptr = getpwnam("sar")) == NULL) err_sys("getpwnam error"); if (strcmp(ptr->pw_name, "sar") != 0) printf("return value corrupted!, pw_name = %s\n", ptr->pw_name); } }

3. System

V SIGCLD handler that doesn't work :

#include "apue.h" #include <sys/wait.h> static void sig_cld(int); int main() { pid_t pid; if (signal(SIGCLD, sig_cld) == SIG_ERR) perror("signal error"); if ((pid = fork()) < 0) { perror("fork error"); } else if (pid == 0) { /* child */ sleep(2); _exit(0); } pause(); exit(0); /* parent */ } static void sig_cld(int signo) { pid_t pid; int status; /* interrupts pause() */ printf("SIGCLD received\n"); if (signal(SIGCLD, sig_cld) == SIG_ERR) /* reestablish handler */ perror("signal error"); If ((pid = wait(&status)) < 0) /* fetch child status */ perror("wait error"); printf("pid = %d\n", pid); } 4. Simple,

implementation of sleep

#include <signal.h> #include <unistd.h> static void sig_alrm(int signo) { /* nothing to do, just return to wake up the pause */ } unsigned int sleep1(unsigned int nsecs) { if (signal(SIGALRM, sig_alrm) == SIG_ERR) return(nsecs); alarm(nsecs); /* start the timer */ pause(); /* next caught signal wakes us up */ return(alarm(0)); /* turn off timer, return unslept time */ }

5.

Calling sleep2 from a program that catches other signals


#include "apue.h" unsigned int static void int main(void) { unsigned int sleep2(unsigned int); sig_int(int); unslept; if (signal(SIGINT, sig_int) == SIG_ERR) err_sys("signal(SIGINT) error"); unslept = sleep2(5); printf("sleep2 returned: %u\n", unslept); exit(0); } static void sig_int(int signo) { int i, j; volatile int k; /* * Tune these loops to run for more than 5 seconds * on whatever system this test program is run. */ printf("\nsig_int starting\n"); for (i = 0; i < 300000; i++) for (j = 0; j < 4000; j++) k += i * j; printf("sig_int finished\n"); }

6. Calling

read with a timeout

#include "apue.h" static void sig_alrm(int); int main(void) { int n; char line[MAXLINE]; if (signal(SIGALRM, sig_alrm) == SIG_ERR) err_sys("signal(SIGALRM) error"); alarm(10); if ((n = read(STDIN_FILENO, line, MAXLINE)) < 0) err_sys("read error"); alarm(0); write(STDOUT_FILENO, line, n); exit(0); } static void sig_alrm(int signo) { /* nothing to do, just return to interrupt the read */ }

7.Calling read with a timeout, #include "apue.h" #include <setjmp.h> static void sig_alrm(int); static jmp_buf env_alrm;

using longjmp

int main(void) { int n; char env_alrm; line[MAXLINE]; if (signal(SIGALRM, sig_alrm) == SIG_ERR) err_sys("signal(SIGALRM) error"); if (setjmp(env_alrm) != 0) err_quit("read timeout"); alarm(10); if ((n = read(STDIN_FILENO, line, MAXLINE)) < 0) err_sys("read error"); alarm(0); write(STDOUT_FILENO, line, n); exit(0); } static void sig_alrm(int signo) { longjmp(env_alrm, 1); } 8.An implementation of sigaddset, sigdelset, and sigismember. #include<signal.h> #include<errno.h> /* <signal.h> usually defines NSIG to include signal number 0 */ #define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG) int sigaddset(sigset_t *set, int signo) { if (SIGBAD(signo)) { errno = EINVAL; return(-1); } *set |= 1 << (signo - 1); return(0); /* turn bit on */ } int sigdelset(sigset_t *set, int signo) { if (SIGBAD(signo)) { errno = EINVAL; return(-1); } *set &= ~(1 << (signo - 1)); return(0); /* turn bit off */ } int sigismember(const sigset_t *set, int signo) { if (SIGBAD(signo)) { errno = EINVAL; return(-1); } return((*set & (1 << (signo - 1))) != 0);

} 9.Print

the signal mask for the process.


#include "apue.h" #include <errno.h> void pr_mask(const char *str) { sigset_t sigset; int errno_save; errno_save = errno; /* we can be called by signal handlers */ if (sigprocmask(0, NULL, &sigset) < 0) err_sys("sigprocmask error"); printf("%s", str); if (sigismember(&sigset,SIGINT)) printf("SIGINT "); if (sigismember(&sigset,SIGQUIT)) printf("SIGQUIT "); if (sigismember(&sigset,SIGUSR1)) printf("SIGUSR1 "); if (sigismember(&sigset,SIGALRM)) printf("SIGALRM "); /* remaining signals can go here */ printf("\n"); errno = errno_save; }

10.Example

of signal sets and sigprocmask.

#include "apue.h" static void sig_quit(int); int main(void) { sigset_t newmask, oldmask, pendmask; if (signal(SIGQUIT, sig_quit) == SIG_ERR) err_sys("can't catch SIGQUIT"); /* * Block SIGQUIT and save current signal mask. */ sigemptyset(&newmask); sigaddset(&newmask, SIGQUIT); if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) err_sys("SIG_BLOCK error"); sleep(5); /* SIGQUIT here will remain pending */ if (sigpending(&pendmask) < 0) err_sys("sigpending error"); if (sigismember(&pendmask, SIGQUIT)) printf("\nSIGQUIT pending\n"); if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); printf("SIGQUIT unblocked\n"); sleep(5); exit(0); } static void sig_quit(int signo) { printf("caught SIGQUIT\n"); if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) err_sys("can't reset SIGQUIT"); }

11.An

implementation of signal using sigaction

#include "apue.h" Sigfunc *signal(int signo, Sigfunc *func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; #endif } else { #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif } if (sigaction(signo, &act, &oact) < 0) return(SIG_ERR); return(oact.sa_handler); } 12. The

signal_intr function

#include "apue.h" Sigfunc *signal_intr(int signo, Sigfunc *func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; #endif if (sigaction(signo, &act, &oact) < 0) return(SIG_ERR); return(oact.sa_handler); }

13.Example of signal masks, sigsetjmp, and siglongjmp


#include "apue.h" #include <setjmp.h> #include <time.h> static void sig_usr1(int), sig_alrm(int); static sigjmp_buf jmpbuf;

static volatile sig_atomic_t canjump; sig_usr1(int), sig_alrm(int); int main(void) { if (signal(SIGUSR1, sig_usr1) == SIG_ERR) err_sys("signal(SIGUSR1) error"); if (signal(SIGALRM, sig_alrm) == SIG_ERR) err_sys("signal(SIGALRM) error"); pr_mask("starting main: "); if (sigsetjmp(jmpbuf, 1)) { pr_mask("ending main: "); exit(0); } canjump = 1; /* now sigsetjmp() is OK */ for ( ; ; ) pause(); } static void sig_usr1(int signo) { time_t starttime; if (canjump == 0) return; /* unexpected signal, ignore */ pr_mask("starting sig_usr1: "); alarm(3); starttime = time(NULL); for ( ; ; ) if (time(NULL) > starttime + 5) break; pr_mask("finishing sig_usr1: "); canjump = 0; siglongjmp(jmpbuf, 1); } static void sig_alrm(int signo) { pr_mask("in sig_alrm: "); } 14.Protecting a critical region from a signal #include "apue.h" static void sig_int(int); int main(void) { sigset_t newmask, oldmask, waitmask; pr_mask("program start: "); if (signal(SIGINT, sig_int) == SIG_ERR) err_sys("signal(SIGINT) error"); sigemptyset(&waitmask); sigaddset(&waitmask, SIGUSR1); sigemptyset(&newmask); signaled(&newmask, SIGINT); pr_mask("in critical region: "); if (sigsuspend(&waitmask) != -1) err_sys("sigsuspend error"); pr_mask("after return from sigsuspend: ");

if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); pr_mask("program exit: "); exit(0); } static void sig_int(int signo) { pr_mask("\nin sig_int: "); }

15. Using sigsuspend to wait for a global variable to be set


#include "apue.h" volatile sig_atomic_t quitflag; static void sig_int(int signo) /* set nonzero by signal handler */ /* one signal handler for SIGINT and SIGQUIT */ { if (signo == SIGINT) printf("\ninterrupt\n"); else if (signo == SIGQUIT) quitflag = 1; /* set flag for main loop */ } int main(void) { sigset_t newmask, oldmask, zeromask; if (signal(SIGINT, sig_int) == SIG_ERR) err_sys("signal(SIGINT) error"); if (signal(SIGQUIT, sig_int) == SIG_ERR) err_sys("signal(SIGQUIT) error"); sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask, SIGQUIT); /* * Block SIGQUIT and save current signal mask. */ if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) err_sys("SIG_BLOCK error"); while (quitflag == 0) sigsuspend(&zeromask); /* * SIGQUIT has been caught and is now blocked; do whatever. */ quitflag = 0; /* * Reset signal mask which unblocks SIGQUIT. */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); exit(0); }

16.Routines

to allow a parent and child to synchronize

#include "apue.h" static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */

static sigset_t newmask, oldmask, zeromask; static void sig_usr(int signo) { sigflag = 1; } /* one signal handler for SIGUSR1 and SIGUSR2 */ void TELL_WAIT(void) { if (signal(SIGUSR1, sig_usr) == SIG_ERR) err_sys("signal(SIGUSR1) error"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) err_sys("signal(SIGUSR2) error"); sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask, SIGUSR1); sigaddset(&newmask, SIGUSR2); /* * Block SIGUSR1 and SIGUSR2, and save current signal mask. */ if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) err_sys("SIG_BLOCK error"); } void TELL_PARENT(pid_t pid) { kill(pid, SIGUSR2); } void /* tell parent we're done */ WAIT_PARENT(void) { while (sigflag == 0) sigsuspend(&zeromask); sigflag = 0; /* and wait for parent */ /* * Reset signal mask to original value. */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); } void TELL_CHILD(pid_t pid) { kill(pid, SIGUSR1); } /* tell child we're done */ void WAIT_CHILD(void) { while (sigflag == 0) sigsuspend(&zeromask); sigflag = 0; /* and wait for child */ /* * Reset signal mask to original value. */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); } 17.Implementation of POSIX.1 abort

#include<signal.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h> void abort(void) /* POSIX-style abort() function */ { sigset_t mask; struct sigaction action; /* * Caller can't ignore SIGABRT, if so reset to default. */ sigaction(SIGABRT, NULL, &action); if (action.sa_handler == SIG_IGN) { action.sa_handler = SIG_DFL; sigaction(SIGABRT, &action, NULL); } if (action.sa_handler == SIG_DFL) fflush(NULL); /* flush all open stdio streams */ /* * Caller can't block SIGABRT; make sure it's unblocked. */ sigfillset(&mask); sigdelset(&mask, SIGABRT); /* mask has only SIGABRT turned off */ sigprocmask(SIG_SETMASK, &mask, NULL); kill(getpid(), SIGABRT); /* send the signal */ /* * If we're here, process caught SIGABRT and returned. */ fflush(NULL); /* flush all open stdio streams */ action.sa_handler = SIG_DFL; sigaction(SIGABRT, &action, NULL); /* reset to default */ sigprocmask(SIG_SETMASK, &mask, NULL); /* just in case ... */ kill(getpid(), SIGABRT); /* and one more time */ exit(1); /* this should never be executed ... */ } 18.Using

system to invoke the ed editor

#include "apue.h" static void sig_int(int signo) { printf("caught SIGINT\n"); } static void sig_chld(int signo) {

printf("caught SIGCHLD\n"); } int main(void) { if (signal(SIGINT, sig_int) == SIG_ERR) err_sys("signal(SIGINT) error"); if (signal(SIGCHLD, sig_chld) == SIG_ERR) err_sys("signal(SIGCHLD) error"); if (system("/bin/ed") < 0) err_sys("system() error"); exit(0); } 19.Correct

POSIX.1 implementation of system function

#include<sys/wait.h> #include<errno.h> #include<signal.h> #include<unistd.h> int system(const char *cmdstring) /* with appropriate signal handling */ { pid_t pid; int status; struct sigaction ignore, saveintr, savequit; sigset_t chldmask, savemask; if (cmdstring == NULL) return(1); /* always a command processor with UNIX */ ignore.sa_handler = SIG_IGN; sigemptyset(&ignore.sa_mask); ignore.sa_flags = 0; /* ignore SIGINT and SIGQUIT */ if (sigaction(SIGINT, &ignore, &saveintr) < 0) return(-1); if (sigaction(SIGQUIT, &ignore, &savequit) < 0) return(-1); sigemptyset(&chldmask); /* now block SIGCHLD */ sigaddset(&chldmask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0) return(-1); if ((pid = fork()) < 0) { status = -1; /* probably out of processes */ } else if (pid == 0) { /* child */ /* restore previous signal actions & reset signal mask */ sigaction(SIGINT, &saveintr, NULL); sigaction(SIGQUIT, &savequit, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL); execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); _exit(127); /* exec error */ } else {

/* parent */ while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) { status = -1; /* error other than EINTR from waitpid() */ break; } } /* restore previous signal actions & reset signal mask */ if (sigaction(SIGINT, &saveintr, NULL) < 0) return(-1); if (sigaction(SIGQUIT, &savequit, NULL) < 0) return(-1); if (sigprocmask(SIG_SETMASK, &savemask, NULL) < 0) return(-1); return(status); } 20. Reliable implementation of sleep #include "apue.h" static void sig_alrm(int signo) { /* nothing to do, just returning wakes up sigsuspend() */ } unsigned int sleep(unsigned int nsecs) { struct sigaction newact, oldact; sigset_t newmask, oldmask, suspmask; unsigned int unslept; /* set our handler, save previous information */ newact.sa_handler = sig_alrm; sigemptyset(&newact.sa_mask); newact.sa_flags = 0; sigaction(SIGALRM, &newact, &oldact); /* block SIGALRM and save current signal mask */ sigemptyset(&newmask); sigaddset(&newmask, SIGALRM); sigprocmask(SIG_BLOCK, &newmask, &oldmask); alarm(nsecs); suspmask = oldmask; /* make sure SIGALRM isn't blocked */ sigdelset(&suspmask, SIGALRM); /* wait for any signal to be caught */ sigsuspend(&suspmask); /* some signal has been caught, SIGALRM is now blocked */ unslept = alarm(0); sigaction(SIGALRM, &oldact, NULL); /* reset previous action */ /* reset signal mask, which unblocks SIGALRM */ sigprocmask(SIG_SETMASK, &oldmask, NULL); return(unslept); } 21. How to handle SIGTSTP #include "apue.h" #define BUFFSIZE 1024 static void sig_tstp(int); int main(void) {

int n; char buf[BUFFSIZE]; /* * Only catch SIGTSTP if we're running with a job-control shell. */ if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) signal(SIGTSTP, sig_tstp); while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) if (write(STDOUT_FILENO, buf, n) != n) err_sys("write error"); if (n < 0) err_sys("read error"); exit(0); } static void sig_tstp(int signo) /* signal handler for SIGTSTP */ { sigset_t mask; /* ... move cursor to lower left corner, reset tty mode ... */ /* * Unblock SIGTSTP, since it's blocked while we're handling it. */ sigemptyset(&mask); sigaddset(&mask, SIGTSTP); sigprocmask(SIG_UNBLOCK, &mask, NULL); signal(SIGTSTP, SIG_DFL); /* reset disposition to default */ kill(getpid(), SIGTSTP); /* and send the signal to ourself */ /* we won't return from the kill until we're continued */ signal(SIGTSTP, sig_tstp); /* reestablish signal handler */ /* ... reset tty mode, redraw screen ... */ }

DAEMON PROCESSES
22.Initialize

a daemon process

#include"apue.h" #include<syslog.h> #include<fcntl.h> #include<sys/resource.h> void daemonize(const char *cmd) { int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; struct sigaction sa; /* * Clear file creation mask. */ umask(0); /* * Get maximum number of file descriptors. */ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) err_quit("%s: can't get file limit", cmd); /* * Become a session leader to lose controlling TTY.

*/ if ((pid = fork()) < 0) err_quit("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0); setsid(); /* * Ensure future opens won't allocate controlling TTYs. */ sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) err_quit("%s: can't ignore SIGHUP"); if ((pid = fork()) < 0) err_quit("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0); /* * Change the current working directory to the root so * we won't prevent file systems from being unmounted. */ if (chdir("/") < 0) err_quit("%s: can't change directory to /"); /* * Close all open file descriptors. */ if (rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; for (i = 0; i < rl.rlim_max; i++) close(i); /* * Attach file descriptors 0, 1, and 2 to /dev/null. */ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); /* * Initialize the log file. */ openlog(cmd, LOG_CONS, LOG_DAEMON); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpected file descriptors %d %d %d",fd0, fd1, fd2); exit(1); } } 23.Ensure that only one copy of a daemon is running #include<unistd.h> #include<stdlib.h> #include<fcntl.h> #include<syslog.h> #include<errno.h> #include<stdio.h> #include<sys/stat.h> #include<string.h> #define LOCKFILE "/var/run/daemon.pid" #define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

extern int lockfile(int); int already_running(void) { int fd; char buf[16]; fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE); if (fd < 0) { syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno)); exit(1); } if (lockfile(fd) < 0) { if (errno == EACCES || errno == EAGAIN) { close(fd); return(1); } syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno)); exit(1); } ftruncate(fd, 0); sprintf(buf, "%ld", (long)getpid()); write(fd, buf, strlen(buf)+1); return(0); } 24.Daemon rereading configuration files #include "apue.h" #include <pthread.h> #include <syslog.h> sigset_t mask; extern int already_running(void); void reread(void) { /* ... */ } void *thr_fn(void *arg) { int err, signo; for (;;) { err = sigwait(&mask, &signo); if (err != 0) { syslog(LOG_ERR, "sigwait failed"); exit(1); } switch (signo) { case SIGHUP: syslog(LOG_INFO, "Re-reading configuration file"); reread(); break; case SIGTERM: syslog(LOG_INFO, "got SIGTERM; exiting");

exit(0); default: syslog(LOG_INFO, "unexpected signal %d\n", signo); } } return(0); } int main(int argc, char *argv[]) { int err; pthread_t tid; char *cmd; struct sigaction sa; if ((cmd = strrchr(argv[0], '/')) == NULL) cmd = argv[0]; else cmd++; if (already_running()) { syslog(LOG_ERR, "daemon already running"); exit(1); } sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) err_quit("%s: can't restore SIGHUP default"); sigfillset(&mask); if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0) err_exit(err, "SIG_BLOCK error"); err = pthread_create(&tid, NULL, thr_fn, 0); if (err != 0) err_exit(err, "can't create thread"); exit(0); } 24.Alternate

implementation of daemon rereading configuration files

#include "apue.h" #include <syslog.h> #include <errno.h> extern int lockfile(int); extern int already_running(void); void reread(void) { /* ... */ } void sigterm(int signo) { syslog(LOG_INFO, "got SIGTERM; exiting"); exit(0); } void sighup(int signo) { syslog(LOG_INFO, "Re-reading configuration file");

reread(); } int main(int argc, char *argv[]) { char *cmd; struct sigaction sa; if ((cmd = strrchr(argv[0], '/')) == NULL) cmd = argv[0]; else cmd++; daemonize(cmd); /* * Make sure only one copy of the daemon is running. */ if (already_running()) { syslog(LOG_ERR, "daemon already running"); exit(1); } /* * Handle signals of interest. */ sa.sa_handler = sigterm; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGHUP); sa.sa_flags = 0; if (sigaction(SIGTERM, &sa, NULL) < 0) { syslog(LOG_ERR, "can't catch SIGTERM: %s", strerror(errno)); exit(1); } sa.sa_handler = sighup; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGTERM); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) { syslog(LOG_ERR, "can't catch SIGHUP: %s", strerror(errno)); exit(1); } /* * Proceed with the rest of the daemon. */ /* ... */ exit(0); }

You might also like