printf( "\nEND-------------------------------------\n" ); } disconnect(); /* otklyuchit'sya ot servera */ exit(0); } /* P_server.c ---------------------------------------------------------*/ /* * Process-server, prinimayushchij zaprosy i vypolnyayushchij ih. */ #include <stdio.h> #include <signal.h> #include <fcntl.h> #include "P_packet.h" int datapipe, ctrlpipe, datafile, got_sig; char *dataname = "/etc/passwd"; /* waiting for signal */ #define WAITSIG while( !got_sig ) void handler(nsig){ signal( SIGUSR1, handler ); /* reset trap */ got_sig++; } /* zavershenie raboty servera: unichtozhit' kanaly svyazi */ void die(nsig){ unlink( CNAME ); unlink( DNAME ); exit(0); /* Esli eti fajly byli otkryty klientami, * to klienty ne umrut, hotya imena fajlov i budut udaleny! */ } main(){ struct packet pk; struct packet sendpk; /* sdelat' standartnyj vyvod nebuferizovannym kanalom */ setbuf( stdout, NULL ); /* make unbuffered */ /* sozdat' kanaly svyazi */ mknod( DNAME, S_IFIFO | 0666, 0 ); /* create FIFO */ mknod( CNAME, S_IFIFO | 0666, 0 ); /* create FIFO */ /* po etim signalam budet vyzyvat'sya funkciya die() */ signal( SIGINT, die ); signal( SIGQUIT, die ); signal( SIGTERM, die ); /* Otkryt' upravlyayushchij kanal svyazi. O_NDELAY oznachaet, * chto fajl otkryvaetsya dlya "chteniya bez ozhidaniya", * t.e. esli kanal pust (net zayavok), to sistemnyj vyzov * read() ne budet "spat'", dozhidayas' poyavleniya informacii, * a prosto vernet 0 (prochitano 0 bajt). * |tot flag primenim takzhe k chteniyu s terminala. */ ctrlpipe = open( CNAME, O_RDONLY | O_NDELAY ); if( ctrlpipe < 0 ){ printf( "Can't open %s\n", CNAME ); die(0); } datafile = open( dataname, O_RDONLY ); if( datafile < 0 ){ printf( "Can't open %s\n", dataname ); die(0); } /* zaranee formiruem paket dlya otvetov */ sendpk.pk_code = SENDPID; sendpk.pk_pid = getpid(); /* server's pid */ sendpk.pk_blk = (-1); printf( "Server pid=%d\n", getpid()); handler(0); for(;;){ int n; static long i = 0L; /* active spin loop */ printf( "%20ld\r", i++ ); /* oprashivat' kanal naschet postupleniya zaprosov */ while((n = read( ctrlpipe, &pk, sizeof(pk))) > 0 ){ putchar( '\n' ); if( n != sizeof pk ){ printf( "Wrong packet size\n" ); continue; } /* obrabotat' prochitannyj zapros */ process( &pk, &sendpk ); } } die(0); } process( pkp, spkp ) struct packet *pkp, *spkp; { char pbuf[ PBUFSIZE ]; /* Zapis' v FIFO-fajl budet proizvedena tol'ko esli * on uzhe otkryt dlya chteniya */ datapipe = open( DNAME, O_WRONLY | O_NDELAY ); printf( "REQUEST TYPE_%d from pid=%d blk=%d\n", pkp->pk_code, pkp->pk_pid, pkp->pk_blk ); switch( pkp -> pk_code ){ case CONNECT: /* otvetit' svoim identifikatorom processa */ write( datapipe, spkp, sizeof( struct packet )); break; case RQ_READ: /* otvetit' blokom informacii iz fajla */ /* read block # pk_blk */ lseek( datafile, pkp -> pk_blk * (long)PBUFSIZE, 0 ); read( datafile, pbuf, PBUFSIZE ); write( datapipe, pbuf, PBUFSIZE ); break; case DISCONNECT: /* podtverdit' otklyuchenie */ printf( "Client pid=%d finished\n", pkp -> pk_pid ); write ( datapipe, spkp, sizeof( struct packet )); break; case BYE: /* zavershit'sya */ printf( "Server terminated.\n" ); kill( pkp-> pk_pid, SIGKILL ); die(0); default: printf( "Unknown packet type %d\n", pkp -> pk_code ); break; } close( datapipe ); /* "podtolknut'" otpravitelya signalom */ got_sig = 0; kill( pkp -> pk_pid , SIGUSR1 ); printf( "Waiting for reply... " ); /* zhdat' signala-podtverzhdeniya ot klienta */ WAITSIG; printf( "server continued\n" ); } /* Primer 26 */ /* Obshchenie processov pri pomoshchi obshchej pamyati i semaforov. * Vyzov: shms & * shmc a & shmc b & shmc c & */ /* --------------------------- fajl shm.h ----------------------- */ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <signal.h> #include <errno.h> extern errno; /* Sistemnyj kod oshibki */ struct connect { /* Struktura pochtovogo yashchika */ int pid; int msgnum; int max; char message[128]; /* tekst soobshcheniya */ }; #define NSEMS 3 /* chislo semaforov */ /* Imena semaforov */ #define EMPTY 0 /* 1 - yashchik pust; 0 - soderzhit pis'mo */ #define NOTEMPTY 1 /* negativ dlya EMPTY */ #define ACCESS 2 /* 1 - yashchik dostupen (zakryt); * 0 - yashchik uzhe otkryt kem-to eshche */ /* Znacheniya semaforov */ #define YES 1 #define NO 0 /* Operacii */ #define OPEN 1 #define CLOSE (-1) #define TEST_NO 0 #ifdef COMMENT Algoritm odnovremennogo izmeneniya semaforov: semop Dano: argument: chislo semaforov : nsems argument: velichiny izmeneniya : sem_op[i] v yadre: tekushchie znacheniya semaforov gruppy sem_id: sem[i] Algoritm: again: Sohranit' znacheniya vseh semaforov (dlya otmeny izmenenij); for(i=0; i<nsems; i++) /* OPEN */ if( sem_op[i] > 0 ){ sem[i] += sem_op[i]; razbudit'ZHdushchihSobytie( "sem[i]++" ); /* CLOSE */ }else if( sem_op[i] < 0 ){ if((newsm = sem[i] + sem_op[i]) >= 0 ){ sem[i] = newsm; if( sem[i] == 0 ) razbudit'ZHdushchihSobytie( "sem[i]==0" ); }else{ vosstanovit'VseSemafory; zhdat'Sobytie( "sem[i]++" ); goto again; } /* TEST0 */ }else{ /* sem_op[i] == 0 */ if( sem[i] != 0 ){ vosstanovit'VseSemafory; zhdat'Sobytie( "sem[i]==0" ); goto again; } } Algoritm sinhronizacii v nashej sheme KLIENT-SERVER: |----------------------------------------------------------------| |semafory: EMPTY ACCESS | |----------------------------------------------------------------| |nachal'noe znachenie: YES YES | |----------------------------------------------------------------| SERVER |================================================================| |loop: | |----------------------------------------------------------------| |zhdat': NO YES | |sdelat': NO(test0) NO(close) | |----------------------------------------------------------------| | prochest' pochtu; | |----------------------------------------------------------------| |iz: NO NO | |sdelat': YES(open) YES(open) | |----------------------------------------------------------------| | goto loop; | |================================================================| KLIENT |================================================================| |loop: | |----------------------------------------------------------------| |zhdat': YES YES | |sdelat': YES(test!=0) NO(close) | |----------------------------------------------------------------| | zapisat' pochtu; | |----------------------------------------------------------------| |iz: YES NO | |sdelat': NO(close) YES(open) | |----------------------------------------------------------------| | goto loop; | |================================================================| K sozhaleniyu, operacii test!=0 ne sushchestvuet - prihoditsya vvodit' dopolnitel'nyj semafor NOTEMPTY, negativnyj dlya EMPTY: |----------------------------------------------------------------| |semafory: EMPTY NOTEMPTY ACCESS | |----------------------------------------------------------------| |nachal'noe znachenie: YES NO YES | |----------------------------------------------------------------| SERVER |================================================================| |loop: | |----------------------------------------------------------------| |zhdat': NO - YES | |sdelat': NO(test0) - NO(close) | |----------------------------------------------------------------| | prochest' pochtu; | |----------------------------------------------------------------| |iz: NO YES NO | |sdelat': YES(open) NO(close) YES(open) | |----------------------------------------------------------------| | goto loop; | |================================================================| KLIENT |================================================================| |loop: | |----------------------------------------------------------------| |zhdat': - NO YES | |sdelat': - NO(test0) NO(close) | |----------------------------------------------------------------| | zapisat' pochtu; | |----------------------------------------------------------------| |iz: YES NO NO | |sdelat': NO(close) YES(open) YES(open) | |----------------------------------------------------------------| | goto loop; | |================================================================| #endif /*COMMENT*/ /* Obshchaya chast' servera i klienta ------------------------------- */ key_t key = 1917; /* Unikal'nyj klyuch dlya dostupa */ int shm_id; /* Deskriptor dlya dostupa k obshchej pamyati */ int sem_id; /* Deskriptor dlya dostupa k semaforam */ char name[40]; /* imya programmy */ char far *addr; struct connect far *caddr; struct sembuf ops[NSEMS]; /* EMPTY NOTEMPTY ACCESS */ short values[NSEMS] = { YES, NO, YES }; void semtell(msg, name) char *msg, *name; { int i; semctl(sem_id, NSEMS, GETALL, values); printf( "%s %-10s: znacheniya semaforov:", name, msg); for(i=0; i < NSEMS; i++) printf( " %d", values[i]); putchar('\n'); } void inisem(){ register i; for(i=0; i < NSEMS; i++ ) ops[i].sem_flg = 0; } /* --------------------------- fajl shms.c ----------------------- */ /* Shared memory server */ #include "shm.h" int npack; /* nomer soobshcheniya */ void cleanup(sig){ /* Unichtozhit' segment obshchej pamyati (eto nuzhno delat' yavno) */ shmctl( shm_id, IPC_RMID, NULL ); /* Unichtozhit' semafory */ semctl( sem_id, NSEMS, IPC_RMID, NULL ); if( npack ) printf( "\t** Vsego bylo %d soobshchenij **\n", npack+1); exit(0); } void main(){ register i; int pid = getpid(); FILE *fout; sprintf( name, "Server-%03d", pid ); for( i = 1; i <= SIGTERM; i++ ) signal( i, cleanup ); /* Sozdat' razdelyaemyj segment */ if((shm_id = shmget( key, sizeof(struct connect), 0644 | IPC_CREAT )) < 0 ){ perror( "shmget" ) ; exit(1); } /* Podklyuchit' obshchij segment k proizvol'nomu adresu */ if((addr = (char far *) shmat( shm_id, NULL, 0 )) == NULL ){ perror( "shmat" ); cleanup(); } caddr = (struct connect far *) addr; /* Sozdat' gruppu iz NSEMS semaforov */ if((sem_id = semget( key, NSEMS, 0644 |IPC_CREAT |IPC_EXCL)) < 0){ if(errno == EEXIST){ printf( "Server uzhe zapushchen\n");exit(2); } else{ perror( "semget" ); cleanup(); } } /* Zagruzit' nachal'nye znacheniya semaforov */ semctl( sem_id, NSEMS, SETALL, values ); setbuf(stdout, NULL); inisem(); printf( "Server is up now. CHitaj fajl MESSAGES.\n"); fout = fopen( "MESSAGES", "w"); for(;;npack++){ printf( "%s: zhdet pochty\n", name ); semtell("Vhod", name); ops[0].sem_num = EMPTY; ops[0].sem_op = TEST_NO; ops[1].sem_num = ACCESS; ops[1].sem_op = CLOSE; semop( sem_id, ops, 2 /* srazu dva semafora */); printf( "%s: GOT-%02d/%02d ot %d \"%s\"\n", name, caddr->msgnum, caddr->max, caddr->pid, caddr->message); fprintf( fout, "#%03d %02d/%02d ot %d \"%s\"\n", npack, caddr->msgnum, caddr->max, caddr->pid, caddr->message); if( ! strcmp(caddr->message, "-exit" )){ printf( "%s: zavershaet rabotu.\n", name ); cleanup(); } semtell("Vyhod", name); ops[0].sem_num = EMPTY ; ops[0].sem_op = OPEN; ops[1].sem_num = NOTEMPTY; ops[1].sem_op = CLOSE; ops[2].sem_num = ACCESS ; ops[2].sem_op = OPEN; semop( sem_id, ops, 3 /* srazu tri semafora */); } /*NOTREACHED*/ } /* --------------------------- fajl shmc.c ----------------------- */ /* Shared memory client */ #include "shm.h" void ignsigs(sig){ register i; for( i = 1; i <= SIGTERM; i++ ) signal( i, ignsigs ); printf( "Klient ignoriruet signaly,\n\ chtoby ne ostavlyat' zakrytyh semaforov v sluchae svoej smerti.\n" ); } void main(argc, argv) char **argv; { int pid = getpid(); int i, ntimes = 60; if( argc < 2 ){ fprintf( stderr, "Vyzov: %s soobshchenie [chisloPovtorov]\n", argv[0] ); fprintf( stderr, "soobshchenie \"-exit\" zavershaet server\n"); fprintf( stderr, "soobshchenie \"-info\" vydaet znacheniya semaforov\n"); exit(1); } if( argc > 2 ) ntimes = atoi(argv[2]); sprintf( name, "Client-%03d", pid); ignsigs(); srand( pid ); /* Poluchit' dostup k razdelyaemomu segmentu */ if((shm_id = shmget( key, sizeof(struct connect), 0644)) < 0 ){ perror( "shmget" ); exit(2); } /* Podklyuchit' obshchij segment k proizvol'nomu adresu */ if((addr = (char far *) shmat( shm_id, NULL, 0 )) == NULL ){ perror( "shmat" ); exit(3); } caddr = (struct connect far *) addr; /* Poluchit' dostup k semaforam */ if((sem_id = semget( key, NSEMS, 0644)) < 0 ){ perror( "semget" ); exit(4); } setbuf(stdout, NULL); inisem(); if( !strcmp(argv[1], "-info")){ semtell("Informaciya", name); exit(0); } for( i=0; i < ntimes; i++ ){ printf( "%s: zhdet pustogo yashchika\n", name); semtell("Vhod", name); ops[0].sem_num = NOTEMPTY; ops[0].sem_op = TEST_NO; ops[1].sem_num = ACCESS ; ops[1].sem_op = CLOSE; if( semop( sem_id, ops, 2 /* srazu dva semafora */) < 0) goto err; caddr->pid = pid; caddr->msgnum = i; caddr->max = ntimes; strncpy( caddr->message, argv[1], sizeof(caddr->message) - 1); printf( "%s: PUT-%02d \"%s\"\n", name, i, argv[1]); semtell("Vyhod", name); ops[0].sem_num = EMPTY ; ops[0].sem_op = CLOSE; ops[1].sem_num = NOTEMPTY; ops[1].sem_op = OPEN; ops[2].sem_num = ACCESS ; ops[2].sem_op = OPEN; if( semop( sem_id, ops, 3 /* srazu tri semafora */) < 0) goto err; if( rand()%2 ) sleep(2); /* pauza */ } shmdt( addr ); /* Otklyuchit'sya ot obshchego segmenta */ exit(0); err: perror("semop"); exit(5); } /* Primer 27 */ /* Kommunikaciya processov pri pomoshchi psevdo-terminala. * Dannaya programma pozvolyaet sohranyat' polnyj protokol raboty * ekrannoj programmy v fajl. * Ne ekrannye programmy dannaya versiya NE trassiruet, * poskol'ku sama rabotaet v "prozrachnom" rezhime. * * Variaciej dannoj programmy mozhet sluzhit' ispol'zovanie * sistemnogo vyzova select() vmesto zapuska neskol'kih processov. * * Programma takzhe illyustriruet "derevo" iz 5 processov. * Dannaya versiya napisana dlya UNIX System V. * TRACE__ * \ \ master slave * |ekran<======\(Reader)=======!~!<====(celevaya ) * / <==\ | ! !====>(programma) * \ | !P! | * | | !T! | * . . . . | | !Y! (Slave)-->Upravlyaet * klaviatura=|===|=>(Writer)=>!_! | \ semaforom * | | | | \ * | #####starter################## \ * |...................................| * ftty */ #include <stdio.h> #include <sys/types.h> #include <sys/signal.h> #include <termio.h> #include <sys/stat.h> #include <fcntl.h> extern int exit (); extern char *ttyname (); extern FILE * fopen (); extern errno; #define SEMAPHORE "/tmp/+++" /* semafornyj fajl */ #define TRACE "./TRACE" /* fajl s protokolom */ /* psevdoterminal svyazi */ /* master - eto chast', kotoraya vedet sebya kak FAJL i umeet * reagirovat' na nekotorye special'nye ioctl()-i */ #define PTY "/dev/ptyp0" /* master */ /* slave - eto chast', kotoraya vedet sebya kak drajver terminalov */ #define TTYP "/dev/ttyp0" /* slave */ int ptyfd; FILE * ftrace = NULL; /* pri preryvanii zavershit' rabotu processa "pisatelya" */ onintr () { closeVisual (); fprintf (stderr, "\rwriter finished\r\n"); exit (0); } /* zavershenie raboty processa-"chitatelya" */ bye () { if (ftrace) fclose (ftrace); fprintf (stderr, "\rreader finished\r\n"); exit (0); } int visual = 0; struct termio old, new; /* nastroit' rezhimy raboty terminala na "prozrachnyj" rezhim */ initVisual () { ioctl (0, TCGETA, &old); new = old; new.c_iflag &= ~ICRNL; new.c_lflag &= ~(ECHO | ICANON); new.c_oflag &= ~(TAB3 | ONLCR); new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; /* new.c_cc[VINTR] = ctrl('C'); */ new.c_cc[VQUIT] = 0; new.c_cc[VERASE] = 0; new.c_cc[VKILL] = 0; } /* vklyuchit' prozrachnyj rezhim */ openVisual () { if (visual) return; visual = 1; ioctl (0, TCSETAW, &new); } /* vyklyuchit' prozrachnyj rezhim */ closeVisual () { if (!visual) return; visual = 0; ioctl (0, TCSETAW, &old); } struct stat st; main (argc, argv) char **argv; { int r, /* pid processa-"chitatelya" */ w; /* pid processa-"pisatelya" */ if (argc == 1) { fprintf (stderr, "pty CMD ...\n"); exit (1); } initVisual (); if((ptyfd = open ( PTY , O_RDWR)) < 0){ fprintf(stderr, "Cannot open pty\n"); exit(2); } /* zapustit' process chteniya s psevdodispleya */ r = startReader (); /* zapustit' process chteniya s klaviatury */ w = startWriter (); sleep (2); /* zapustit' protokoliruemyj process */ startSlave (argv + 1, r, w); /* dozhdat'sya okonchaniya vseh potomkov */ while (wait (NULL) > 0); exit (0); } /* zapusk protokoliruemogo processa */ startSlave (argv, r, w) char **argv; { FILE * ftty; int pid; int tfd; char *tty = ttyname (1); /* polnoe imya nashego terminala */ if (!(pid = fork ())) { /* PTY SLAVE process */ ftty = fopen (tty, "w"); /* Dlya vydachi soobshchenij */ setpgrp (); /* obrazovat' novuyu gruppu processov ; * lishit'sya upravlyayushchego terminala */ /* zakryt' standartnye vvod, vyvod, vyvod oshibok */ close (0); close (1); close (2); /* pervyj otkrytyj terminal stanet upravlyayushchim dlya processa, * ne imeyushchego upravlyayushchego terminala. * Otkryvaem psevdoterminal (slave) v kachestve standartnyh * vvoda, vyvoda i vyvoda oshibok */ open ( TTYP, O_RDWR); open ( TTYP, O_RDWR); tfd = open ( TTYP, O_RDWR); if (tfd < 0) { fprintf (ftty, "\rSlave: can't read/write pty\r\n"); kill(r, SIGKILL); kill(w, SIGKILL); exit (1); } /* zapuskaem celevuyu programmu */ if (!(pid = fork ())) { fprintf (ftty, "\rCreating %s\r\n", SEMAPHORE); fflush (ftty); /* sozdaem semafornyj fajl */ close (creat (SEMAPHORE, 0644)); fprintf (ftty, "\rStart %s\r\n", argv[0]); fclose(ftty); /* zamenit' otvetvivshijsya process programmoj, * ukazannoj v argumentah */ execvp (argv[0], argv); exit (errno); } /* dozhidat'sya okonchaniya celevoj programmy */ while (wait (NULL) != pid); /* unichtozhit' semafor, chto yavlyaetsya priznakom zaversheniya * dlya processov chteniya i zapisi */ unlink (SEMAPHORE); fprintf (ftty, "\rDied.\r\n"); fflush (ftty); /* ubit' processy chteniya i zapisi */ /* terminate reader & writer */ kill (r, SIGINT); kill (w, SIGINT); exit (0); } return pid; } /* Para master-processov chteniya i zapisi */ /* zapusk processa chteniya s psevdoterminala (iz master-chasti) */ startReader () { char c[512]; int pid; int n; if (!(pid = fork ())) { /* chitat' dannye s ptyp na ekran i v fajl trassirovki */ signal (SIGINT, bye); /* ozhidat' poyavleniya semafora */ while (stat (SEMAPHORE, &st) < 0); fprintf (stderr, "\rReader: Hello\r\n"); ftrace = fopen (TRACE, "w"); /* rabotat', poka sushchestvuet semafornyj fajl */ while (stat (SEMAPHORE, &st) >= 0) { /* prochest' ocherednye dannye */ n = read (ptyfd, c, 512); if( n > 0 ) { /* zapisat' ih na nastoyashchij terminal */ fwrite( c, sizeof(char), n, stdout ); /* i v fajl protokola */ fwrite( c, sizeof(char), n, ftrace ); fflush (stdout); } } bye (); } return pid; } /* zapusk processa chteniya dannyh s klaviatury i zapisi * ih na "psevdoklaviaturu". |ti dannye protokolirovat' ne nado, * tak kak ih eho-otobrazit sam psevdoterminal */ startWriter () { char c; int pid; if (!(pid = fork ())) { /* chitat' klaviaturu moego terminala i vydavat' eto v ptyp */ openVisual (); /* nash terminal - v prozrachnyj rezhim */ signal (SIGINT, onintr); while (stat (SEMAPHORE, &st) < 0); fprintf (stderr, "\rWriter: Hello\r\n"); /* rabotat', poka sushchestvuet semafornyj fajl */ while (stat (SEMAPHORE, &st) >= 0) { read (0, &c, 1); /* chitat' bukvu s klaviatury */ write (ptyfd, &c, 1); /* zapisat' ee na master-pty */ } onintr (); /* zavershit'sya */ } return pid; } /* Primer 28 */ /* Ocenka fragmentirovannosti toma fajlovoj sistemy * (neuporyadochennosti blokov v fajlah). * Illyustraciya raboty s fajlovoj sistemoj UNIX napryamuyu, * v obhod yadra sistemy. Dlya etogo vy dolzhny imet' prava * superpol'zovatelya !!! Dannaya programma otnositsya k klassu * "sistemnyh" (administratorskih) programm. * |ta programma predpolagaet kanonicheskuyu fajlovuyu sistemu V7 * ("staruyu"), a ne tu, kotoraya ispol'zuetsya nachinaya s BSD/4.2 i * v kotoroj vse ustroeno neskol'ko slozhnee i effektivnee. * Poetomu vy dolzhny budete modificirovat' etu programmu dlya * ispol'zovaniya v sovremennyh UNIX-sistemah. * Po motivam knigi M.Dansmura i G.Dejvisa. */ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/param.h> #include <sys/ino.h> /* struct dinode: disk inode */ #include <sys/stat.h> /* struct stat */ #include <sys/dir.h> /* struct direct */ char blkflag; /* pechatat' li nomera blokov fajla */ /* Otvedenie pamyati v kuche s vydachej oshibki, esli net pamyati */ char *MyAlloc( n ){ extern char *malloc(); char *ptr; ptr = malloc( n ); if( ptr == NULL ){ fprintf( stderr, "Cannot allocate %d bytes\n", n ); exit(77); } return ptr; } char DEV[] = "/dev" ; /* katalog, gde lezhat vse fajly ustrojstv */ /* Opredelit' imya ustrojstva po ego st_dev nomeru. * Poisk - po katalogu /dev */ char *whichdev( dev ) dev_t dev; { struct stat s; struct direct d; long i; int fd; /* deskriptor chteniya kataloga */ long dsize; /* chislo slotov kataloga */ char *devname; if( stat( DEV, &s ) < 0 ){ fprintf( stderr, "Cannot stat %s\n", DEV ); exit(1); } if((fd = open( DEV, O_RDONLY )) < 0 ){ fprintf( stderr, "Cannot read %s\n", DEV ); exit(2); } dsize = s.st_size / sizeof( struct direct ); /* chitat' katalog */ for( i = 0 ; i < dsize ; i++ ){ char leaf[ DIRSIZ + 1 ]; if( read( fd, &d, sizeof d ) != sizeof d ){ fprintf( stderr, "Cannot read %s\n", DEV ); exit(14); } if( ! d.d_ino ) continue; /* pustoj slot */ strncpy( leaf, d.d_name, DIRSIZ ); leaf[ DIRSIZ ] = '\0'; devname = MyAlloc( strlen( DEV ) + 1 + strlen( leaf ) + 1 ); /* /dev / xxxx \0 */ sprintf( devname, "%s/%s", DEV, leaf ); if( stat( devname, &s ) < 0 ){ fprintf( stderr, "Cannot stat %s\n", devname ); exit(3); } if( (s.st_mode & S_IFMT ) == S_IFBLK && s.st_rdev == dev ){ close(fd); return devname; } else free( devname ); } close( fd ); return NULL; } /* Fajlovaya sistema UNIX: konstanty podstroeny pod DEMOS 2.2 */ /* razmer bloka fajlovoj sistemy */ #define BLOCK 1024 /* libo stand. konstanta BSIZE iz <sys/param.h> */ /* chislo adresov blokov v kosvennom bloke */ #define NAPB (BLOCK/sizeof(daddr_t)) #define LNAPB ((long) NAPB ) /* chislo I-uzlov v bloke I-fajla */ #ifndef INOPB # define INOPB (BLOCK/sizeof(struct dinode)) #endif /* I-uzly - "pasporta" fajlov. I-uzly raspolozheny v nachale diska, v oblasti, nazyvaemoj I-fajl. V I-uzle fajla soderzhatsya: razmer fajla, kody dostupa, vladelec fajla, i.t.p. V chastnosti - adresa blokov fajla hranyatsya v massive di_addr: 0 : ... snachala DIR0 adresov pervyh blokov IX1: 1 adres kosvennogo bloka, soderzhashchego adresa eshche NAPB blokov IX2: 1 adres kosv. bloka, soderzhashchego adresa NAPB kosv. blokov IX3: 1 adres kosv. bloka, soderzhashchego adresa NAPB kosv. blokov, soderzhashchih adresa eshche NAPB kosv. blokov Sisvyzov stat() vydaet kak raz chast' informacii iz I-uzla. Pole d_ino v kataloge hranit nomer I-uzla fajla. */ /* chislo adresnyh polej po 3 bajta v I-uzle */ #define NADDR 7 /* chislo pryamo adresuemyh blokov */ #define DIR0 ((long)(NADDR-3)) /* chislo pryamyh i pervyh kosvennyh blokov */ #define DIR1 (DIR0 + LNAPB) /* chislo pryamyh, pervyh i vtoryh kosvennyh blokov */ #define DIR2 (DIR0 + LNAPB + LNAPB*LNAPB) /* chislo pryamyh, vtoryh i tret'ih kosvennyh blokov */ #define DIR3 (DIR0 + LNAPB + LNAPB*LNAPB + LNAPB*LNAPB*LNAPB) /* indeks adresa pervichnogo bloka kosvennosti */ #define IX1 (NADDR-3) /* indeks adresa vtorichnogo bloka kosvennosti */ #define IX2 (NADDR-2) /* indeks adresa tretichnogo bloka kosvennosti */ #define IX3 (NADDR-1) /* Vydat' fizicheskij nomer bloka diska, * sootvetstvuyushchij logicheskomu bloku fajla */ daddr_t bmap( fd, ip, lb ) int fd; /* raw disk */ daddr_t lb; /* logicheskij blok */ struct dinode *ip; /* diskovyj I-uzel */ { long di_map[ NADDR ]; long dd_map[ NAPB ]; /* perevesti 3h bajtovye adresa v daddr_t */ l3tol( di_map, ip->di_addr, NADDR ); if( lb < DIR0 ) return di_map[ lb ]; if( lb < DIR1 ){ lb -= DIR0; lseek( fd, di_map[ IX1 ] * BLOCK, 0 ); read( fd, dd_map, BLOCK ); return dd_map[ lb % LNAPB ]; } if( lb < DIR2 ){ lb -= DIR1; lseek( fd, di_map[ IX2 ] * BLOCK, 0 ); read( fd, dd_map, BLOCK ); lseek( fd, dd_map[ lb / LNAPB ] * BLOCK, 0 ); read( fd, dd_map, BLOCK ); return dd_map[ lb % LNAPB ]; } if( lb < DIR2 ){ lb -= DIR2; lseek( fd, di_map[ IX3 ] * BLOCK, 0 ); read( fd, dd_map, BLOCK ); lseek( fd, dd_map[ lb / (LNAPB*LNAPB) ] * BLOCK, 0 ); read( fd, dd_map, BLOCK ); lseek( fd, dd_map[ lb % (LNAPB*LNAPB) ] * BLOCK, 0 ); read( fd, dd_map, BLOCK ); return dd_map[ lb % LNAPB ]; } fprintf( stderr, "Strange block %ld\n", lb ); exit(4); } /* Rasschitat' fragmentaciyu fajla, to est' srednee rasstoyanie mezhdu blokami fajla. Norma ravna faktoru interlivinga dlya dannogo ustrojstva. N SUM | p(j) - p(j-1) | j = 2 F = ---------------------------------- N p(j) - nomer fiz.bloka diska, sootvetstvuyushchego logich. bloku j Zamechaniya: 1) I-uzly numeruyutsya s 1 (a ne s 0), 0 - priznak pustogo mesta v kataloge (d_ino == 0). 2) I-fajl nachinaetsya so 2-ogo bloka diska (0-boot, 1-superblock) 3) esli fajl pust - on ne soderzhit blokov, N = 0, F = 0 4) esli blok ne otveden ("dyrka"), to ego adres raven 0L */ double xabs( l ) daddr_t l; { return ( l < (daddr_t) 0 ? -l : l ); } double getfrag( dev, ino ) char *dev; /* imya diska */ ino_t ino; /* I-uzel fajla */ { struct dinode db; int fd; /* deskriptor diska */ daddr_t i; /* log. blok */ daddr_t op; /* fiz.blok */ daddr_t ip; daddr_t nb; /* dlina fajla (blokov) */ long ni = 0L; /* chislo intervalov mezhdu blokami */ double ifrag = 0.0; if((fd = open( dev, O_RDONLY )) < 0 ){ fprintf( stderr, "Cannot read %s\n", dev ); perror( "open" ); exit(5); } /* prochitat' I-uzel s nomerom ino. * Fajl I-uzlov razmeshchen na diske nachinaya so 2 bloka * po INOPB uzlov v bloke. */ lseek( fd, (( 2 + ((ino-1)/INOPB)) * (long)BLOCK ) + ( sizeof(struct dinode) * ((ino-1) % INOPB)), 0 ); if( read( fd, &db, sizeof db ) != sizeof db ){ fprintf( stderr, "Cannot read %s\n", dev ); perror( "read" ); exit(6); } /* vychislit' razmer fajla v blokah */ nb = ((long) db.di_size + BLOCK - 1) / BLOCK; printf( "%4ld blk%s\t" , nb, nb > 1 ? "s" : " " ); /* ignorirovat' pustoj fajl */ if( nb == 0L ){ close(fd); return 0.0; } /* vychislit' fragmentaciyu */ op = bmap( fd, &db, 0L ); /* 0-block */ if( blkflag ) printf( "%ld ", op ); for( i = 1 ; i < nb ; i++ ){ ip = bmap( fd, &db, i ); if( blkflag ) printf( "%ld ", ip ); /* adresa, ravnye 0, sleduet ignorirovat' ("dyrki") */ if( ip && op ){ ni++; ifrag += xabs( ip - op ); } if( ip ) op = ip; } close ( fd ); if( blkflag ) putchar( '\n' ); return ni ? (ifrag/ni) : 0.0 ; } double process( name ) char *name; { struct stat ss; char *dn; double f; /* opredelyaem imya ustrojstva, na kotorom raspolozhen * fajl name */ if( stat( name, &ss ) < 0 ){ fprintf( stderr, "Cannot stat %s\n", name ); exit(8); } /* printf( "major %d minor %d", major(ss.st_dev), minor(ss.st_dev)); */ if((dn = whichdev( ss.st_dev )) == NULL){ fprintf( stderr, "Cannot determine device\n" ); exit(9); } printf( "%-14s on %-12s %12.3f\n", name, dn, f = getfrag(dn, ss.st_ino )); free( dn ); return f; } usage( name ) char *name; { fprintf( stderr, "Usage: %s [-b] file ...\n" , name ); exit(7); } main(ac, av) char *av[]; { double fr = 0.0; int n = 0; if( ac < 2 ) usage( av[0] ); if( !strcmp( av[1], "-b" )){ blkflag = 1; av++; ac--; } while( av[1] ){ fr += process( av[1] ); n++; av++; } if( n > 1 ) printf( "\nAverage %12.3f\n", fr / n ); exit(0); } /* Primer 29 */ /* * Programma vosstanovleniya blokov udalennogo fajla. * Rabotaet na kanonicheskoj fajlovoj sisteme UNIX (DEMOS). * Prosmatrivaet spisok svobodnyh blokov diska. * * |ta programma pozvolyaet vosstanovit' bloki TOLXKO CHTO udalennogo fajla. * Kak tol'ko vy udalili nuzhnyj fajl, nemedlenno prekratite lyubuyu * rabotu na mashine i dazhe otmontirujte disk s udalennym fajlom. * Zatem, nahodyas' na DRUGOM diske, vyzovite etu programmu. */ #include <stdio.h> #include <sys/types.h> #include <sys/param.h> /* BSIZE */ #include <sys/filsys.h> /* struct filsys */ #include <sys/fblk.h> /* struct fblk */ #include <fcntl.h> #include <ctype.h> /* #define BSIZE 1024 razmer bloka fajlovoj sistemy */ int fd; /* raw disk */ int fdout; /* deskriptor dlya spasennyh blokov na DRUGOM diske */ char blk[ BSIZE ], /* bufer dlya prochitannogo bloka */ sublk[ BSIZE ]; /* bufer dlya superbloka */ /* struktura superbloka */ struct filsys *super = (struct filsys *) sublk; /* schetchik */ long n = 0L; main( ac, av ) char *av[]; { daddr_t bno; /* nomer bloka iz spiska svobodnyh */ extern daddr_t alloc(); if( ac < 2 ){ fprintf( stderr, "Usage: %s disk\n", av[0] ); exit(1); } if((fd = open( av[1], O_RDONLY )) < 0 ){ fprintf( stderr, "Can't read %s\n", av[1] ); exit(2); } sync(); /* syncronize */ printf( "Vy dolzhny nahodit'sya na DRUGOM diske, nezheli %s,\n", av[1] ); printf( "chtoby bloki fajlov, v kotorye budut zapisany spasaemye\n"); printf( "bloki, vydelyalis' na drugom ustrojstve i ne portili\n" ); printf( "spisok svobodnyh blokov na %s\n\n", av[1] ); fflush( stdout ); sleep(2); /* prochest' superblok */ lseek( fd, (long) BSIZE, 0 ); read( fd, sublk, BSIZE ); fprintf( stderr, "%ld free blocks at %s (%6.6s)\n" , super->s_tfree, av[1], super->s_fpack ); /* Prosmotr svobodnyh blokov. Spisok svobodnyh blokov * imeet organizaciyu LIFO (stek), poetomu bloki * v spiske mogut idti ne v tom poryadke, * v kotorom oni shli v fajle. Uchtite, chto v fajle * krome blokov, soderzhashchih tekst fajla, * byvayut takzhe kosvennye adresnye bloki ! */ while((bno = alloc()) >= 0L ){ save( bno ); } printf( "total %ld\n", n ); exit(0); } /* Izvlech' ocherednoj blok iz spiska svobodnyh blokov */ daddr_t alloc(){ daddr_t bno; if( super -> s_nfree <= 0 ) /* chislo adresov svob. blokov, * hranimyh v superbloke */ goto nospace; /* chitaem nomer bloka iz spiska svobodnyh */ bno = super -> s_free[ --super -> s_nfree ]; if( bno == (daddr_t) 0 ) goto nospace; if( super -> s_nfree <= 0 ){ /* Prodolzhenie spiska - ne v superbloke, * a v special'nom dopolnitel'nom bloke fajlovoj sistemy. */ printf( "Indirect block %ld\n", bno ); lseek( fd, (long) BSIZE * bno , 0 ); read ( fd, blk, BSIZE ); super -> s_nfree = ((struct fblk *)blk) -> df_nfree ; memcpy( (char *) (super -> s_free), (char *) (((struct fblk *) blk) -> df_free ), sizeof( super->s_free)); } if( super -> s_nfree <= 0 || super -> s_nfree > NICFREE ){ fprintf( stderr, "Bad free count %d\n", super->s_nfree ); goto nospace; } if( super -> s_tfree ) /* kol-vo svobodnyh blokov */ super -> s_tfree --; return bno; nospace: super -> s_nfree = 0; super -> s_tfree = 0; return (-1L); /* konec spiska */ } /* peresylka uchastka pamyati dlinoj n bajt */ memcpy( to, from, n ) register char *to, *from; register n; { while( n > 0 ){ *to++ = *from++; n--; } } save( bno ) daddr_t bno; { register i; char answer[ 20 ]; printf( "block %ld-------------------\n", bno ); lseek( fd, bno * BSIZE , 0 ); read ( fd, blk, BSIZE ); for( i=0; i < BSIZE; i++ ) putchar(isprint(blk[i]) || isspace(blk[i]) ? blk[i] : '.' ); printf( "\n\7===> save block %ld ? ", bno ); fflush( stdout ); gets( answer ); if( *answer == 'y' || *answer == 'Y' ){ sprintf( answer, "#%012ld", n ); fdout = creat( answer, 0644 ); if( fdout < 0 ){ fprintf( stderr, "Can't create %s\n", answer ); exit(3); } write( fdout, blk, BSIZE ); close( fdout ); } n++; } /* Primer 30 */ /* /bin/cc -M2 -Ml -DMATCHONLY -LARGE dosfs.c match.c -o dosfs * Kopirovanie fajlov s diskety, zapisannoj v MS DOS, v UNIX. * Predpolagaetsya, chto vasha UNIX-mashina imeet sootvetstvuyushchij drajver * dlya chteniya disket, sformatirovannyh na IBM PC. * match.c - fajl, soderzhashchij tekst funkcii match(). */ #include <stdio.h> #include <fcntl.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> extern char *malloc(); /* vydelitel' pamyati */ extern char *strrchr(); /* poisk poslednego vhozhdeniya bukvy */ extern long lseek(); void readBoot(), readFAT(), readRootDir(), main(), line(), getFile(), doDirectory(), mkname(), enterDir(), countFree(), traceclu(); int fd; /* deskriptor fajla - diskovoda */ FILE *mapfp; /* fajl trassirovki */ int trace = 0; /* trassirovka poka vyklyuchena */ int ask = 1; /* sprashivat' li podtverzhdenie na perezapis' fajlov */ int dironly = 0; /* 1: tol'ko pokazyvat' imena, fajly ne skidyvat' */ typedef unsigned char uchar; /*typedef unsigned short ushort; Est' v sys/types.h */ /* Format sektora zagruzki */ struct boot { char jmp[3]; /* komanda jmp */ char label[8]; /* nazvanie sistemy */ char bfs[2]; /* razmer boot-sektora */ uchar sectorsPerCluster; /* chislo sektorov v klastere */ char fatoff[2]; /* smeshchenie do nachala FAT */ uchar copies; /* chislo kopij FAT */ char dirsize[2]; /* chislo zapisej v kornevom kataloge */ char sectors[2]; /* razmer diskety v sektorah */ uchar desc; /* opisatel' tipa diskety */ char FATsize[2]; /* razmer FAT v sektorah */ char sectorsPerTrack[2]; /* chislo sektorov na trek */ char sides[2]; /* chislo storon (1, 2) */ char hidden[2]; /* chislo spryatannyh sektorov */ } *boot; #define SECTOR 512 /* Razmer sektora v bajtah */ int CLU; /* Razmer klastera v bajtah */ int SPC; /* Razmer klastera v sektorah */ int SECT; /* CHislo sektorov na diskete */ long capacity; /* emkost' diskety v bajtah */ ushort MAXCLU; /* maksimal'nyj nomer klastera + 1 */ int NDIR; /* CHislo slotov v kornevom kataloge */ int DIRSIZE; /* Dlina kornevogo kataloga v bajtah */ int ENTRperCLUSTER; /* Kolichestvo slotov v odnom klastere kataloga */ int SPF; /* Razmer FAT v sektorah */ int FATSIZE; /* Razmer FAT v bajtah */ int FATSTART; /* Smeshchenie do FAT v bajtah */ int NFAT; /* Kolichestvo kopij FAT */ uchar DESC; /* Opisatel' tipa diskety */ int DATACLU; /* Nachalo oblasti dannyh (nomer fizich. klastera) */ int bit16 = 0; /* 1 esli FAT ispol'zuet 16-bitnye polya, a ne 12 */ /* Preobrazovanie char[] v integer */ #define INT(s) ( * (short *)s) #define LONG(s) ( * (long *)s) /* Format odnoj zapisi kataloga. */ struct dir{ char name[8]; /* imya fajla */ char ext[3]; /* rasshirenie (suffiks) */ uchar attrib; /* atributy fajla */ char unused[10]; char creat_time[2]; /* vremya sozdaniya */ char creat_date[2]; /* data sozdaniya */ char firstCluster[2]; /* nachal'nyj klaster */ char size[4]; /* razmer v bajtah */ }; #define isdir(attr) (attr & 0x10) /* YAvlyaetsya li katalogom ? */ #define islabel(attr) (attr & 0x08) /* Metka toma ? */ #define eq(s1, s2) (!strcmp(s1, s2)) /* sravnenie strok na == */ struct dir *droot; /* Soderzhimoe kornevogo kataloga */ char *FAT1; /* File Allocation Table, kopiya 1 */ char *FAT2; /* kopiya 2 */ char cwd[256] = ""; /* Tekushchij katalog v DOS. "" - kornevoj */ char *root = "/tmp"; /* Katalog v UNIX, kuda kopiruyutsya fajly */ char *pattern = NULL; /* shablon bazovogo imeni */ char *dirpattern; /* katalog (ne shablon) */ char newname[256]; /* bufer dla generacii imen */ char cluster[4098]; /* bufer dlya chteniya klastera */ /* CHtenie n bajt po adresu s */ Read(fd, s, n) char *s; { int nn = read(fd, s, n); if(nn != n ){ fprintf(stderr, "Oshibka chteniya: %d vmesto %d\n", nn, n); perror( "read" ); exit(1); } return nn; } /* Pozicionirovanie golovok */ long Lseek(fd, off, how) long off; { long offf; if((offf = lseek(fd, off, how)) < 0){ fprintf(stderr, "Oshibka lseek(%ld,%d)\n", off, how); } return offf; } /* Otvedenie pamyati i ee zachistka */ char *Malloc(n) unsigned n;{ char *ptr = malloc(n); register unsigned i; if( !ptr){ fprintf(stderr, "Ne mogu malloc(%u)\n", n ); exit(2); } for(i=0; i < n ; i++ ) ptr[i] = 0; /* Mozhno bylo by ispol'zovat' ptr = calloc(1,n); eta funkciya * kak raz otvodit i ochishchaet pamyat' */ return ptr; } /* Narisovat' gorizontal'nuyu chertu */ void line(c) char c;{ register i; for(i=0; i < 78; i++) putchar(c); putchar('\n'); } /* Obrabotka psevdo-imen ustrojstv. Ispol'zuyutsya imena dlya XENIX */ char *drive(name) char *name; { if( eq(name, "360")) return "/dev/fd048ds9"; if( eq(name, "720")) return "/dev/fd096ds9"; if( eq(name, "1.2")) return "/dev/fd096ds15"; return name; } /* Sozdat' katalog */ char command[512]; /* bufer dla formirovaniya komand */ mkdir(name, mode) char *name; { int retcode; struct stat st; if( stat(name, &st) >= 0 && (st.st_mode & S_IFMT) == S_IFDIR ) return 0; /* uzhe est' */ sprintf(command, "mkdir \"%s\"", name ); retcode = system(command); /* vypolnit' komandu, zapisannuyu v command */ chmod(name, mode & 0777); /* ustanovit' kody dostupa */ return retcode; /* 0 - uspeshno */ } /* Otkryt' fajl, sozdavaya (esli nado) nedostayushie katalogi */ FILE *fmdopen(name, mode) char *name, *mode; { extern errno; char *s; FILE *fp; if( fp = fopen(name, mode)) return fp; /* OK */ /* inache fajl ne smog sozdat'sya */ /* if( errno != ENOENT ) return NULL; /* iz-za nedostatka prav */ /* Probuem sozdat' vse katalogi po puti k fajlu */ if((s = strrchr(name, '/' )) == NULL ) return NULL; *s = '\0'; md(name); *s = '/'; return fopen(name, mode); } /* Rekursivnyj mkdir */ md(path) char *path; {