Текст книги "Операционная система UNIX"
Автор книги: Андрей Робачевский
Жанр:
ОС и Сети
сообщить о нарушении
Текущая страница: 8 (всего у книги 39 страниц)
nice -[[-]n] command | Утилита nice(1) применяется для запуска программы на выполнение с относительным приоритетом (nice number), отличным от принятого по умолчанию. Например, ввод команды: $ nice -10 big program приведет к запуску big program с большим значением nice. В UNIX чем больше значение nice number, тем меньший приоритет имеет процесс. Таким образом, при планировании выполнения процессов вероятность того, что ядро операционной системы выберет именно big_program для запуска, уменьшится. Как следствие, big_program станет выполняться дольше, но будет менее интенсивно потреблять процессорные ресурсы. Только администратор системы может повысить приоритет процесса (уменьшить значение nice number): $ nice – -10 job1 | |
renice new_nice pid | Утилита renice(1) позволяет изменять приоритет процесса во время его выполнения. Например, команда $ renice 5 1836 устанавливает значение nice number процесса с идентификатором 1836 равным 5. Как и в случае команды nice(1), увеличить приоритет процесса может только администратор системы. | |
ps | Утилита ps(1) выводит информацию о существующих процессах. При использовании различных опций она позволяет получить следующую информацию: | |
F | статус процесса (системный процесс, блокировки в памяти и т.д.) | |
S | состояние процесса (О – выполняется процессором, S – находится в состоянии сна, R – готов к выполнению, I – создается, Z – зомби) | |
UID | идентификатор (имя) пользователя – владельца процесса | |
PID | идентификатор процесса | |
PPID | идентификатор родительского процесса | |
PRI | текущий динамический приоритет процесса | |
NI | значение nice number процесса | |
TTY | управляющий терминал процесса ('?' – означает отсутствие управляющего терминала) | |
TIME | суммарное время выполнения процесса процессором | |
STIME | время создания процесса (может отличаться от времени запуска команды) | |
COMMAND | имя команды, соответствующей процессу | |
kill [signo] pid1, pid2... | Посылает процессам с идентификаторами pid1, pid2 и т.д. сигнал signo . Сигнал signo может быть указан как в числовой, так и в символьной форме. Команда kill -l выводит таблицу соответствия между символьными именами сигналов и их числовыми значениями: $ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGIOT 7) SIGEMT 8) SIGFPE 9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGUSR1 ... Таким образом, следующие две команды эквивалентны: $ kill -9 18793 $ kill -SIGKILL 18793 | |
at [opt] время_запуска | Утилита at(1) считывает команды стандартного потока ввода и группирует их в задание at, которое будет выполнено в указанное пользователем время. Для выполнения задания будет запущен командный интерпретатор, в среде которого и будут исполнены команды. Например, следующая команда, позволит вам поздравить друга с днем рождения в назначенное время: $ at May 30 < Вы можете добавить опцию -m, и после выполнения задания вам будет отправлено уведомление по электронной почте. |
Об администрировании UNIX
Достаточно открыть оглавление любого «Руководства системного администратора» для UNIX, чтобы оценить то многообразие задач и проблем, с которыми приходится сталкиваться при обслуживании системы:
□ Настройка жизненно важных для пользователей подсистем, таких как файловая система, система печати и сетевая поддержка. Каждая из них, в свою очередь, может быть разделена на десятки подзадач.
□ Регистрация пользователей. Каждый новый пользователь добавляет "забот" администратору системы, но какой же UNIX без пользователей!
□ Постоянный мониторинг системы и борьба с авариями. Причем, как правило, неполадки возникают в самый неподходящий момент и там, где их совсем не ждешь. Здесь от администратора потребуется хорошее знание не только операционной системы, но и аппаратуры, на которой она работает.
□ Настройка производительности системы.
□ Обучение, наставление, "ссоры" и "примирения" с пользователями операционной системы, которую вы обслуживаете.
В этой книге вы не найдете практического руководства по администрированию системы. Вместо этого в следующих главах мы попытаемся взглянуть на UNIX изнутри, понять как устроена эта система и как она работает. Может быть после этого вы посмотрите на руководства другими глазами, а администрирование системы не сведется к простому заучиванию команд.
В качестве компенсации за отсутствие практического руководства предлагаю вашему вниманию перевод материала, найденный мною на одном из WWW-серверов Internet, в котором приведена забавная классификация системных администраторов.
Можно выделить четыре типа системных администраторов UNIX:
□ Технический бандит. Обычно в прошлом системный программист, вынужденный заниматься системным администрированием. Пишет скрипты на смеси языков интерпретатора Bourne shell, sed, С, awk, perl и APL.
□ Администратор-фашист. Обычно это законченный тунеядец (реже – бывшая ведьма-секретарша), вынужденный заниматься системным администрированием.
□ Маньяк. Стареющий хакер, обнаруживший, что ни Массада, ни Куба не собираются достойно оплачивать его услуги по компьютерному шпионажу, вследствие чего подавшийся в системные администраторы.
□ Идиот. Полный кретин или старый программист на Коболе, выбранный в системные администраторы комитетом, состоящим из таких же кретинов или старых программистов на Коболе.
Как определить, к какому типу принадлежит ваш системный администратор?
Технический бандит. Пишет набор скриптов для мониторинга использования дискового пространства, для сопровождения базы данных статистики использования диска, для прогнозирования будущего использования с помощью регрессионного анализа, для выявления пользователей, которые превысили стандартное отклонение от среднего значения и, наконец, для отправления нарушителям почтовых сообщений. Помещает скрипты под управление cron(1). В результате свободное дисковое пространство не увеличивается, поскольку «дисковые обжоры» обычно не читают почту.
Администратор-фашист. Помещает правила использования диска в сообщение дня motd. Активно пользуется квотированием дискового пространства. Не допускает никаких исключений, чем полностью останавливает деятельность разработчиков. Блокирует регистрацию пользователей, превысивших квоту.
Маньяк:
# cd /home
# rm -rf `du -s * | sort -rn | head -1 | awk '{print $2}'`
Идиот:
# cd /home
# cat `du -s * | sort -rn | head -1 | awk '{ printf «%s/*n», $2}'` | compress
Технический бандит. Пишет набор скриптов для мониторинга использования вычислительных ресурсов, для сопровождения базы данных статистики их использования, для выявления процессов, превысивших стандартное значение и для изменения приоритета таких процессов. Помещает скрипты под управление cron(1). В результате понижения приоритета офисной базы данных, предает ее забвению, ставя всю работу на грань срыва к немалой радости поклонников игры в
Администратор-фашист. Помещает правила использования вычислительных ресурсов в сообщение дня motd. Активно пользуется квотированием процессорных ресурсов. Не допускает никаких исключений, чем полностью останавливает деятельность разработчиков к немалой радости поклонников игры в xtrek.
Маньяк:
# kill -9 `ps -augxww | sort -rn +8 -9 | head -1 | awk '{print $2}'`
Идиот:
# compress -f `ps -augxww | sort -rn +8 -9 | head -1 | awk '{print $2}'`
Технический бандит. Пишет скрипт на языке Perl, создающий домашний каталог пользователя, определяющий непонятное окружение и помещающий записи в файлы /etc/passwd, /etc/shadow и /etc/group. Устанавливает на скрипт бит SUID и обязывает секретаршу обеспечить регистрацию новых пользователей. Поскольку обычно секретарша так и не может разобраться в разнице между <Enter> и <Return>, ни один новый пользователь не зарегистрирован.
Администратор-фашист. Помещает правила регистрации пользователей в сообщение дня motd. Поскольку незарегистрированные пользователи не могут прочитать это сообщение, никто не выполняет бюрократических требований, и, как следствие, ни один новый пользователь не зарегистрирован.
Маньяк. «Если ты настолько глуп, что не можешь взломать машину и самостоятельно зарегистрироваться, тебе нечего делать в моей системе. В этом ящике и так слишком много придурков».
Идиот:
# cd /home; mkdir «Bob's home directory»
# echo «Bob Simon:gandalf:0:0::/dev/tty:compress -f» > /etc/passwd
Технический бандит. Чинит диск. Обычно ему удается восстановить файловую систему прямо из приглашения загрузки. Если это не помогает, запускает микроядро, которое запускает на соседнем компьютере скрипт, копирующий на аварийную машину загрузочный код, переформатирующий диск и инсталлирующий операционную систему. Оставляет скрипт работать до конца уик-энда, а сам отправляется в поход в горы.
Администратор-фашист. Начинает расследование аварии. Отказывается исправить аварию до тех пор, пока виновный не найден, и с него не взыскана стоимость сломанного оборудования.
Маньяк. Извлекает диск. С помощью кузнечного молота пытается подогнать отдельные пластины. Звонит производителю. Во время установки нового диска и операционной системы наносит оскорбления присланному инженеру.
Идиот. Не замечает ничего необычного.
Технический бандит. Пишет скрипт для мониторинга сети, переписывает программное обеспечение, чем повышает производительность на 2%. Пожимает плечами, говорит: «Я сделал все, что мог», и отправляется в поход в горы.
Администратор-фашист. Помещает правила работы в сети в сообщение дня motd. Звонит в Беркли и в AT&T, приставая к ним, как установить сетевые квоты. Пытается уволить поклонников игры в xtrek.
Маньяк. Каждые два часа размыкает кабель Ethernet и ждет тайм-аута на сетевых соединениях.
Идиот:
# compress -f /dev/en0
Технический бандит. Отвечает на вопросы в шестнадцатеричном или двоичном виде, иногда по-французски, пока пользователь не уходит.
Администратор-фашист. Блокирует вход пользователя в систему, пока тот не представит веские доказательства своей квалификации.
Маньяк:
# cat >> ~luser/.cshrc
alias vi 'rm !*;unalias vi;grep -v BoZo ~/.cshrc > ~/.z;
mv -f ~/.z ~/~/cshrc'
^D
Идиот. Отвечает на все вопросы в меру своего понимания. Приглашает пользователя в группу администрирования системы.
Технический бандит. Изучает исходные тексты новой версии и выбирает из них только то, что ему нравится.
Администратор-фашист. В первую очередь изучает законодательные акты против производителя, поставляющего программное обеспечение с ошибками.
Маньяк:
# uptime
1:33pm up 19 days, 22:49, 167 users, load average: 6.49, 6.45, 6.31
# wall
Итак, настало время установки новой версии. Займет несколько часов, и если нам повезет – управимся к 5-00. Мы работаем для вас!
^D
Идиот:
# dd if=/dev/rmt8 of=/vmunix
Технический бандит. Пишет программу на RDBMS, perl и Smalltalk. Отчаявшиеся пользователи возвращаются к использованию записных книжек.
Администратор-фашист. Устанавливает Oracle. Отчаявшиеся пользователи возвращаются к использованию записных книжек.
Маньяк. Предлагает пользователям хранить данные в едином сплошном файле и применять grep(1) для поиска телефонных номеров.
Идиот:
% dd ibs=80 if=/dev/rdisk001s7 | grep «Fred»
Заключение
Эта глава знакомит с пользовательской средой UNIX, а также с основными подсистемами этой операционной системы – файловой подсистемой, подсистемой управления процессами и памятью, и с подсистемой ввода/вывода.
Большое внимание уделено командному интерпретатору shell, и его языку программирования. Это, как вы убедились, достаточно мощный инструмент, который, в частности, используется при администрировании системы и конфигурации процесса инициализации UNIX. В конце главы приведены наиболее распространенные утилиты, которые можно найти в любой версии UNIX.
Глава 2
Среда программирования UNIX
Одной из целей, которые изначально ставились перед разработчиками UNIX, являлось создание удобной среды программирования. Во многом это справедливо и сегодня.
Разговор в данной главе пойдет о программировании в UNIX. Может показаться, что предлагаемый материал интересен лишь разработчикам программного обеспечения. Это не совсем так. Безусловно, разработка программ невозможна без знания интерфейса системных вызовов и без понимания внутренних структур и функций, предоставляемых операционной системой. Однако осмысленное администрирование системы также затруднительно без представления о том, как работает UNIX. Программный интерфейс UNIX позволяет наглядно показать внутренние механизмы этой операционной системы.
В начале главы дана общая характеристика программного интерфейса UNIX и связанной с ним среды разработки; затронуты такие важные темы, как обработка ошибок, различия между системными вызовами и функциями стандартных библиотек, форматы исполняемых файлов и размещение образа программы в памяти; также описано, как происходит запуск и завершение программы с точки зрения программиста.
Следующие два раздела посвящены подробному обсуждению программного интерфейса двух важнейших подсистем операционной системы UNIX: файловой подсистемы и подсистемы управления процессами и памятью. В них рассматриваются важнейшие системные вызовы работы с файлами, функции стандартной библиотеки ввода/вывода, системные вызовы создания процесса, запуска новой программы и управления процессами.
В заключение приводятся два типичных приложения: демон и командный интерпретатор, на примере которых проиллюстрированы темы, затронутые в данной главе.
Программный интерфейс UNIX
Системные вызовы и функции стандартных библиотекВсе версии UNIX предоставляют строго определенный ограниченный набор входов в ядро операционной системы, через которые прикладные задачи имеют возможность воспользоваться базовыми услугами, предоставляемыми UNIX. Эти точки входа получили название системных вызовов (system calls). Системный вызов, таким образом, определяет функцию, выполняемую ядром операционной системы от имени процесса, выполнившего вызов, и является интерфейсом самого низкого уровня взаимодействия прикладных процессов с ядром. Седьмая редакция UNIX включала около 50 системных вызовов, современные версии, например, SVR4, предлагают более 120.
Системные вызовы обычно документированы в разделе 2 электронного справочника. В среде программирования UNIX они определяются как функции С, независимо от фактической реализации вызова функции ядра операционной системы. В UNIX используется подход, при котором каждый системный вызов имеет соответствующую функцию (или функции) с тем же именем, хранящуюся в стандартной библиотеке языка С (в дальнейшем эти функции будем для простоты называть системными вызовами). Функции библиотеки выполняют необходимое преобразование аргументов и вызывают требуемую процедуру ядра, используя различные приемы. Заметим, что в этом случае библиотечный код выполняет только роль оболочки, в то время как фактические инструкции расположены в ядре операционной системы.
Помимо системных вызовов программисту предлагается большой набор функций общего назначения. Эти функции не являются точками входа в ядро операционной системы, хотя в процессе выполнения многие из них выполняют системные вызовы. Например, функция printf(3S) использует системный вызов write(2) для записи данных в файл, в то время как функции strcpy(3C) (копирование строки) или atoi(3C) (преобразование символа в его числовое значение) вообще не прибегают к услугам операционной системы. Функции, о которых идет речь, хранятся в стандартных библиотеках С и наряду с системными вызовами составляют основу среды программирования в UNIX. Подробное описание этих функций приведено в разделе 3 электронного справочника.
Таким образом, часть библиотечных функций является "надстройкой" над системными вызовами, обеспечивающей более удобный способ получения системных услуг. В качестве примера рассмотрим процесс получения текущей даты и времени. Соответствующий системный вызов time(2) возвращает время в секундах, прошедшее с момента Epoch: 1 января 1970 года. Дополнительная интерпретация этого значения, такая как преобразование в вид, удобный для восприятия (дата и время) с учетом временной зоны, осуществляется библиотечными функциями (ctime(3C), localtime(3C) и т.д.). К этим функциям можно отнести функции библиотеки ввода/вывода, функции распределения памяти, часть функций управления процессами и т.д.
На рис. 2.1 показана схема взаимодействия приложения с ядром операционной системы при использовании системных вызовов и библиотечных функций.
Рис. 2.1. Системные вызовы и библиотечные функции
Обработка ошибокВ предыдущем разделе мы обсудили разницу между системными вызовами и библиотечными функциями. Они также различаются по способу передачи процессу информации об ошибке, произошедшей во время выполнения системного вызова или функции библиотеки.
Обычно в случае возникновения ошибки системные вызовы возвращают и устанавливают значение переменной errno, указывающее причину возникновения ошибки. Так, например, существует более десятка причин завершения вызова open(2) с ошибкой, и все они могут быть определены с помощью переменной errno. Файл заголовков
Библиотечные функции, как правило, не устанавливают значение переменной errno, а код возврата различен для разных функций. Для уточнения возвращаемого значения библиотечной функции необходимо обратиться к электронному справочнику man(1).
Поскольку базовым способом получения услуг ядра являются системные вызовы, рассмотрим более подробно обработку ошибок в этом случае.
Переменная errno определена следующим образом:
external int errno;
Следует обратить внимание, что значение errno не обнуляется следующим нормально завершившимся системным вызовом. Таким образом, значение errno имеет смысл только после системного вызова, который завершился с ошибкой.
Стандарт ANSI С определяет две функции, помогающие сообщить причину ошибочной ситуации: strerror(3C) и perror(3C).
Функция strerror(3C) имеет вид:
#include
char *strerror(int errnum);
Функция принимает в качестве аргумента errnum номер ошибки и возвращает указатель на строку, содержащую сообщение о причине ошибочной ситуации.
Функция perror(3C) объявлена следующим образом:
#include
#include
void perror(const char *s);
Функция выводит в стандартный поток сообщений об ошибках информацию об ошибочной ситуации, основываясь на значении переменной errno. Строка s, передаваемая функции, предваряет это сообщение и может служить дополнительной информацией, например содержа название функции или программы, в которой произошла ошибка.
Следующий пример иллюстрирует использование этих двух функций:
#include
#include
main(int argc, char *argv[]) {
fprintf(stderr, «ENOMEM: %sn», strerror(ENOMEM));
errno = ENOEXEC;
perror(argv[0]);
}
Запустив программу, мы получим следующий результат на экране:
$ a.out
ENOMEM: Not enough space
a.out: Exec format error
Эти функции используются, в частности, командным интерпретатором и большинством стандартных утилит UNIX. Например:
$ rm does_not_exist
does_not_exist: No such file or directory
ошибка ENOENT
$ pg do_not_read
do_not_read: Permission denied
ошибка EACCESS
$
В табл. 2.1 приведены наиболее общие ошибки системных вызовов, включая сообщения, которые обычно выводят функции strerror(3C) и perror(3C), а также их краткое описание.
Таблица 2.1. Некоторые ошибки системных вызовов
E2BIG Arg list too long | Размер списка аргументов, переданных системному вызову exec(2), плюс размер экспортируемых переменных окружения превышает ARG_MAX байт |
EACCESS Permission denied | Попытка доступа к файлу с недостаточными правами для данного класса (определяемого эффективным UID и GID процесса и соответствующими идентификаторами файла) |
EAGAIN Resource temporarily unavailable | Превышен предел использования некоторого ресурса, например, переполнена таблица процессов или пользователь превысил ограничение по количеству процессов с одинаковым UID. Причиной также может являться недостаток памяти или превышение соответствующего ограничения (см. раздел «Ограничения» далее в этой главе) |
EALREADY Operation already in progress | Попытка операции с неблокируемым объектом, уже обслуживающим некоторую операцию |
EBADF Bad file number | Попытка операции с файловым дескриптором, не адресующим никакой файл; также попытка операции чтения или записи с файловым дескриптором, полученным при открытии файла на запись или чтение, соответственно |
EBADFD File descriptor in bad state | Файловый дескриптор не адресует открытый файл или попытка операции чтения с файловым дескриптором, полученным при открытии файла только на запись |
EBUSY Device busy | Попытка монтирования устройства (файловой системы), которое уже примонтировано; попытка размонтировать файловую систему, имеющую открытые файлы; попытка обращения к недоступным ресурсам (семафоры, блокираторы и т.п.) |
ECHILD No child processes | Вызов функции wait(2) процессом, не имеющим дочерних процессов или процессов, для которых уже был сделан вызов wait(2) |
EDQUOT Disk quota exceeded | Попытка записи в файл, создание каталога или файла при превышении квоты пользователя на дисковые блоки, попытка создания файла при превышении пользовательской квоты на число inode |
EEXIST File exists | Имя существующего файла использовано в недопустимом контексте, например, сделана попытка создания символической связи с именем уже существующего файла |
EFAULT Bad address | Аппаратная ошибка при попытке использования системой аргумента функции, например, в качестве указателя передан недопустимый адрес |
EFBIG File too large | Размер файла превысил установленное ограничение RLIMIT_FSIZE или максимально допустимый размер для данной файловой системы (см. раздел «Ограничения» далее в этой главе) |
EINPROGRESS Operation now in progress | Попытка длительной операции (например, установление сетевого соединения) для неблокируемого объекта |
EINTR Interrupted system call | Получение асинхронного сигнала, например, сигнала SIGINT или SIGQUIT, во время обработки системного вызова. Если выполнение процесса будет продолжено после обработки сигнала, прерванный системный вызов завершится с этой ошибкой |
EINVAL Invalid argument | Передача неверного аргумента системному вызову. Например, размонтирование устройства (файловой системы), которое не было примонтировано. Другой пример – передача номера несуществующего сигнала системному вызову kill(2) |
EIO I/O error | Ошибка ввода/вывода физического устройства |
EISDIR Is a directory | Попытка операции, недопустимой для каталога, например, запись в каталог с помощью вызова write(2) |
ELOOP Number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS | При попытке трансляции имени файла было обнаружено недопустимо большое число символических связей, превышающее значение MAXSYMLINKS |
EMFILE Too many open files | Число открытых файлов для процесса превысило максимальное значение OPEN_MAX |
ENAMETOOLONG File name too long | Длина полного имени файла (включая путь) превысила максимальное значение PATH_MAX |
ENFILE File table overflow | Переполнение файловой таблицы |
ENODEV No such device | Попытка недопустимой операции для устройства. Например, попытка чтения устройства только для записи или операция для несуществующего устройства |
ENOENT No such file or directory | Файл с указанным именем не существует или отсутствует каталог, указанный в полном имени файла |
ENOEXEC Exec format error | Попытка запуска на выполнение файла, который имеет права на выполнение, но не является файлом допустимого исполняемого формата |
ENOMEM Not enough space | При попытке запуска программы (exec(2)) или размещения памяти (brk(2)) размер запрашиваемой памяти превысил максимально возможный в системе |
ENOMSG No message of desired type | Попытка получения сообщения определенного типа, которого не существует в очереди (см. раздел «Сообщения» в главе 3) |
ENOSPC No space left on device | Попытка записи в файл или создания нового каталога при отсутствии свободного места на устройстве (в файловой системе) |
ENOSR Out of stream resources | Отсутствие очередей или головных модулей при попытке открытия устройства STREAMS. Это состояние является временным. После освобождения соответствующих ресурсов другими процессами операция может пройти успешно |
ENOSTR Not a stream device | Попытка применения операции, определенной для устройств типа STREAMS (например системного вызова putmsg(2) или getmsg(2)), для устройства другого типа |
ENOTDIR Not a directory | В операции, предусматривающей в качестве аргумента имя каталога, было указано имя файла другого типа (например, в пути для полного имени файла) |
ENOTTY Inappropriate ioctl for device | Попытка системного вызова ioctl(2) для устройства, которое не является символьным |
EPERM Not owner | Попытка модификации файла, способом, разрешенным только владельцу и суперпользователю и запрещенным остальным пользователям. Попытка операции, разрешенной только суперпользователю |
EPIPE Broken pipe | Попытка записи в канал (pipe), для которого не существует процесса, принимающего данные. В этой ситуации процессу обычно отправляется соответствующий сигнал. Ошибка возвращается при игнорировании сигнала |
EROFS Read-only file system | Попытка модификации файла или каталога для устройства (файловой системы), примонтированного только на чтение |
ESRCH No such process | Процесс с указанным PID не существует в системе |