Троан Эрик В.
Шрифт:
331: if (!input) {
332: perror("fopen");
333: exit(1);
334: }
335: }
336:
337: /* не обращать внимания на этот сигнал; он только вводит
338: в заблуждение и не имеет особого значения для оболочки */
339: signal(SIGTTOU, SIG_IGN);
340:
341: while(1) {
342: if (!jobList.fg) {
343: /* нет заданий переднего плана */
344:
345: /* проверить, завершились ли какие-то фоновые процессы */
346: checkJobs(&jobList);
347:
348: if (!nextCommand) {
349: if (getCommand(input, command)) break;
350: nextCommand=command;
351: }
352:
353: if (!parseCommand(&nextCommand, &newJob, &inBg) &&
354: newJob.numProgs) {
355: runCommand(newJob,&jobList,inBg);
356: }
357: } else {
358: /* задание выполняется на переднем плане; ждать завершения */
359: i = 0;
360: while (!jobList.fg->progs[i].pid) i++;
361:
362: waitpid(jobList.fg->progs[i].pid,&status,0);
363:
364: jobList.fg->runningProgs--;
365: jobList.fg->progs[i].pid=0;
366:
367: if (!jobList.fg->runningProgs) {
368: /* дочернее завершилось */
369:
370: removeJob(&jobList, jobList.fg);
371: jobList.fg = NULL;
372:
373: /* переместить оболочку на передний план */
374: if (tcsetpgrp(0, getpid))
375: perror("tcsetpgrp");
376: }
377: }
378: }
379:
380: return 0;
381: }
Эта версия не делает ничего, кроме запуска внешней программы с аргументами, поддержки комментариев стиля
#
(все, что следует за символом #
, игнорируется), и позволяет программам выполняться в фоновом режиме. Она работает как интерпретатор простых сценариев оболочки, написанных в нотации #!
, но ничего сверх этого не делает. Она разработана в качестве имитации обычного интерпретатора оболочки, используемого в системах Linux, несмотря на то, что в значительной степени упрощена. Прежде всего, взглянем на структуры данных, которые здесь используются. На рис. 10.2 показаны структуры данных, используемые в
ladsh1.с
для отслеживания запускаемых дочерних процессов, на примере применения программы grep
в фоновом режиме и links
— в режиме переднего плана, struct jobSet
описывает набор функционирующих заданий. Он содержит связный список заданий и указатель на текущее задание, выполняемое на переднем плане. Если такового нет, то указатель равен NULL
, ladsh1.с
использует struct jobSet
для того, чтобы отслеживать задания, выполняемые в данный момент в фоновом режиме. Рис. 10.2. Структуры данных, описывающие задания для
ladsh1.с
struct childProgram
описывает отдельную выполняемую программу. Это не совсем то же самое, что задание — в конце концов, каждое задание может состоять из нескольких программ, связанных по программным каналам. Для каждой дочерней программы ladsh
отслеживает pid
, имя программы и аргументы командной строки. Первый элемент argv
, argv[0]
, содержит имя запущенной программы, которое передается также потомку в виде первого аргумента. Множество программ объединяется в одно задание с помощью
struct job
. Каждое задание имеет уникальный идентификатор в оболочке, соответствующее количество программ, составляющих задание (хранимых в progs
, указателе на массив struct childProgram
), а также указатель на другое (следующее) задание, что позволяет объединять их вместе в связный список (который описывает struct jobSet
). Задание также отслеживает, сколько отдельных программ составляет его, и сколько их них все еще выполняются (поскольку не все компоненты задания могут завершаться одновременно). Остальные два члена — text
и cmdBuf
— служат в качестве буферов для хранения различных строк, которые используются структурами struct childProgram
, содержащимися в задании.