Новые книги

As distributed computer systems become more pervasive, so does the need for understanding how their operating systems are designed and implemented. Andrew S. Tanenbaum's Distributed Operating Systems fulfills this need. Representing a revised and greatly expanded Part II of the best-selling Modern Operating Systems, it covers the material from the original book, including communication, synchronization, processes, and file systems, and adds new material on distributed shared memory, real-time distributed systems, fault-tolerant distributed systems, and ATM networks. It also contains four detailed case studies: Amoeba, Mach, Chorus, and OSF/DCE. Tanenbaum's trademark writing provides readers with a thorough, concise treatment of distributed systems.
Без цифрового фотоаппарата довольно трудно представить современную жизнь. Практически в каждой семье уже есть это «чудо техники». В данной книге собрано множество по-настоящему полезных практических примеров использования цифровой фототехники, каждый из которых основан на оригинальной идее или задаче.

Системные вызовы и взаимодействие с UNIX.

6.11.2. В качестве самостоятельной работы предлагаем вам пример программы, ведущей протокол сеанса работы. Информацию о псевдотерминалах изучите самостоятельно.

    /*
     *              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
    #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);
            }
    }
    /* Описатель трассируемого процесса */
    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
            /* 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;
            }
    # 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;
    }
    /* Ведение статистики по вызовам 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);
    }
    /* Запуск трассируемого процесса на псевдотерминале */
    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);
            } 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 set, rset;       /* маски */
            struct timeval timeout, rtimeout;
            FD_ZERO(&set); nopen = 0;        /* очистка маски */
            FD_SET (PP.pfd, &set); nopen++;  /* учесть в маске */
            FD_SET (STDIN,  &set); nopen++;
            maxfd = max(PP.pfd, STDIN);
            timeout.tv_sec = 3600;      /* секунд */
            timeout.tv_usec = 0;        /* миллисекунд */
            nfds =  maxfd + 1;
            while( nopen ){
               rset = set;
               rtimeout = timeout;
               /* опросить дескрипторы */
               if((nready = select( nfds, &rset, NULL, NULL, &rtimeout )) <= 0)
                    continue;
               for(f=0; f < nfds; f++ )
                    if( FD_ISSET(f, &rset)){  /* дескриптор f готов */
                            int n;
                            if((n = read(f, buf, sizeof buf)) <= 0 ){
                                FD_CLR(f, &set); nopen--; /* исключить */
                                close(f);
                            } else {
                                int fdout;
                                /* учет и контроль */
                                if( f == PP.pfd ){
                                    fdout = STDOUT;
                                    PP.out_bytes += n;
                                    if( fpscript )
                                        fwrite(buf, 1, n, fpscript);
                                } else if( f == STDIN  ) {
                                    fdout = PP.pfd;
                                    PP.in_bytes += n;
                                    if( halfflag && fpscript )
                                        fwrite(buf, 1, n, fpscript);
                                    if( autoecho )
                                        write(STDOUT, buf, n);
                                }
                                write(fdout, buf, n);
                            }
                    }
            }
    }
    int main(ac, av) char **av;
    {
            while( ac > 1 && *av[1] == '-' ){
                    switch(av[1][1]){
                    case 's':
                            scriptflg++;
                            break;
                    case 'f':
                            av++; ac--;
                            protocol = av[1];
                            scriptflg++;
                            break;
                    case 'h':
                            halfflag++;
                            break;
                    case 'a':
                            autoecho++;
                            break;
                    default:
                            fprintf(stderr, "Bad key %s\n", av[1]);
                            break;
                    }
                    ac--; av++;
            }
            if( scriptflg ){
                    fpscript = fopen( protocol, "w" );
            }
            ac--; av++;
            wm_init();
            PP = wm_ptypair();
            if( PP.pfd < 0 ){
                    fprintf(stderr, "Cannot get pty. Please wait and try again.\n");
                    return 1;
            }
            wm_fixtty();
            wm_startshell(ac, av);
            go++;
            wm_select();
            wm_done(0);
            /* NOTREACHED */
            return 0;
    }

© Copyright А. Богатырев, 1992-95
Си в UNIX

Назад | Содержание | Вперед