Unix Lab Programs
Unix Lab Programs
Unix Lab Programs
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
} 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;
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
#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);
if(argc!=3) { }
{ change_mode(); 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; }
#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); }
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
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
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:
} 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) {
} }
/*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); }
/* 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); }
Process Relationships
1. Creating
#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.
3. System
#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.
6. Calling
#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
10.Example
#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
#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); }
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: "); }
16.Routines
#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
#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
#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
#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); }