- •Введение
- •Лабораторная работа 1.
- •Регистрация пользователя в системе
- •Выход из системы
- •Выполнение простых команд
- •Группирование команд
- •Задание для самостоятельной работы
- •Контрольные вопросы
- •Задание для самостоятельной работы
- •Контрольные вопросы
- •Задание для самостоятельной работы
- •Контрольные вопросы
- •Задание для самостоятельной работы
- •Контрольные вопросы
- •Литература
- •5.3. Задание для самостоятельной работы
- •5.4. Контрольные вопросы
- •Задание для самостоятельной работы
- •Контрольные вопросы
- •Задание для самостоятельной работы
- •Формат файла /etc/passwd
- •Формат файла /etc/shadow
- •Формат файла /etc/group
- •Создание нового пользователя
- •Переключение между пользователями
- •Файлы инициализации пользователей
- •Файлы, регламентирующие работу пользователей
- •Задания для самостоятельной работы
- •Контрольные вопросы
- •9.3. Права доступа к каталогам
- •9.4. Смена прав доступа на файлы
- •9.5. Маска на вновь создаваемые файлы
- •9.6. Дополнительные атрибуты файла
- •9.7. Списки управления доступом
- •Задания для самостоятельной работы
- •Контрольные вопросы
- •10.3. Метасимволы или шаблоны
- •10.4. История команд
- •10.5. Псевдонимы
- •10.6. Перенаправление ввода и вывода
- •10.7. Конвейеры
- •10.8. Приглашение ко вводу
- •10.9. Сценарии оболочки
- •10.10. Задания для самостоятельной работы
- •10.11. Контрольные вопросы
- •11.3. Системный вызов open()
- •11.4. Системный вызов read()
- •11.5. Системный вызов write()
- •11.6. Системный вызов lseek()
- •11.7. Системный вызов close()
- •11.8. Задания для самостоятельной работы
- •11.9. Контрольные вопросы
- •12.3. Системный вызов fork
- •12.4. Системный вызов exit
- •12.5. Системный вызов wait
- •12.6. Системный вызов exec
- •12.7. Системные вызовы наследования пользовательских дескрипторов файла
- •12.8. Задания для самостоятельной работы
- •12.9. Контрольные вопросы
- •13.3. Системный вызов signal
- •13.4. Системный вызов pause
- •13.5. Системный вызов alarm
- •13.6. Управление непредусмотренными событиями
- •13.7. Неименованные каналы
- •13.8. Именованные каналы
- •13.9. Задания для самостоятельной работы
- •13.10. Контрольные вопросы
- •Литература
- •Заключение
- •Учебное издание
- •Системное программирование Лабораторный практикум
12.4. Системный вызов exit
Системный вызов exit служит для завершения процесса и имеет следующий формат: void exit (int status). Системный вызов exit закрывает все дескрипторы файла процесса, освобождает его код, данные и стек, а затем заканчивает процесс. Когда дочерний процесс завершается, он посылает своему родителю сигнал SIGCHLD и ждет его код статуса – status завершения для того, чтобы принять его. Используются только младшие восемь битов статуса. Процесс, который ожидает своего родителя, чтобы принять от него код возврата, называется зомби-процессом. Родитель принимает код завершения дочернего процесса, выполняя системный вызов wait. Ядро гарантирует, что все осиротевшие дети завершающегося процесса усыновляются процессом init путем установки их PPID в 1. Процесс init всегда принимает коды завершения своих порожденных процессов.
12.5. Системный вызов wait
Системный вызов wait заставляет процесс приостанавливаться, пока один из его дочерних процессов не закончит выполнение. Данный вызов имеет следующий формат: wait (int* status). Успешный вызов wait возвращает PID завершившегося порожденного процесса и помещает код статуса в status, который кодируется следующим образом:
если правый байт status – 0, левый байт содержит восемь битов значения, возвращаемого системным вызовом wait;
если правый байт отличен от 0, самые правые семь битов равны номеру сигнала, который заставил дочерний процесс завершить работу, и оставшийся бит самого правого байта установлен в 1, если порожденный процесс произвел дамп памяти;
Если процесс выполняет системный вызов wait и не имеет дочерних процессов, wait возвращается немедленно с -1. Если процесс выполняет wait и один или большее его порожденных процессов уже зомби, wait возвращается немедленно со статусом одного из зомби.
Пример. Ниже приведен фрагмент программы на языке Си, иллюстрирующий применение системных вызовов fork, wait и exit
main ()
{
int pid, status, died;
switch(pid = fork()) { /* порождаем новый процесс */
case -1: /* аварийное завершение */
printf(“Can’t fork\n”);
exit(-1);
case 0: /* процесс потомок */
printf(“I am the child\n”);
exit(3);
default: /* процесс предок ожидает окончания процесса потомка */
died =wait(&status);
}
printf(“Child was %d\n”, pid);
printf(“%d died\n”, died);
printf(“Exit value %d\n”, status>>8);
printf(“Exit status %d\n”, status & 0377);
exit(0);
}
12.6. Системный вызов exec
Системный вызов exec заменяет программу текущего процесса. Процесс может заменить свой текущий код, данные и стек с таковыми другого исполняемого файла, используя один из системных вызовов семейства exec. Когда процесс выполняет exec, его номера PID и PPID остаются теми же самыми – заменяется лишь код, выполняемый процессом. Приведем форматы семейства системных вызовов exec:
execl(name, arg0, arg1, …, argn,0)
char *name, *arg0, *arg1, …, *argn;
execv(name, argv)
char *name, *argv[];
execle(name, arg0, arg1, …, argn,0, envp)
char *name, *arg0, *arg1, …, *argn, *envp[];
execve(name, argv, envp)
char *name, *argv[],*envp[] ;
Здесь аргумент name имеет тип данных указатель на символы и специфицирует имя файла, содержащего исполняемый код программ, а аргументы arg0, arg1, …, argn, которые также имеют тип данных указатель на символы, специфицируют аргументы этой программы, передаваемые ей при вызове ее на выполнение.
Системный вызов execl используется, как правило, в том случае, когда вызываемая на выполнение программа имеет фиксированное число аргументов. При этом аргумент arg0 специфицирует имя файла, содержащего вызываемую на выполнение программу, а в качестве последнего аргумента обязательно должен быть символ 0 или NULL.Например, рассмотрим вызов на выполнение команды ls с помощью системного вызова execl: execl(“/bin/ls”, “ls”, “-l”, 0). В качестве аргумента name использовано абсолютное полное имя файла, содержащего команду ls, в противном случае поиск файла будет осуществляться только в текущем каталоге.
Системный вызов execv, наоборот, используется чаще всего в случае, когда число аргументов вызываемой на выполнение программы заранее не известно. При этом аргумент name системного вызова специфицирует абсолютное полное имя файла, содержащего исполняемый код программы, а аргумент argv, имеющий тип данных массив указателей на символы, специфицирует весь список аргументов вызываемой на выполнение программы. Последним элементом этого списка должна быть строка, содержащая только символ 0 или NULL. В качестве примера рассмотрим вызов на выполнение команды ls с помощью системного вызова execv:
char *pv[] = {
“cc”,
“-0”,
“fred”,
“fred.c”,
0
};
main()
{
execv(“/bin/cc”, pv);
}
Пример. Ниже приведен фрагмент программы на языке Си, иллюстрирующий использование системных вызовов fork, wait, exit и execl:
main ()
{
int pid, status;
switch(pid = fork()) { /* порождаем новый процесс */
case -1: /* аварийное завершение */
printf(“Can’t fork\n”);
exit(-1);
case 0: /* процесс потомок */
printf(“I am the child\n”);
execl(“/bin/echo”, “echo”, “Hello mike !”, 0);
/* запускаем программу echo “Hello mike !” */
exit(1);
break;
default: /* процесс предок */
wait(&status);
/* ожидаем завершения процесса потомка */
}
/* процесс отец выводит на экран код завершения и статус завершения процесса потомка */
printf(“Exit value %d\n”, status>>8);
printf(“Exit status %d\n”, status & 0377);
exit(0);
}