11.7.2. Изменения в коде

We use cookies. Read the Privacy and Cookie Policy

11.7.2. Изменения в коде

Как только в parseCommand() будут правильно отражены структуры данных, то запуск команд в правильном порядке становится довольно простым при достаточном внимании к деталям. Прежде всего, мы добавляем цикл в parseCommand() для запуска дочерних процессов, поскольку теперь их может быть множество. Прежде чем войти в цикл, мы устанавливаем nextin и nextout, которые являются файловыми дескрипторами, используемыми в качестве стандартных потоков ввод и вывода для следующего запускаемого процесса. Для начала мы используем те же stdin и stdout, что и оболочка.

Теперь посмотрим, что происходит внутри цикла. Основная идея описана ниже.

1. Если это финальный процесс в задании, убедиться, что nextout указывает на stdout. В противном случае нужно подключить вывод этого задания к входному концу неименованного канала.

2. Породить новый процесс. Внутри дочернего перенаправить stdin и stdout, как указано с помощью nextin, nextout и всех специфицированных ранее перенаправлений.

3. Вернувшись обратно в родительский процесс, закрыть nextin и nextout, используемые только что запущенным дочерним процессом (если только они не являются потоками ввода и вывода самой оболочки).

4. Теперь настроить следующий процесс в задании для приема его ввода из вывода процесса, который мы только что создали (через nextin).

Вот как эти идеи перевести на С.

365: nextin=0, nextout=1;

366: for (i=0; i<newJob.numProgs; i++) {

367:  if ((i+1) < newJob.numProgs) {

368:   pipe(pipefds);

369:   nextout = pipefds[1];

370:   } else {

371:    nextout = 1;

372:   }

373:

374:   if (!(newJob.progs[i].pid = fork())) {

375:    if (nextin != 0) {

376:     dup2(nextin, 0);

377:     close(nextin);

378:    }

379:

380:    if (nextout != 1) {

381:     dup2(nextout, 1);

382:     close(nextout);

383:    }

384:

385:    /* явное перенаправление перекрывает каналы */

386:    setupRedirections(newJob.progs+i);

387:

388:    execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);

389:    fprintf(stderr, "exec() of %s failed: %s ",

390:     newJob.progs[i].argv[0],

391:    strerror(errno));

392:    exit(1);

393:   }

394:

395:   /* поместить наш дочерний процесс в группу процессов,

396:      чей лидер - первый процесс канала */

397:   setpgid(newJob.progs[i].pid, newJob.progs[0].pid);

398:

399:   if (nextin != 0) close(nextin);

400:   if (nextout != 1) close (nextout);

401:

402:   /* Если больше нет процессов, то nextin - мусор,

403:      но это не имеет значения */

404:   nextin = pipefds[0];

Единственный код, добавленный в ladsh2.с для обеспечения перенаправлений — это функция setupRedirections(), код которой останется неизменным во всех последующих версиях ladsh. Ее задача состоит в обработке спецификаторов struct redirectionSpecifier для дочерних заданий и соответствующей модификации дочерних файловых дескрипторов. Мы рекомендуем просмотреть код этой функции в приложении Б.