Хрестоматия по программированию на Си в Unix
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; /* миллисекунд */
А. Богатырев, 1992-95 - 270 - Си в UNIX
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);
}
}
}
}
А. Богатырев, 1992-95 - 271 - Си в UNIX
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;
}
6.12. Простой интерпретатор команд.
Данный раздел просто приводит исходный текст простого интерпретатора команд.
Функция match описана в главе "Текстовая обработка".
А. Богатырев, 1992-95 - 272 - Си в UNIX
/* Примитивный интерпретатор команд. Распознает построчно
* команды вида: CMD ARG1 ... ARGn FILE >>FILE >&FILE >>&FILE
* Сборка: cc -U42 -DCWDONLY sh.c match.c pwd.c -o sh
*/
#include /* определение типов, используемых системой */
#include /* описание библиотеки ввода/вывода */
#include /* описание сигналов */
#include /* определение O_RDONLY */
#include /* коды системных ошибок */
#include /* макросы для работы с символами */
#include /* эмуляция файловой системы BSD 4.2 */
#include /* работа с /etc/passwd */
#include /* описание формата wait() */
char cmd[256]; /* буфер для считывания команды */
#define MAXARGS 256 /* макс. количество аргументов */
char *arg[MAXARGS]; /* аргументы команды */
char *fin, *fout; /* имена для перенаправления ввода/вывода */
int rout; /* флаги перенаправления вывода */
char *firstfound; /* имя найденной, но невыполняемой программы */
#define LIM ':' /* разделитель имен каталогов в path */
extern char *malloc(), *getenv(), *strcpy(), *getwd();
extern char *strchr(), *execat();
extern void callshell(), printenv(), setenv(), dowait(), setcwd();
extern struct passwd *getpwuid();
/* Предопределенные переменные */
extern char **environ; /* окружение: изначально смотрит на тот же
* массив, что и ev из main() */
extern int errno; /* код ошибки системного вызова */
char *strdup(s)char *s;
{ char *p; return(p=malloc(strlen(s)+1), strcpy(p,s)); }
/* strcpy() возвращает свой первый аргумент */
char *str3spl(s, p, q) char *s, *p, *q;
{ char *n = malloc(strlen(s)+strlen(p)+strlen(q)+1);
strcpy(n, s); strcat(n, p); strcat(n, q); return n;
}
int cmps(s1, s2) char **s1, **s2;
{ return strcmp(*s1, *s2); }
А. Богатырев, 1992-95 - 273 - Си в UNIX
/* Перенаправить вывод */
#define APPEND 0x01
#define ERRTOO 0x02
int output (name, append, err_too, created) char *name; int *created;
{
int fd;
*created = 0; /* Создан ли файл ? */
if( append ){ /* >>file */
/* Файл name существует? Пробуем открыть на запись */
if((fd = open (name, O_WRONLY)) < 0) {
if (errno == ENOENT) /* Файл еще не существовал */
goto CREATE;
else
return 0; /* Не имеем права писать в этот файл */
}
/* иначе fd == открытый файл, *created == 0 */
}else{
CREATE: /* Пытаемся создать (либо опустошить) файл "name" */
if((fd = creat (name, 0666)) < 0 )
return 0; /* Не могу создать файл */
else *created = 1; /* Был создан новый файл */
}
if (append)
lseek (fd, 0l, 2); /* на конец файла */
/* перенаправить стандартный вывод */
dup2(fd, 1);
if( err_too ) dup2(fd, 2); /* err_too=1 для >& */
close(fd); return 1;
}
/* Перенаправить ввод */
int input (name) char *name;
{
int fd;
if((fd = open (name, O_RDONLY)) < 0 ) return 0;/* Не могу читать */
/* перенаправить стандартный ввод */
dup2(fd, 0); close(fd); return 1;
}
А. Богатырев, 1992-95 - 274 - Си в UNIX
/* запуск команды */
int cmdExec(progr, av, envp, inp, outp, outflg)
char *progr; /* имя программы */
char **av; /* список аргументов */
char **envp; /* окружение */
char *inp, *outp; /* файлы ввода-вывода (перенаправления) */
int outflg; /* режимы перенаправления вывода */
{
void (*del)(), (*quit)();
int pid;
int cr = 0;
del = signal(SIGINT, SIG_IGN); quit = signal(SIGQUIT, SIG_IGN);
if( ! (pid = fork())){ /* ветвление */
/* порожденный процесс (сын) */
signal(SIGINT, SIG_DFL); /* восстановить реакции */
signal(SIGQUIT,SIG_DFL); /* по умолчанию */
/* getpid() выдает номер (идентификатор) данного процесса */
printf( "Процесс pid=%d запущен\n", pid = getpid());
/* Перенаправить ввод-вывод */
if( inp ) if(!input( inp )){
fprintf(stderr, "Не могу <%s\n", inp ); goto Err;
}
if( outp )
if(!output (outp, outflg & APPEND, outflg & ERRTOO, &cr)){
fprintf(stderr, "Не могу >%s\n", outp ); goto Err;
}
/* Заменить программу: при успехе
* данная программа завершается, а вместо нее вызывается
* функция main(ac, av, envp) программы, хранящейся в файле progr.
* ac вычисляет система.
*/
execvpe(progr, av, envp);
Err:
/* при неудаче печатаем причину и завершаем порожденный процесс */
perror(firstfound ? firstfound: progr);
/* Мы не делаем free(firstfound),firstfound = NULL
* потому что данный процесс завершается (и тем ВСЯ его
* память освобождается) :
*/
if( cr && outp ) /* был создан новый файл */
unlink(outp); /* но теперь он нам не нужен */
exit(errno);
}
/* процесс - отец */
/* Сейчас сигналы игнорируются, wait не может быть оборван
* прерыванием с клавиатуры */
dowait(); /* ожидать окончания сына */
/* восстановить реакции на сигналы от клавиатуры */
signal(SIGINT, del); signal(SIGQUIT, quit);
return pid; /* вернуть идентификатор сына */
}
А. Богатырев, 1992-95 - 275 - Си в UNIX
/* Запуск программы с поиском по переменной среды PATH */
int execvpe(progr, av, envp) char *progr, **av, **envp;
{
char *path, *cp;
int try = 1;