Книга: UNIX — универсальная среда программирования

6.7 Пример: zap

6.7 Пример: zap

Программа zap, которая избирательно уничтожает процессы, отличается от той, что была представлена в виде файла shell в гл. 5. Главная проблема данной версии скорость. Она создает много процессов и поэтому работает медленно, что недопустимо для программы, уничтожающей процессы с ошибками. Если переписать zap на Си, ее быстродействие повысится. Мы, однако, снова воспользуемся ps, чтобы найти информацию о процессе. Это намного легче, чем выуживать информацию из ядра, и, кроме того, мы имеем переносимый вариант. Программа zap открывает программный канал, входной поток для которого берется из ps, и читает из него, как из файла. Функция popen(3) аналогична fopen, за исключением того, что первый аргумент является командой, а не именем файла. То же самое справедливо и для pclose, но здесь она нам не нужна.

/* zap: interactive process killer */
#include <stdio.h>
#include <signal.h>
char *progname; /* program name for error message */
char *ps = "ps -ag"; /* system dependent */
main(argc, argv)
 int argc;
 char *argv[];
{
 FILE *fin, *popen();
 char buf[BUFSIZ];
 int pid;
 progname = argv[0];
 if ((fin = popen(ps, "r")) == NULL) {
  fprintf(stderr, "%s: can't run %sn", progname, ps);
  exit(1);
 }
 fgets(buf, sizeof buf, fin); /* get header line */
 fprintf(stderr, "%s", buf);
 while (fgets(buf, sizeof buf, fin) != NULL)
  if (argc == 1 || strindex(buf, argv[1]) >= 0) {
   buf[strlen(buf)-1] = ''; /* suppress n */
   fprintf(stderr, "%s? ", buf);
   if (ttyin() == 'y') {
    sscanf(buf, "%d", &pid);
    kill(pid, SIGKILL);
   }
  }
 exit(0);
}

Мы писали программу, чтобы использовать ps -ag (этот флаг системно зависим), но если вы не являетесь привилегированным пользователем, то можете уничтожать лишь свои собственные процессы.

Первый вызов fgets выбирает заголовок из ps; интересно выяснить, что случится, если попытаться уничтожить "процесс", соответствующий данному заголовку.

Функция sscanf представляет собой член семейства scanf(3) для форматного преобразования входной строки. Она преобразует строку, а не файл. Вызов kill из системы посылает специальный сигнал процессу; сигнал SIGKILL, определенный в <signal.h>, не может быть перехвачен или проигнорирован. Вы можете вспомнить пятую главу, где его численное значение равно девяти, но лучше использовать символические константы из файлов макроопределений, чем включать в свои программы загадочные числа.

Если аргументы отсутствуют, zap предоставляет каждую строку выходного потока ps как возможность для выбора. При наличии аргумента zap предлагает только те выходные строки ps, которые ему соответствуют. Функция strindex(s1, s2) проверяет, соответствует ли аргумент какой-либо части строки выходного потока ps, используя strncmp (см. табл. 6.2). Функция strindex возвращает позицию s2 в s1 или -1, если ее там нет.

strindex(s, t) /* return index of t in s, -1 if none */
 char *s, *t;
{
 int i, n;
 n = strlen(t);
 for (i = 0; s[i] != ''; i++)
  if (strncmp(s+i, t, n) == 0)
   return i;
 return -1;
}

В табл. 6.4 представлены широко используемые функции из стандартной библиотеки ввода вывода.

fp=fopen(s, mode) Открыть файл s; значения mode "r", "w", "a" соответствуют чтению, записи и добавлению (при ошибке возвращается NULL)
c=gets(fp) Читать символ: getchar() это getc(stdin)
putc(c, fp) Записать символ: putchar(c) это putc(c, stdout)
ungetc(c, fp) Вернуть символ во входной файл fp; можно вернуть не более одного символа за раз
scanf(fmt, a1, ...) Читать символы из stdin в a1, ... в соответствии с fmt. Каждый ai должен быть указателем
fscanf(fp,...) Читать из файла fp
sscanf(s,...) Читать из строки s
printf(fmt, a1, ...) Форматировать a1, ... в соответствии с fmt; печатать в stdout
fprintf(fp, ...) Печатать ... в файл fp
sprintf(s, ...) Печатать ... в строку s
fqets(s, n, fp) Читать не более n символов в s из fp (возвращается NULL по концу файла)
fputs(s, fp) Печатать строку s в файл fp
fflush(fp) Занести буферизованные данные выходного потока в файл fp
fclose(fp) Закрыть файл fp
fp=popen(s, mode) Открыть программный канал для команды s (см. fopen)
pclose(fp) Закрыть программный канал fp
system(s) Запустить команду s и ждать ее окончания

Таблица 6.4: Полезные стандартные функции ввода-вывода

Упражнение 6.11

Модифицируйте zap так, чтобы можно было применять любое число аргументов. В настоящем виде zap высвечивает на экране строку, соответствующую выбранному варианту. Будет она делать это? Если нет, модифицируйте программу соответствующим образом. Подсказка: getpid(2).

Упражнение 6.12

Постройте fgrep(1) на основе strindex. Сравните время работы при сложных поисках, например 10 слов на документ. Почему fgrep выполняется быстрее?

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


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