[<<Previous Entry]
[^^Up^^]
[Next Entry>>]
[Menu]
[About The Guide]
Упражнения
Вводное упражнение
Напишите программу, которая входит в бесконечный цикл и издает
звуковой сигнал на вашем терминале каждый раз, когда вы нажимаете
<DELETE>. При получении SIGQUIT, она должна вывести сообщение,
говорящее, сколько раз прозвучал сигнал, и завершиться. { signal(2) }
Мультиплексирование ввода
Напишите программу, которая читает из нескольких файлов по очереди,
т.е. после чтения строки из одного файла, читается строка из
следующего и т.д. Если в течение TIME_OUT секунд ничего не было
прочитано, берется следующий файл.
Программа получает в качестве аргументов имена одного или нескольких
файлов, из которых она будет читать. Обычно это терминальные файлы
(т.е. /dev/ttynn), но могут быть файлы и других типов. (read(2) с
нетерминального устройства может прочитать несколько строк, в
зависимости от количества требуемых байтов и длины этих строк.) Если в
одном из файлов достигнут конец файла, из него больше не читают. Когда
конец файла достигнут во всех файлах, программа завершается. Проверьте
вашу программу так:
$ multiplex /dev/tty 'tty'
{ alarm(2), signal(2), read(2) }
Командный интерпретатор shell - продолжение
Защита от сигналов, посылаемых с терминала
Если вы проходили курс UU1001, модифицируйте ваш shell, над которым вы
работали в качестве упражнения, так чтобы он не завершался, когда вы
генерируете сигнал SIGINT. Вместо этого должен завершаться процесс
первого плана, а ваш shell должен немедленно выдавать приглашение.
Кроме того, предохраните команды, исполняемые в фоновом режиме, от
прерывания сигналами SIGINT и SIGQUIT. (Если вы не имеете собственной
версии этой программы, в вашей директории находятся файлы shell.c,
parseline.c, promptline.c и shell.h. Откомпилировав их, вы получите
простой командный интерпретатор, способный выполнять программы в виде
порожденных процессов, запускать фоновые процессы и перенаправлять
ввод/вывод.) { signal(2) или sigset(2) или sigaction(2), longjmp(3) }
Простое управление заданиями
Если вы реализовали защиту от сигналов, модифицируйте ваш
интерпретатор shell, так чтобы обеспечить следующие возможности для
управления заданиями: SIGTSTP, посланный с клавиатуры (<CTRL Z> по
умолчанию), должен заставить основную программу перейти в фоновый
режим и возобновить исполнение. PID переведенного на фон процесса
будет выведен на stderr, и командный интерпретатор выдаст приглашение
для следующей команды. (Совет: сделайте каждый порожденный процесс
лидером группы процессов и явным образом переводите его на первый
план. Когда порожденный процесс первого плана завершается или
останавливается, переводите на первый план интерпретатор).
{ sigset(2), sigsend(2), setpgid(2), tcsetpgrp(2), waitid(2) }
shell.c:
1 /* PRIMITIVE JOB CONTROL SHELL */
2 #include <sys/types.h>
3 #include <stdio.h>
4 #include <signal.h>
5 #include <fcntl.h>
6 #include <setjmp.h>
7 #include "shell.h"
8 #include <sys/procset.h>
9
10 char *infile, *outfile, *appfile;
11 struct command cmds[MAXCMDS];
12 char bkgrnd;
13 /* ADD - SIGNAL HANDLING DECLARATION*/
14 pid_t cpid;
15
16 main(int argc, char **argv)
17 {
18 register int i;
19 char line[1024]; /* allow large command lines */
20 int ncmds;
21 char prompt[50]; /* shell prompt */
22 int ifd, ofd; /* for i/o file redirection */
23 /*ADD - SIGNAL HANDLING & JOB CONTROL DECLARATIONS */
24
25 /*ADD - SIGNAL HANDLING*/
26 /*ADD - JOB CONTROL*/
27
28 sprintf(prompt,"[%s] ", argv[0]);
29
30 /*ADD - SIGNAL HANDLING*/
31
32 while (promptline(prompt, line, sizeof(line)) > 0) {/* until
eof */
33 if ((ncmds = parseline(line)) <= 0)
34 continue; /* read next line */
35 #ifdef DEBUG
36 {
37 int i, j;
38 for (i = 0; i < ncmds; i++) {
39 for (j = 0; cmds[i].cmdargs[j] != (char *) NULL; j++)
40 fprintf(stderr, "cmd[%d].cmdargs[%d] = %s\n",
41 i, j, cmds[i].cmdargs[j]);
42 fprintf(stderr, "cmds[%d].cmdflag = %o\n", i,
cmds[i].cmdflag);
43 }
44 }
45 #endif
46
47 for (i = 0; i < ncmds; i++) {
48 if (!(cpid = fork())) {
49
50 /* ADD - JOB CONTROL*/
51
52 /* ADD - SIGNAL HANDLING */
53
54 /* ADD - JOB CONTROL*/
55
56 /* input redirection */
57 if ((infile != (char *) NULL) && i == 0) {
58 /* check for i == 0 because only */
59 /* first command can have input */
60 /* redirected */
61 if ((ifd = open(infile, O_RDONLY)) < 0) {
62 fprintf(stderr,
63 "%s: %s: cannot open\n",
64 argv[0], infile);
65 exit(2);
66 }
67 close(0); /* close standard input */
68 dup(ifd); /* ifd is now stdin */
69 close(ifd);
70 }
71
72 /* output redirection */
73 if ((outfile != (char*)NULL) && i == ncmds-1){
74 /* create new file */
75 if ((ofd = open(outfile,
76 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
77 fprintf(stderr,
78 "%s: %s: cannot create\n",
79 argv[0], outfile);
80 exit(2);
81 }
82 close(1);
83 dup(ofd);
84 close(ofd);
85 } else if ((appfile != (char *) NULL) &&
86 i == ncmds-1) {
87 if ((ofd = open(appfile,
88 O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) {
89 fprintf(stderr,
90 "%s: %s: cannot open\n",
91 argv[0], appfile);
92 exit(2);
93 }
94 close(1);
95 dup(ofd);
96 close(ofd);
97 }
98
99 execvp(cmds[i].cmdargs[0], cmds[i].cmdargs);
100 fprintf(stderr, "%s: not found\n",
101 cmds[i].cmdargs[0]);
102 exit(1); /* make sure child exits */
103 } /* close child block */
104 if (!bkgrnd) {
105
106 while (cpid != wait((int *)0))/*CHANGE for J.C
107 ; /* wait for child */
108
109 /* ADD JOB CONTROL */
110 }
111 else
112 fprintf(stderr, "%d\n", cpid);
113 }
114
115 } /* close while */
116 }
117
118 /* ADD - SIGNAL HANDLING & JOB CONTROL */