Книга: Разработка приложений в среде Linux. Второе издание

Приложение Б Исходный код ladsh

Приложение Б

Исходный код ladsh
  1: /* ladsh4.c */
  2:
  3: #define _GNU_SOURCE
  4:
  5: #include <ctype.h>
  6: #include <errno.h>
  7: #include <fcntl.h>
  8: #include <glob.h>
  9: #include <signal.h>
 10: #include <stdio.h>
 11: #include <stdlib.h>
 12: #include <string.h>
 13: #include <sys/ioctl.h>
 14: #include <sys/wait.h>
 15: #include <unistd.h>
 16:
 17: #define MAX_COMMAND_LEN 250 /* максимальная длина одной
 18:                                командной строки */
 19: #define JOB_STATUS_FORMAT "[%d] %-22s %.40sn"
 20:
 21: struct jobSet {
 22:  struct job * head; /* заголовок списка выполняющихся заданий */
 23:  struct job * fg; /* текущее высокоприоритетное задание */
 24: };
 25:
 26: enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
 27:                        REDIRECT_APPEND };
 28:
 29: struct redirectionSpecifier {
 30:  enum redirectionType type; /* тип переадресации */
 31:  int fd;                    /* переадресация fd */
 32:  char * filename;           /* файл, в который будет переадресовано fd */
 33: };
 34:
 35: struct childProgram {
 36:  pid_t pid;                                 /* 0 в случае выхода */
 37:  char ** argv;                              /* имя программы и аргументы */
 38:  int numRedirections;                       /* элементы в массиве переадресации */
 39:  struct redirectionSpecifier* redirections; /* переадресации ввода-вывода */
 40:  glob_t globResult;                         /* результат универсализации параметра */
 41:  int freeGlob;                              /* нужно ли освобождать globResult? */
 42:  int isStopped;                             /* выполняется ли в данный момент программа?*/
 43: };
 44:
 45: struct job {
 46:  int jobId;        /* номер задания */
 47:  int numProgs;     /* количество программ в задании */
 48:  int runningProgs; /* количество выполняющихся программ */
 49:  char * text;      /* имя задания */
 50:  char * cmdBuf;    /* буфер, на который ссылаются различные массивы argv */
 51:  pid_t pgrp;       /* идентификатор группы процесса для задания */
 52:  struct childProgram* progs; /* массив программ в задании */
 53:  struct job* next; /* для отслеживания фоновых команд */
 54:  int stoppedProgs; /* количество активных, но приостановленных программ */
 55: };
 56:
 57: void freeJob (struct job * cmd) {
 58:  int i;
 59:
 60:  for (i = 0; i <cmd->numProgs; i++) {
 61:   free(cmd->progs[i].argv);
 62:   if (cmd->progs[i].redirections)
 63:    free(cmd->progs[i].redirections);
 64:   if (cmd->progs[i].freeGlob)
 65:    globfree(&cmd->progs[i].globResult);
 66:  }
 67:  free(cmd->progs);
 68:  if (cmd->text) free(cmd->text);
 69:   free(cmd->cmdBuf);
 70: }
 71:
 72: int getCommand(FILE * source, char * command) {
 73:  if (source == stdin) {
 74:   printf("# ");
 75:   fflush(stdout);
 76:  }
 77:
 78:  if (!fgets(command, MAX_COMMAND_LEN, source)) {
 79:   if (source == stdin) printf("n");
 80:   return 1;
 81:  }
 82:
 83:  /* удаление хвостового символа новой строки */
 84:  command[strlen(command) - 1] = '';
 85:
 86:  return 0;
 87: }
 88:
 89: void globLastArgument(struct childProgram * prog, int * argcPtr,
 90:  int * argcAllocedPtr) {
 91:  int argc = *argcPtr;
 92:  int argcAlloced = *argcAllocedPtr;
 93:  int rc;
 94:  int flags;
 95:  int i;
 96:  char * src, * dst;
 98:  if (argc>1) { /* cmd->globResult уже инициализирован */
 99:   flags = GLOB_APPEND;
100:   i = prog->globResult.gl_pathc;
101:  } else {
102:   prog->freeGlob = 1;
103:   flags = 0;
104:   i = 0;
105:  }
106:
107:  rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
108:  if (rc == GLOB_NOSPACE) {
109:   fprintf(stderr, "недостаточно пространства для универсализацииn");
110:   return;
111:  } else if (rc == GLOB_NOMATCH ||
112:   (!rc && (prog->globResult.gl_pathc - i) == 1 &&
113:   !strcmp(prog->argv[argc - 1],
114:   prog->globResult.gl_pathv[i]))) {
115:   /* нам нужно удалить все, что до сих пор было заключено между */
116:   src = dst = prog->argv[argc - 1];
117:   while (*src) {
118:    if (*src != '') *dst++ = *src;
119:    src++;
120:   }
121:   *dst = '';
122:  } else if (!rc) {
123:   argcAlloced += (prog->globResult.gl_pathc - i);
124:   prog->argv = realloc(prog->argv,
125:   argcAlloced * sizeof(*prog->argv));
126:   memcpy(prog->argv + (argc - 1),
127:   prog->globResult.gl_pathv + i,
128:   sizeof(*(prog->argv)) *
129:    (prog->globResult.gl_pathc - i));
130:   argc += (prog->globResult.gl_pathc - i - 1);
131:  }
132:
133:  *argcAllocedPtr = argcAlloced;
134:  *argcPtr = argc;
135: }
136:
137: /* Возвращаем cmd->numProgs как 0, если не представлено ни одной команды
138:    (например, пустая строка). Если будет обнаружена допустимая команда,
139:    commandPtr будет ссылаться на начало следующей команды (если исходная
140:    команда была связана с несколькими заданиями) или будет равно NULL,
141:    если больше не представлено ни одной команды. */
142: int parseCommand(char ** commandPtr, struct job * job, int * isBg) {
143:  char * command;
144:  char * returnCommand = NULL;
145:  char * src, * buf, * chptr;
146:  int argc = 0;
147:  int done = 0;
148:  int argvAlloced;
149:  int i;
150:  char quote = '';
151:  int count;
152:  struct childProgram * prog;
153:
154:  /* пропускаем первое свободное место (например, пробел) */
155:  while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++;
156:
157:  /* обрабатываем пустые строки и первые символы '#' */
158:  if (!**commandPtr || (**commandPtr=='#')) {
159:   job->numProgs = 0;
160:   *commandPtr = NULL;
161:   return 0;
162:  }
163:
164:  *isBg = 0;
165:  job->numProgs = 1;
166:  job->progs = malloc(sizeof(*job->progs));
167:
168:  /* Мы задаем элементы массива argv для ссылки внутри строки.
169:     Освобождение памяти осуществляется с помощью функции freeJob().
170:
171:     Получив незанятую память, нам не нужно будет использовать завершающие
172:     значения NULL, поэтому оставшаяся часть будет выглядеть аккуратнее
173:     (хотя, честно говоря, менее эффективно). */
174:  job->cmdBuf = command = calloc(1, strlen(*commandPtr) + 1);
175:  job->text = NULL;
176:
177:  prog = job->progs;
178:  prog->numRedirections = 0;
179:  prog->redirections = NULL;
180:  prog->freeGlob = 0;
181:  prog->isStopped = 0;
182:
183:  argvAlloced = 5;
184:  prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
185:  prog->argv[0] = job->cmdBuf;
186:
187:  buf = command;
188:  src = *commandPtr;
189:  while (*src && !done) {
190:   if (quote == *src) {
191:    quote = '';
192:   } else if (quote) {
193:    if (*src ==0 '') {
194:     src++;
195:     if (!*src) {
196:      fprintf(stderr,
197:       "после ожидался символn");
198:      freeJob(job);
199:      return 1;
200:     }
201:
202:     /* в оболочке сочетание "'" должно дать */
203:     if (*src != quote) *buf++ = '';
204:    } else if (*src == '*' | | *src == ' ?' | | *src == '[' ||
205:     *src == ']')
206:     *buf++ = '';
207:    *buf++ = *src;
208:   } else if (isspace(*src)) {
209:    if (*prog->argv[argc]) {
210:     buf++, argc++;
211:     /* +1 здесь оставляет место для NULL, которое
212:        завершает массив argv */
213:     if ((argc + 1) == argvAlloced) {
214:      argvAlloced += 5;
215:      prog->argv = realloc(prog->argv,
216:       sizeof(*prog->argv) * argvAlloced);
217:     }
218:     prog->argv[argc] = buf;
219:
220:     globLastArgument(prog, &argc, &argvAlloced);
221:    }
222:   } else switch (*src) {
223:   case '"':
224:   case ''':
225:    quote = *src;
226:    break;
227:
228:   case '#': /* комментарий */
229:    done = 1;
230:    break;
231:
232:   case '>': /* переадресации */
233:   case '<':
234:    i = prog->numRedirections++;
235:    prog->redirections = realloc(prog->redirections,
236:    sizeof(*prog->redirections) * (i+1));
237:
238:    prog->redirections[i].fd= -1;
239:    if (buf != prog->argv[argc]) {
240:     /* перед этим символом может быть указан номер
241:        переадресовываемого файла */
242:     prog->redirections[i].fd =
243:      strtol(prog->argv[argc], &chptr, 10);
244:
245:     if (*chptr && *prog->argv[argc]) {
246:      buf++, argc++;
247:      globLastArgument(prog, &argc, &argvAlloced);
248:     }
249:    }
250:
251:    if (prog->redirections[i].fd == -1) {
252:     if (*src == '>')
253:      prog->redirections[i].fd = 1;
254:     else
255:      prog->redirections[i].fd = 0;
256:    }
257:
258:    if (*src++ == '>') {
259:     if (*src == '>') {
260:      prog->redirections[i].type = REDIRECT_APPEND;
261:      src++;
262:     } else {
263:      prog->redirections[i].type = REDIRECT_OVERWRIТЕ;
264:     }
265:    } else {
266:     prog->redirections[i].type = REDIRECT_INPUT;
267:    }
268:
269:    /* Это не соответствует стандарту sh POSIX. Ну и ладно. */
270:    chptr = src;
271:    while (isspace(*chptr)) chptr++;
272:
273:    if (!*chptr) {
274:     fprintf(stderr, "после %c ожидалось имя файлаn",
275:      *src);
276:     freeJob(job);
277:     return 1;
278:    }
279:
280:    prog->redirections[i].filename = buf;
281:    while (*chptr && !isspace(*chptr))
282:     *buf++ = *chptr++;
283:
284:    src = chptr - 1; /* src++ будет сделано позже */
285:    prog->argv[argc] = ++buf;
286:    break;
287:
288:   case '|': /* канал */
289:    /* завершение этой команды */
290:    if (*prog->argv[argc]) argc++;
291:    if (large) {
292:     fprintf(stderr, "пустая команда в каналеn");
293:     freeJob(job);
294:     return 1;
295:    }
296:    prog->argv[argc] = NULL;
297:
298:    /* и начало следующей */
299:    job->numProgs++;
300:    job->progs = realloc(job->progs,
301:     sizeof (*job->progs) *
302:      job->numProgs);
303:    prog = job->progs + (job->numProgs - 1);
304:    prog->numRedirections = 0;
305:    prog->redirections = NULL;
306:    prog->freeGlob = 0;
307:    argc = 0;
308:
309:    argvAlloced = 5;
310:    prog->argv = malloc(sizeof(*prog->argv) *
311:     argvAlloced);
312:    prog->argv[0] = ++buf;
313:
314:    src++;
315:    while (*src && isspace(*src)) src++;
316:
317:    if (!*src) {
318:     fprintf(stderr, "пустая команда в каналеn");
319:     return 1;
320:    }
321:    src--; /* инкремент ++ мы сделаем в конце цикла */
322:
323:    break;
324:
325:   case '&': /* фон */
326:    *isBg = 1;
327:   case ';': /* разнообразные команды */
328:    done = 1;
329:    returnCommand = *commandPtr + (src - * commandPtr) + 1;
330:    break;
331:
332:   case '':
333:    src++;
334:    if (!*src) {
335:     freeJob(job);
336:     fprintf(stderr, "после ожидался символn");
337:     return 1;
338:    }
339:    if (*src == '*' | | *src == '[' || *src == '] '
340:     || *src == '?')
341:     *buf++ = '';
342:    /* неудача */
343:   default:
344:    *buf++ = *src;
345:   }
346:
347:   src++;
348:  }
349:
350:  if (*prog->argv[argc]) {
351:   argc++;
352:   globLastArgument(prog, &argc, &argvAlloced);
353:  }
354:  if (!argc) {
355:   freeJob(job);
356:   return 0;
357:  }
358:  prog->argv[argc] = NULL;
359:
360:  if (!returnCommand) {
361:   job->text = malloc(strlen(*commandPtr) + 1);
362:   strcpy(job->text, *commandPtr);
363:  } else {
364:   /*Оставляем любые хвостовые пробелы, хотя и получится это несколько небрежно*/
365:
366:   count = returnCommand - *commandPtr;
367:   job->text = malloc(count + 1);
368:   strncpy(job->text, *commandPtr, count);
369:   job->text[count] = '';
370:  }
371:
372:  *commandPtr = returnCommand;
373:
374:  return 0;
375: }
376:
377: int setupRedirections(struct childProgram * prog) {
378:  int i;
379:  int openfd;
380:  int mode;
381:  struct redirectionSpecifier * redir = prog->redirections;
382:
383:  for (i = 0; i < prog->numRedirections; i++, redir++) {
384:   switch (redir->type) {
385:   case REDIRECT_INPUT:
386:    mode = O_RDONLY;
387:    break;
388:   case REDIRECT_OVERWRITE:
389:    mode = O_RDWR | O_CREAT | O_TRUNC;
390:    break;
391:   case REDIRECT_APPEND:
392:    mode = O_RDWR | O_CREAT | O_APPEND;
393:    break;
394:   }
395:
396:   openfd = open(redir->filename, mode, 0666);
397:   if (openfd < 0) {
398:    /* мы могли потерять это в случае переадресации stderr,
399:       хотя bash и ash тоже потеряют его (а вот
400:       zsh - нет!) */
401:    fprintf(stderr, "ошибка при открытии %s: %sn",
402:    redir->filename, strerror(errno));
403:    return 1;
404:   }
405:
406:   if (openfd != redir->fd) {
407:    dup2(openfd, redir->fd);
408:    close(openfd);
409:   }
410:  }
411:
412:  return 0;
413: }
414:
415: int runCommand(struct job newJob, struct jobSet * jobList,
416:  int inBg) {
417:  struct job * job;
418:  char * newdir, * buf;
419:  int i, len;
420:  int nextin, nextout;
421:  int pipefds[2]; /* pipefd[0] предназначен для чтения */
422:  char * statusString;
423:  int jobNum;
424:  int controlfds[2] ;/*канал для возможности приостановки работы дочернего процесса*/
425:
426:  /* здесь производится обработка встраиваемых модулей — мы не используем fork(),
427:     поэтому, чтобы поместить процесс в фон, придется потрудиться */
428:  if (!strcmp(newJob.progs[0].argv[0], "exit")) {
429:   /* здесь возвращается реальный код выхода */
430:   exit(0);
431:  } else if (!strcmp(newJob.progs[0].argv[0], "pwd")) {
432:   len = 50;
433:   buf = malloc(len);
434:   while (!getcwd(buf, len) && errno == ERANGE) {
435:    len += 50;
436:    buf = realloc(buf, len);
437:   }
438:   printf("%sn", buf);
439:   free(buf);
440:   return 0;
441:  } else if (!strcmp(newJob.progs[0].argv[0], "cd")) {
442:   if (!newJob.progs[0].argv[1] == 1)
443:    newdir == getenv("HOME");
444:   else
445:    newdir = newJob.progs[0].argv[1];
446:   if (chdir(newdir))
447:    printf("сбой при смене текущего каталога: %sn",
448:     strerror(errno));
449:   return 0;
450:  } else if (!strcmp(newJob.progs[0].argv[0], "jobs")) {
451:   for (job = jobList->head; job; job = job->next) {
452:    if (job->runningProgs == job->stoppedProgs)
453:     statusString = "Остановлено";
454:    else
455:     statusString = "Выполняется";
456:
457:    printf(JOB_STATUS_FORMAT, job->jobId, statusString,
458:     job->text);
459:   }
460:   return 0;
461:  } else if (!strcmp(newJob.progs[0].argv[0], "fg") ||
462:   !strcmp(newJob.progs[0].argv[0], "bg")) {
463:   if (!newJob.progs[0].argv[1] || newJob.progs[0].argv[2]) {
464:    fprintf(stderr,
465:     "%s: ожидался в точности один аргументn",
466:     newJob.progs[0].argv[0]);
467:    return 1;
468:   }
469:
470:   if (sscanf(newJob.progs[0].argv[1], "%%%d", &jobNum) != 1) {
471:    fprintf(stderr, "%s: неверный аргумент '%s'n",
472:     newJob.progs[0].argv[0],
473:     newJob.progs[0].argv[1]);
474:    return 1;
475:   }
476:
477:   for (job = jobList->head; job; job = job->next)
478:    if (job->jobId == jobNum) break;
479:
480:   if (!job) {
481:    fprintf(stderr, "%s: неизвестное задание %dn",
482:     newJob.progs[0].argv[0], jobNum);
483:    return 1;
484:   }
485:
486:   if (*new Job. progs[0].argv[0] == 'f') {
487:    /* Переводим задание на передний план */
488:
489:    if (tcsetpgrp(0, job->pgrp))
490:     perror("tcsetpgrp");
491:    jobList->fg = job;
492:   }
493:
494:   /* Повторяем запуск процессов в задании */
495:   for (i = 0; i<job->numProgs; i++)
496:    job->progs[i].isStopped = 0;
497:
498:   kill(-job->pgrp, SIGCONT);
499:
500:   job->stoppedProgs = 0;
501:
502:   return 0;
503:  }
504:
505:  nextin = 0, nextout = 1;
506:  for (i = 0; i < newJob.numProgs; i++) {
507:   if ((i + 1) < newJob.numProgs) {
508:    pipe(pipefds);
509:    nextout = pipefds[1];
510:   } else {
511:    nextout = 1;
512:   }
513:
514:   pipe(controlfds);
515:
516:   if (!(newJob.progs[i].pid = fork())) {
517:    signal(SIGTTOU, SIG_DFL);
518:
519:    close(controlfds[1]);
520:    /* при чтении будет возвращен 0, когда записывающая сторона закрыта */
521:    read(controlfds[0], &len, 1);
522:    close(controlfds[0]);
523:
524:    if (nextin != 0) {
525:     dup2(nextin, 0);
526:     close(nextin);
527:    }
528:
529:    if (nextout != 1) {
530:     dup2(nextout, 1);
531:     close(nextout);
532:    }
533:
534:    /* явные переадресации подменяют каналы */
535:    setupRedirections(newJob.progs + i);
536:
537:    execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
538:    fprintf(stderr, "сбой exec() для %s: %sn",
539:    newJob.progs[i].argv[0],
540:    strerror(errno));
541:    exit(1);
542:   }
543:
544:   /* помещаем дочерний процесс в группу процессов, лидером в которой
545:      является первый процесс в этом канале */
546:   setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
547:
548:   /* закрываем канал управления, чтобы продолжить работу дочернего процесса */
549:   close(controlfds[0]);
550:   close(controlfds[1]);
551:
552:   if (nextin !=0) close(nextin);
553:   if (nextout !=1) close(nextout);
554:
555:   /* Если другого процесса нет, то nextin является "мусором",
556:      хотя это и не является помехой */
557:   nextin = pipefds[0];
558:  }
559:
560:  newJob.pgrp = newJob.progs[0].pid;
561:
562:  /* поиск идентификатора используемого задания */
563:  newJob.jobld = 1;
564:  for (job = jobList->head; job; job = job->next)
565:   if (job->jobId> = newJob.jobId)
566:    newJob.jobId = job->jobId + 1;
567:
568:  /* добавляем задание в список выполняющихся заданий */
569:  if (!jobList->head) {
570:   job = jobList->head = malloc(sizeof(*job));
571:  } else {
572:   for (job = jobList->head; job->next; job = job->next);
573:   job->next = malloc(sizeof(*job));
574:   job = job->next;
575:  }
576:
577:  *job = newJob;
578:  job->next = NULL;
579:  job->runningProgs = job->numProgs;
580:  job->stoppedProgs = 0;
581:
582:  if (inBg) {
583:   /* мы не ожидаем возврата фоновых заданий - добавляем их
584:      в список фоновых заданий и оставляем их */
585:
586:   printf("[%d] %dn", job->jobId,
587:    newJob.progs[newJob.numProgs - 1].pid);
588:  } else {
589:   jobList->fg = job;
590:
591:   /* перемещаем новую группу процессов на передний план */
592:
593:   if (tcsetpgrp(0, newJob.pgrp))
594:    perror("tcsetpgrp");
595:  }
596:
597:  return 0;
598: }
599:
600: void removeJob(struct jobSet * jobList, struct job * job) {
601:  struct job * prevJob;
602:
603:  freeJob(job);
604:  if (job == jobList->head) {
605:   jobList->head = job->next;
606:  } else {
607:   prevJob = jobList->head;
608:   while (prevJob->next != job) prevJob = prevJob->next;
609:   prevJob->next = job->next;
610:  }
611:
612:  free(job);
613: }
614:
615: /* Проверяем, завершился ли какой-либо фоновый процесс - если да, то
616:    устанавливаем причину и проверяем, окончилось ли выполнение задания */
617: void checkJobs(struct jobSet * jobList) {
618:  struct job * job;
619:  pid_t childpid;
620:  int status;
621:  int progNum;
622:  char * msg;
623:
624:  while ((childpid = waitpid(-1, &status,
625:   WNOHANG | WUNTRACED)) > 0) {
626:   for (job = jobList->head; job; job = job->next) {
627:    progNum = 0;
628:    while(progNum < job->numProgs &&
629:     job->progs[progNum].pid != childpid)
630:     progNum++;
631:    if (progNum < job->numProgs) break;
632:   }
633:
634:   if (WIFEXITED(status) || WIFSIGNALED(status)) {
635:    /* дочерний процесс завершил работу */
636:    job->runningProgs--;
637:    job->progs[progNum].pid = 0;
638:
639:    if (!WIFSIGNALED(status))
640:     msg = "Завершено";
641:    else
642:     msg = strsignal(WTERMSIG(status));
643:
644:    if (!job->runningProgs) {
645:     printf(JOB_STATUS_FORMAT, job->jobId,
646:      msg, job->text);
647:     removeJob(jobList, job);
648:    }
649:   } else {
650:    /* выполнение дочернего процесса остановлено */
651:    job->stoppedProgs++;
652:    job->progs[progNum].isStopped = 1;
653:
654:    if (job->stoppedProgs == job->numProgs) {
655:     printf(JOB_STATUS_FORMAT, job->jobId, "Остановлено",
656:      job->text);
657:    }
658:   }
659:  }
660:
661:  if (childpid == -1 && errno != ECHILD)
662:   perror("waitpid");
663: }
664:
665: int main(int argc, const char ** argv) {
666:  char command[MAX_COMMAND_LEN + 1];
667:  char * nextCommand = NULL;
668:  struct jobSet jobList = { NULL, NULL };
669:  struct job newJob;
670:  FILE * input = stdin;
671:  int i;
672:  int status;
673:  int inBg;
674:
675:  if (argc > 2) {
676:   fprintf(stderr, "неожиданный аргумент; использование: ladsh1 "
677:    "<команды>n");
678:   exit(1);
679:  } else if (argc == 2) {
680:   input = fopen(argv[1], "r");
681:   if (!input) {
682:    perror("fopen");
683:    exit(1);
684:   }
685:  }
686:
687:  /* не обращаем внимания на этот сигнал; это просто помеха,
688:     не имеющая никакого значения для оболочки */
689:  signal(SIGTTOU, SIG_IGN);
690:
691:  while (1) {
692:   if (!jobList.fg) {
693:    /* на переднем плане нет ни одного задания */
694:
695:    /* проверяем, не завершилось выполнение какого-либо фонового задания */
696:    checkJobs(&jobList);
697:
698:    if (!nextCommand) {
699:     if (getCommand(input, command)) break;
700:     nextCommand = command;
701:    }
702:
703:    if (!parseCommand(&nextCommand, &newJob, &inBg) &&
704:     newJob.numProgs) {
705:     runCommand(newJob, &jobList, inBg);
706:    }
707:   } else {
708:    /* задание выполняется на переднем плане; ожидаем, пока оно завершится */
709:    i = 0;
710:    while (!jobList:fg->progs[i].pid ||
711:     jobList.fg->progs[i].isStopped) i++;
712:
713:    waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
714:
715:    if (WIFSIGNALED(status) &&
716:     (WTERMSIG(status) != SIGINT)) {
717:     printf("%sn", strsignal(status));
718:    }
719:
720:    if (WIFEXITED(status) || WIFSIGNALED(status)) {
721:     /* дочерний процесс завершил работу */
722:     jobList.fg->runningProgs--;
723:     jobList.fg->progs[i].pid = 0;
724:
725:     if (!jobList.fg->runningProgs) {
726:      /* дочерний процесс завершил работу */
727:
728:      removeJob(&jobList, jobList.fg);
729:      jobList.fg = NULL;
730:
731:      /* переводим оболочку на передний план */
732:      if (tcsetpgrp(0, getpid()))
733:       perror("tcsetpgrp");
734:     }
735:    } else {
736:     /* выполнение дочернего процесса было остановлено */
737:     jobList.fg->stoppedProgs++;
738:     jobList.fg->progs[i].isStopped = 1;
739:
740:     if (jobList.fg->stoppedProgs ==
741:      jobList.fg->runningProgs) {
742:      printf("n" JOB_STATUS_FORMAT,
743:       jobList.fg->jobId,
744:        "Остановлено", jobList.fg->text);
745:        jobList.fg = NULL;
746:     }
747:    }
748:
749:    if (!jobList.fg) {
750:     /* переводим оболочку на передний план */
751:     if (tcsetpgrp(0, getpid()))
752:      perror("tcsetpgrp");
753:    }
754:   }
755:  }
756:
757:  return 0;
758: }

Оглавление книги


Генерация: 1.159. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз