- , fd = open( , O_RDWR | O_SYNC); , write -  . , . creat, . mknod: #include <sys/sysmacros.h> dev_t dev = makedev(major, minor); /* (major << 8) | minor */ mknod( ߔ, |, dev); dev - (,) ;  - (0777)|=;  - S_IFIFO, S_IFCHR, S_IFBLK include- <sys/stat.h>. mknod ( S_IFIFO). , , - , , . / , ( ). ____________________ |= () - , "" ( - ) - . . , 1992-95 - 251 - UNIX ENODEV. stat() , . dev_t st_dev; - ( ), dev_t st_rdev; , , : #include <sys/types.h> #include <sys/stat.h> void main(ac, av) char *av[]; { struct stat st1, st2; int eq; if(ac != 3) exit(13); stat(av[1], &st1); stat(av[2], &st2); if(eq = (st1.st_ino == st2.st_ino && /* I- */ st1.st_dev == st2.st_dev)) /* */ printf("%s %s - \n",av[1],av[2]); exit( !eq ); } , : ino=2 *------ / \ /\ /dev/hd0 / /\ /\ \ *-/mnt/hd1 : * ino=2 FS /dev/hd1 / \ (removable FS) /\ \ , , /dev/hd1, /mnt/hd1 "" , mount("/dev/hd1", "/mnt/hd1", 0); umount("/dev/hd1"); (, , , - ). /mnt/hd1 , /mnt/hd1 () - /dev/hd1. mount point , "." ".." : struct stat st1, st2; stat("/mnt/hd1/.", &st1); stat("/mnt/hd1/..", &st2); if( st1.st_dev != st2.st_dev) ... ; /*mount point*/ st1 st_dev /dev/hd1, st2 - , - . . - I-. stat <sys/ino.h> <sys/inode.h> <sys/stat.h> . , 1992-95 - 252 - UNIX struct dinode struct inode struct stat // ushort di_mode i_mode st_mode // short di_nlink i_nlink st_nlink // I- ushort --- i_number st_ino // ushort di_uid i_uid st_uid // ushort di_gid i_gid st_gid // off_t di_size i_size st_size // time_t di_ctime i_ctime st_ctime // (write) time_t di_mtime i_mtime st_mtime // (read/write) time_t di_atime i_atime st_atime // , dev_t --- i_dev st_dev // , . dev_t --- i_rdev st_rdev // char di_addr[39] i_addr[] // cnt_t i_count // - , , . - UNIX . 6.10.1. pwd, . #define U42 , - (14 ). . , 1992-95 - 253 - UNIX /* pwd. * getwd() . */ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #define ediag(e,r) (e) /* * getwd() . * NULL, pathname * . */ #ifndef MAXPATHLEN #define MAXPATHLEN 128 #endif #define CURDIR "." /* */ #define PARENTDIR ".." /* */ #define PATHSEP "/" /* */ #define ROOTDIR "/" /* */ #define GETWDERR(s) strcpy(pathname, (s)); #define CP(to,from) strncpy(to,from.d_name,DIRSIZ),to[DIRSIZ]='\0' char *strcpy(char *, char *); char *strncpy(char *, char *, int); char *getwd(char *pathname); static char *prepend(char *dirname, char *pathname); static int pathsize; /* */ #ifndef U42 char *getwd(char *pathname) { char pathbuf[MAXPATHLEN]; /* temporary pathname buffer */ char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */ dev_t rdev; /* root device number */ int fil = (-1); /* directory file descriptor */ ino_t rino; /* root inode number */ struct direct dir; /* directory entry struct */ struct stat d ,dd; /* file status struct */ /* d - "." dd - ".." | dname */ char dname[DIRSIZ+1]; /* an directory entry */ pathsize = 0; *pnptr = '\0'; if (stat(ROOTDIR, &d) < 0) { GETWDERR(ediag("getwd: can't stat /", "getwd: stat /")); return (NULL); } rdev = d.st_dev; /* , */ rino = d.st_ino; /* I-, */ . , 1992-95 - 254 - UNIX for (;;) { if (stat(CURDIR, &d) < 0) { CantStat: GETWDERR(ediag("getwd: can't stat .", "getwd: stat .")); goto fail; } if (d.st_ino == rino && d.st_dev == rdev) break; /* */ if ((fil = open(PARENTDIR, O_RDONLY)) < 0) { GETWDERR(ediag("getwd: can't open ..", "getwd: ..")); goto fail; } if (chdir(PARENTDIR) < 0) { GETWDERR(ediag("getwd: can't chdir to ..", "getwd: ..")); goto fail; } if (fstat(fil, &dd) < 0) goto CantStat; if (d.st_dev == dd.st_dev) { /* */ if (d.st_ino == dd.st_ino) { /* ".." == "." */ close(fil); break; } do { if (read(fil, (char *) &dir, sizeof(dir)) < sizeof(dir) ){ ReadErr: close(fil); GETWDERR(ediag("getwd: read error in ..", "getwd: ..")); goto fail; } } while (dir.d_ino != d.st_ino); CP(dname,dir); } else /* ".." : mount point */ do { if (read(fil, (char *) &dir, sizeof(dir)) < sizeof(dir)) goto ReadErr; if( dir.d_ino == 0 ) /* */ continue; CP(dname,dir); if (stat(dname, &dd) < 0) { sprintf (pathname, "getwd: %s %s", ediag ("can't stat", " stat"), dname); goto fail; } } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); close(fil); pnptr = prepend(PATHSEP, prepend(dname, pnptr)); } . , 1992-95 - 255 - UNIX if (*pnptr == '\0') /* == */ strcpy(pathname, ROOTDIR); else { strcpy(pathname, pnptr); if (chdir(pnptr) < 0) { GETWDERR(ediag("getwd: can't change back to .", "getwd: .")); return (NULL); } } return (pathname); fail: close(fil); chdir(prepend(CURDIR, pnptr)); return (NULL); } #else /* U42 */ extern char *strcpy (); extern DIR *opendir(); char *getwd (char *pathname) { char pathbuf[MAXPATHLEN];/* temporary pathname buffer */ char *pnptr = &pathbuf[(sizeof pathbuf) - 1];/* pathname pointer */ char *prepend (); /* prepend dirname to pathname */ dev_t rdev; /* root device number */ DIR * dirp; /* directory stream */ ino_t rino; /* root inode number */ struct dirent *dir; /* directory entry struct */ struct stat d, dd; /* file status struct */ pathsize = 0; *pnptr = '\0'; stat (ROOTDIR, &d); rdev = d.st_dev; rino = d.st_ino; for (;;) { stat (CURDIR, &d); if (d.st_ino == rino && d.st_dev == rdev) break; /* reached root directory */ if ((dirp = opendir (PARENTDIR)) == NULL) { GETWDERR ("getwd: can't open .."); goto fail; } if (chdir (PARENTDIR) < 0) { closedir (dirp); GETWDERR ("getwd: can't chdir to .."); goto fail; } . , 1992-95 - 256 - UNIX fstat (dirp -> dd_fd, &dd); if (d.st_dev == dd.st_dev) { if (d.st_ino == dd.st_ino) { /* reached root directory */ closedir (dirp); break; } do { if ((dir = readdir (dirp)) == NULL) { closedir (dirp); GETWDERR ("getwd: read error in .."); goto fail; } } while (dir -> d_ino != d.st_ino); } else do { if ((dir = readdir (dirp)) == NULL) { closedir (dirp); GETWDERR ("getwd: read error in .."); goto fail; } stat (dir -> d_name, &dd); } while (dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); closedir (dirp); pnptr = prepend (PATHSEP, prepend (dir -> d_name, pnptr)); } if (*pnptr == '\0') /* current dir == root dir */ strcpy (pathname, ROOTDIR); else { strcpy (pathname, pnptr); if (chdir (pnptr) < 0) { GETWDERR ("getwd: can't change back to ."); return (NULL); } } return (pathname); fail: chdir (prepend (CURDIR, pnptr)); return (NULL); } #endif . , 1992-95 - 257 - UNIX /* * prepend() tacks a directory name onto the front of a pathname. */ static char *prepend ( register char *dirname, /* */ register char *pathname /* */ ) { register int i; /* */ for (i = 0; *dirname != '\0'; i++, dirname++) continue; if ((pathsize += i) < MAXPATHLEN) while (i-- > 0) *--pathname = *--dirname; return (pathname); } #ifndef CWDONLY void main(){ char buffer[MAXPATHLEN+1]; char *cwd = getwd(buffer); printf( "%s%s\n", cwd ? "": "ERROR:", buffer); } #endif 6.10.2. canon(), , ..  ( ), "." "..", - '/'. , , /usr/abs/C- book. . -> /usr/abs/C-book .. -> /usr/abs ../.. -> /usr ////.. -> / /aa -> /aa /aa/../bb -> /bb cc//dd/../ee -> /usr/abs/C-book/cc/ee ../a/b/./d -> /usr/abs/a/b/d : #include <stdio.h> /* , */ #define SLASH '/' extern char *strchr (char *, char), *strrchr(char *, char); struct savech{ char *s, c; }; #define SAVE(sv, str) (sv).s = (str); (sv).c = *(str) #define RESTORE(sv) if((sv).s) *(sv).s = (sv).c /* : void main(){ char *d = "hello"; struct savech ss; SAVE(ss, d+3); *(d+3) = '\0'; printf("%s\n", d); RESTORE(ss); printf("%s\n", d); } */ /* */ struct savech parentdir(char *path){ char *last = strrchr( path, SLASH ); . , 1992-95 - 258 - UNIX char *first = strchr ( path, SLASH ); struct savech sp; sp.s = NULL; sp.c = '\0'; if( last == NULL ) return sp; /* */ if( last[1] == '\0' ) return sp; /* */ if( last == first ) /* : /DIR */ last++; sp.s = last; sp.c = *last; *last = '\0'; return sp; } #define isfullpath(s) (*s == SLASH) /* */ void canon( char *where, /* */ char *cwd, /* */ char *path /* */ ){ char *s, *slash; /* - */ if( isfullpath(path)){ s = strchr(path, SLASH); /* @ */ strncpy(where, path, s - path + 1); where[s - path + 1] = '\0'; /* strcpy(where, "/"); */ path = s+1; /* '/' */ } else strcpy(where, cwd); /* */ do{ if(slash = strchr(path, SLASH)) *slash = '\0'; /* path */ if(*path == '\0' || !strcmp(path, ".")) ; /* "." "///" */ else if( !strcmp(path, "..")) (void) parentdir(where); else{ int len = strlen(where); /* */ if( where[len-1] != SLASH ){ where[len] = SLASH; where[len+1] = '\0'; } strcat( where+len, path ); /* +len * strcat(); */ } if(slash){ *slash = SLASH; /* */ path = slash + 1; } } while (slash != NULL); } char cwd[256], input[256], output[256]; void main(){ /* . * getcwd() - , * popen() pwd ( ). */ getcwd(cwd, sizeof cwd); while( gets(input)){ canon(output, cwd, input); printf("%-20s -> %s\n", input, output); } } . , 1992-95 - 259 - UNIX ( MS DOS) "" , /*@*/. , DOS isfullpath - C:\aaa\bbb,  . 6.11. -. select, , , - . : -  ( ) - . , . 6.11.1. /* select() * . * . * : tty01 tty02 * sleep 30000 * tty00 select /dev/tty01 /dev/tty02 * - tty01 tty02 * : cc select.c -o select -lsocket */ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> /* fd_set, FD_SET, e.t.c. */ #include <sys/param.h> /* NOFILE */ #include <sys/select.h> #include <sys/time.h> #include <sys/filio.h> /* FIONREAD */ #define max(a,b) ((a) > (b) ? (a) : (b)) char buf[512]; /* */ int fdin, fdout; /* stdin, stdout */ int nready; /* */ int nopen; /* */ int maxfd = 0; /* */ int nfds; /* */ int f; /* */ fd_set set, rset; /* */ /* */ struct _fds { int fd; /* */ char name[30]; /* */ } fds[ NOFILE ] = { /* NOFILE - . */ { 0, "stdin" }, { 1, "stdout" }, { 2, "stderr" } /* - */ }; struct timeval timeout, rtimeout; /* */ char *N( int fd ){ register i; for(i=0; i < NOFILE; i++) if(fds[i].fd == fd ) return fds[i].name; return "???"; } . , 1992-95 - 260 - UNIX void main( int ac, char **av ){ nopen = 3; /* stdin, stdout, stderr */ for( f = 3; f < NOFILE; f++ ) fds[f].fd = (-1); fdin = fileno(stdin); fdout = fileno(stdout); setbuf(stdout, NULL); /* */ FD_ZERO(&set); /* */ for(f=1; f < ac; f++ ) if((fds[nopen].fd = open(av[f], O_RDONLY)) < 0 ){ fprintf(stderr, "Can't read %s\n", av[f] ); continue; } else { FD_SET(fds[nopen].fd, &set ); /* */ maxfd = max(maxfd, fds[nopen].fd ); strncpy(fds[nopen].name, av[f], sizeof(fds[0].name) - 1); nopen++; } if( nopen == 3 ){ fprintf(stderr, "Nothing is opened\n"); exit(1); } FD_SET(fdin, &set); /* stdin */ maxfd = max(maxfd, fdin ); nopen -= 2; /* stdout stderr select */ timeout.tv_sec = 10; /* */ timeout.tv_usec = 0; /* */ /* nfds - , * . * nfds = NOFILE; (- ) * nfds = maxfd+1; (- = +1) * ( +1 .. fd 0, - 1). */ nfds = maxfd + 1; while( nopen ){ rset = set; rtimeout = timeout; /* , .. */ /* FIFO-, , pty, socket-, stream- */ nready = select( nfds, &rset, NULL, NULL, &rtimeout ); /* &rtimeout NULL, * ( ) */ if( nready <= 0 ){ /* */ fprintf(stderr, "Timed out, nopen=%d\n", nopen); continue; } . , 1992-95 - 261 - UNIX /* */ for(f=0; f < nfds; f++ ) if( FD_ISSET(f, &rset)){ /* f */ int n; /* FIONREAD * * . */ if(ioctl(f, FIONREAD, &n) < 0) perror("FIONREAD"); else printf("%s have %d bytes.\n", N(f), n); if((n = read(f, buf, sizeof buf)) <= 0 ){ eof: FD_CLR(f, &set); /* */ close(f); nopen--; fprintf(stderr, "EOF in %s\n", N(f)); } else { fprintf(stderr, "\n%d bytes from %s:\n", n, N(f)); write(fdout, buf, n); if( n == 4 && !strncmp(buf, "end\n", 4)) /* ncmp, .. buf \0 */ goto eof; } } } exit(0); } 6.11.2. , . . . , 1992-95 - 262 - UNIX /* * script.c * . * * / select() ( ttyp+ptyp). */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <signal.h> #include <sys/param.h> /* NOFILE */ #include <sys/times.h> #include <sys/wait.h> #include <errno.h> #ifdef TERMIOS # include <termios.h> # define TERMIO struct termios # define GTTY(fd, tadr) tcgetattr(fd, tadr) # define STTY(fd, tadr) tcsetattr(fd, TCSADRAIN, tadr) #else # include <termio.h> # define TERMIO struct termio # define GTTY(fd, tadr) ioctl(fd, TCGETA, tadr) # define STTY(fd, tadr) ioctl(fd, TCSETAW, tadr) #endif . , 1992-95 - 263 - UNIX #ifdef __SVR4 # include <stropts.h> /* STREAMS i/o */ extern char *ptsname(); #endif #if defined(ISC2_2) # include <sys/bsdtypes.h> #else # include <sys/select.h> #endif #ifndef BSIZE # define BSIZE 512 #endif #define LOGFILE "/usr/spool/scriptlog" #define max(a,b) ((a) > (b) ? (a) : (b)) extern int errno; TERMIO told, tnew, ttypmodes; FILE *fpscript = NULL; /* ( ) */ int go = 0; int scriptflg = 0; int halfflag = 0; /* HALF DUPLEX */ int autoecho = 0; char *protocol = "typescript"; #define STDIN 0 /* fileno(stdin) */ #define STDOUT 1 /* fileno(stdout) */ #define STDERR 2 /* fileno(stderr) */ /* ? */ int tty_stdin, tty_stdout, tty_stderr; int TTYFD; void wm_checkttys(){ TERMIO t; tty_stdin = ( GTTY(STDIN, &t) >= 0 ); tty_stdout = ( GTTY(STDOUT, &t) >= 0 ); tty_stderr = ( GTTY(STDERR, &t) >= 0 ); if ( tty_stdin ) TTYFD = STDIN; else if( tty_stdout ) TTYFD = STDOUT; else if( tty_stderr ) TTYFD = STDERR; else { fprintf(stderr, "Cannot access tty\n"); exit(7); } } . , 1992-95 - 264 - UNIX /* */ struct ptypair { char line[25]; /* : /dev/ttyp? */ int pfd; /* master pty */ long in_bytes; /* */ long out_bytes; /* */ int pid; /* */ time_t t_start, t_stop; /* */ char *command; /* */ } PP; /* - * SIGCLD */ char Reason[128]; void ondeath(sig){ int pid; extern void wm_done(); int status; int fd; /* */ while((pid = wait(&status)) > 0 ){ if( WIFEXITED(status)) sprintf( Reason, "Pid %d died with retcode %d", pid, WEXITSTATUS(status)); else if( WIFSIGNALED(status)) { sprintf( Reason, "Pid %d killed by signal #%d", pid, WTERMSIG(status)); #ifdef WCOREDUMP if(WCOREDUMP(status)) strcat( Reason, " Core dumped" ); #endif } else if( WIFSTOPPED(status)) sprintf( Reason, "Pid %d suspended by signal #%d", pid, WSTOPSIG(status)); } wm_done(0); } void wm_init(){ wm_checkttys(); GTTY(TTYFD, &told); /* "" __ */ tnew = told; tnew.c_cc[VINTR] = '\0'; tnew.c_cc[VQUIT] = '\0'; tnew.c_cc[VERASE] = '\0'; tnew.c_cc[VKILL] = '\0'; #ifdef VSUSP tnew.c_cc[VSUSP] = '\0'; #endif . , 1992-95 - 265 - UNIX /* CBREAK */ tnew.c_cc[VMIN] = 1; tnew.c_cc[VTIME] = 0; tnew.c_cflag &= ~(PARENB|CSIZE); tnew.c_cflag |= CS8; tnew.c_iflag &= ~(ISTRIP|ICRNL); tnew.c_lflag &= ~(ICANON|ECHO|ECHOK|ECHOE|XCASE); tnew.c_oflag &= ~OLCUC; /* c_oflag ONLCR TAB3, */ /* */ ttypmodes = told; /* : * ONLCR: \n --> \r\n * TAB3: \t --> */ ttypmodes.c_oflag &= ~(ONLCR|TAB3); (void) signal(SIGCLD, ondeath); } void wm_fixtty(){ STTY(TTYFD, &tnew); } void wm_resettty(){ STTY(TTYFD, &told); } /* */ struct ptypair wm_ptypair(){ struct ptypair p; #ifdef __SVR4 p.pfd = (-1); p.pid = 0; p.in_bytes = p.out_bytes = 0; /* master side pty ( slave) */ if((p.pfd = open( "/dev/ptmx", O_RDWR)) < 0 ){ /* STREAMS driver. * , * , master- * ! */ perror( "Open /dev/ptmx" ); goto err; } . , 1992-95 - 266 - UNIX # ifdef notdef /* slave- . */ if( grantpt (p.pfd) < 0 ){ perror( "grantpt"); exit(errno); } # endif /* slave- : open() */ if( unlockpt(p.pfd) < 0 ){ perror( "unlockpt"); exit(errno); } /* slave--. */ strcpy( p.line, ptsname(p.pfd)); #else register i; char c; struct stat st; p.pfd = (-1); p.pid = 0; p.in_bytes = p.out_bytes = 0; strcpy( p.line, "/dev/ptyXX" ); for( c = 'p'; c <= 's'; c++ ){ p.line[ strlen("/dev/pty") ] = c; p.line[ strlen("/dev/ptyp")] = '0'; if( stat(p.line, &st) < 0 ) goto err; for(i=0; i < 16; i++){ p.line[ strlen("/dev/ptyp") ] = "0123456789abcdef" [i] ; if((p.pfd = open( p.line, O_RDWR )) >= 0 ){ p.line[ strlen("/dev/") ] = 't'; return p; } } } #endif err: return p; } . , 1992-95 - 267 - UNIX /* script */ void write_stat( in_bytes, out_bytes, time_here , name, line, at ) long in_bytes, out_bytes; time_t time_here; char *name; char *line; char *at; { FILE *fplog; struct flock lock; if((fplog = fopen( LOGFILE, "a" )) == NULL ) return; lock.l_type = F_WRLCK; lock.l_whence = 0; lock.l_start = 0; lock.l_len = 0; /* */ fcntl ( fileno(fplog), F_SETLKW, &lock ); fprintf( fplog, "%s (%s) %ld bytes_in %ld bytes_out %ld secs %s %s %s", PP.command, Reason, in_bytes, out_bytes, time_here, name, line, at ); fflush ( fplog ); lock.l_type = F_UNLCK; lock.l_whence = 0; lock.l_start = 0; lock.l_len = 0; /* */ fcntl ( fileno(fplog), F_SETLK, &lock ); fclose ( fplog ); } void wm_done(sig){ char *getlogin(), *getenv(), *logname = getlogin(); time( &PP.t_stop ); /* */ wm_resettty(); /* */ if( fpscript ) fclose(fpscript); if( PP.pid > 0 ) kill( SIGHUP, PP.pid ); /* " " */ if( go ) write_stat( PP.in_bytes, PP.out_bytes, PP.t_stop - PP.t_start, logname ? logname : getenv("LOGNAME"), PP.line, ctime(&PP.t_stop) ); printf( "\n" ); exit(0); } . , 1992-95 - 268 - UNIX /* */ void wm_startshell (ac, av) char **av; { int child, fd, sig; if( ac == 0 ){ static char *avshell[] = { "/bin/sh", "-i", NULL }; av = avshell; } if((child = fork()) < 0 ){ perror("fork"); wm_done(errno); } if( child == 0 ){ /* SON */ if( tty_stdin ) setpgrp(); /* */ /* */ if((fd = open( PP.line, O_RDWR )) < 0 ){ exit(errno); } /* */ if( fpscript ) fclose(fpscript); close( PP.pfd ); #ifdef __SVR4 /* Push pty compatibility modules onto stream */ ioctl(fd, I_PUSH, "ptem"); /* pseudo tty module */ ioctl(fd, I_PUSH, "ldterm"); /* line discipline module */ ioctl(fd, I_PUSH, "ttcompat"); /* BSD ioctls module */ #endif /* , */ if( fd != STDIN && tty_stdin ) dup2(fd, STDIN); if( fd != STDOUT && tty_stdout ) dup2(fd, STDOUT); if( fd != STDERR && tty_stderr ) dup2(fd, STDERR); if( fd > STDERR ) (void) close(fd); /* */ STTY(TTYFD, &ttypmodes); /* */ for(sig=1; sig < NSIG; sig++) signal( sig, SIG_DFL ); execvp(av[0], av); system( "echo OBLOM > HELP.ME"); perror("execl"); exit(errno); . , 1992-95 - 269 - UNIX } else { /* FATHER */ PP.pid = child; PP.command = av[0]; time( &PP.t_start ); PP.t_stop = PP.t_start; signal( SIGHUP, wm_done ); signal( SIGINT, wm_done ); signal( SIGQUIT, wm_done ); signal( SIGTERM, wm_done ); signal( SIGILL, wm_done ); signal( SIGBUS, wm_done ); signal( SIGSEGV, wm_done ); } } char buf[ BSIZE ]; /* */ /* /dev/pty? /dev/ttyp? *--------* *--------* /||| | | PP.pfd | | |||||<-STDOUT--| |<---------| |<-STDOUT---| \||| || ||<-STDERR---| |() | | | ------- | | STDIN | | | |.....|-STDIN--> |----------> |--STDIN--->| |_____| | | | | *--------* *--------* master slave */ /* */ void wm_select(){ int nready; int nfds; int maxfd; int nopen; /* */ register f; fd_set s