Init

Anuncio
Autores:
Fecha:
Francisco A. Ortega Muñoz
Noemí Guerra Sosa
Abril 2002
© Universidad de Las Palmas de Gran Canaria
Init es el padre de todos los procesos de usuario
Para cada terminal crea un proceso hijo
Configuración de la
línea.
Identificación del
usuario.
Realizar el login.
Conexión de la
terminal.
Diseño de Sistemas Operativos
2
Init
Shell
Shell
Shell
Procesos de Usuario
Diseño de Sistemas Operativos
3
Manejo de procesos
Tareas de E/S
Procesos Servidores
Procesos de usuario
Init inicializan
Abstracción
Se
Manejador
de
detodos
Memoria
procesos
los manejadores
(MM).
para las capas
de dispositivo.
superiores.
Manejo del
Sistema
Procesos
de
demecanismo
Ficheros
usuario (FS).
de mensajes.
Servidor de Red.
Diseño de Sistemas Operativos
4
Inicializa y enlaza cada una de las terminales.
Mantiene un historial de las conexiones.
Gestiona la desconexión de las terminales.
Maneja los errores de conexión de las terminales.
Diseño de Sistemas Operativos
5
Ejecución del fichero /etc/rc:
Path del sistema.
Inicialización del teclado.
Establecimiento de la fecha y de la zona horaria.
Preparación de los ficheros /etc/utmp y /etc/wtmp.
Se monta la partición /usr.
Comprobación del cierre correcto en la sesión anterior.
Inicialización de los servicios de red.
Se borran ficheros temporales.
Diseño de Sistemas Operativos
6
Bucle principal:
Inicialización de cada una de las terminales del fichero /etc/ttytab
(startup)
Si un proceso hijo (terminal) finaliza se reexamina el fichero
/etc/ttytab para buscar nuevas conexiones.
Diseño de Sistemas Operativos
7
Acciones de startup:
Configurar los parámetros de la terminal
(stty): Velocidad de la línea
Paridad
Ejecutar el
Getty: Se pide la identificación del
usuario
Se lanza el login
Ejecutar /usr/bin/login:
Si el login es correcto, lanza el shell indicado en /etc/passwd
Ejecución en el shell:
Fork
Exec
Diseño de Sistemas Operativos
8
Diseño de Sistemas Operativos
9
SIGHUP
Se olvidan todos los errores.
Lee de nuevo el fichero /etc/ttytab.
Para cada terminal de /etc/ttytab que no tenga un proceso
asociado, y que no tenga el número máximo de errores permitidos, se
crea un proceso.
SIGTERM
Provoca que init deje de generar procesos.
Normalmente se usa cuando se resetea o se apaga el sistema.
SIGABRT
La envía el driver del teclado.
Provoca que se de la orden de apagar el sistema.
Diseño de Sistemas Operativos
10
slots
Estructura slotent
Asocia una terminal con un proceso
0
1
2
Struct slotent{
int errct;
pid_t pid;
}
PIDSLOTS = 32;
Struct slotent
slots[PIDSLOTS];
31
Diseño de Sistemas Operativos
11
Estructura ttyent
Define para cada terminal: el nombre, el tipo y los comandos para
configurar e iniciar una terminal
Struct ttyent{
char *ty_name;
char *ty_type;
char **ty_getty;
char **ty_init;
}
Struct ttyent *ttyp;
Diseño de Sistemas Operativos
12
Fichero /etc/ttytab
#ttytab - terminals
#
#Device Type
Program
console minix
getty
ttyc1
minix
getty
ttyc2
minix
getty
ttyc3
minix
getty
tty00
unknown
tty01
unknown
ttyp1
network
ttyp2
network
ttyp3
network
Init
Diseño de Sistemas Operativos
13
Procesos
Ficheros
fork
wait
waitpid
exit
execve
setsid
open
close
read
write
lseek
dup
fstat
pipe
fcntl
Señales
sigaction
alarm
Diseño de Sistemas Operativos
14
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/wait.h>
<sys/stat.h>
<ttyent.h>
<errno.h>
<fcntl.h>
<limits.h>
<signal.h>
<string.h>
<time.h>
<stdlib.h>
<unistd.h>
<utmp.h>
char *REBOOT_CMD[] = { "shutdown", "now", "CTRL-ALT-DEL", NULL };
struct ttyent TT_REBOOT = { "console", "-", REBOOT_CMD, NULL };
char PATH_UTMP[] = "/etc/utmp";
char PATH_WTMP[] = "/usr/adm/wtmp";
Diseño de Sistemas Operativos
15
Se crea la estructura slots y se definen constantes relacionadas con
esta: nº máximo de terminales y nº máximo de errores.
#define PIDSLOTS
32
struct slotent {
int errct;
pid_t pid;
};
#define ERRCT_DISABLE 10
#define NO_PID 0
struct slotent slots[PIDSLOTS];
int gothup = 0;
int gotabrt = 0;
int spawn = 1;
Diseño de Sistemas Operativos
16
Se inicializan gothup, gotabrt y spawn.
gothup: Ha llegado la señal SIGHUP
gotabrt: Ha llegado la señal SIGABORT
spawn: Se pueden seguir conectando nuevas terminales
#define PIDSLOTS
32
struct slotent {
int errct;
pid_t pid;
};
#define ERRCT_DISABLE 10
#define NO_PID 0
struct slotent slots[PIDSLOTS];
int gothup = 0;
int gotabrt = 0;
int spawn = 1;
Diseño de Sistemas Operativos
17
Declaración de prototipos de las funciones de este módulo.
Declaración de la función main.
Inicialización de variables:
check: Se debe reexaminar el fichero ttytab
void tell(int fd, char *s);
void report(int fd, char *label);
void wtmp(int type, int linenr, char *line, pid_t pid);
void startup(int linenr, struct ttyent *ttyp);
int execute(char **cmd);
void onhup(int sig);
void onterm(int sig);
void onabrt(int sig);
int main(void)
{
pid_t pid;
int fd;
int linenr;
int check;
Diseño de Sistemas Operativos
18
Se capturan los descriptores de la entrada(0), la salida(1) y el
error(2) estándar.
struct
struct
struct
struct
slotent *slotp;
ttyent *ttyp;
sigaction sa;
stat stb;
if (fstat(0, &stb) < 0) {
(void) open("/dev/null", O_RDONLY);
(void) open("/dev/log", O_WRONLY);
dup(1);
}
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
Diseño de Sistemas Operativos
19
Se asocian funciones a las señales.
sa.sa_handler = onhup;
sigaction(SIGHUP, &sa, NULL);
sa.sa_handler = onterm;
sigaction(SIGTERM, &sa, NULL);
sa.sa_handler = onabrt;
sigaction(SIGABRT, &sa, NULL);
Diseño de Sistemas Operativos
20
Se crea un proceso hijo para ejecutar el fichero /etc/rc. El padre
espera a que este acabe.
if ((pid = fork()) != 0) {
while (wait(NULL) != pid) {
if (gotabrt) reboot(RBT_HALT);
}
} else {
static char *rc_command[] = { "sh", "/etc/rc", NULL, NULL };
#if __minix_vmd
rc_command[2] = getenv("bootopts");
#else
close(0);
(void) open("/dev/console", O_RDONLY);
#endif
execute(rc_command);
report(2, "sh /etc/rc");
_exit(1); /* No debería llegar aquí */
}
Diseño de Sistemas Operativos
21
Se borra el fichero /etc/utmp.
Se registra el inicio del sistema en el fichero /usr/adm/wtmp.
if ((fd = open(PATH_UTMP, O_WRONLY | O_TRUNC)) >= 0) close(fd);
wtmp(BOOT_TIME, 0, NULL, 0);
Diseño de Sistemas Operativos
22
Se inicia el bucle principal.
Espera a que el proceso asociado a una terminal muera.
Se registra en los ficheros /usr/adm/wtmp y /etc/utmp.
Se libera la entrada correspondiente en slots.
Se debe reexaminar el fichero /etc/ttytab (check).
check = 1;
while (1) {
while ((pid = waitpid(-1, NULL, check ? WNOHANG : 0)) > 0) {
for (linenr = 0; linenr < PIDSLOTS; linenr++) {
slotp = &slots[linenr];
if (slotp->pid == pid) {
wtmp(DEAD_PROCESS, linenr, NULL, pid);
slotp->pid = NO_PID;
check = 1;
}
}
}
Diseño de Sistemas Operativos
23
En caso de haber recibido la señal SIGHUP:
Se resetean los errores de las terminales.
Se debe reexaminar el fichero /etc/ttytab (check).
if (gothup) {
gothup = 0;
for (linenr = 0; linenr < PIDSLOTS; linenr++)
slots[linenr].errct = 0;
check = 1;
}
Diseño de Sistemas Operativos
24
Se reexamina el fichero /etc/ttytab
Se lee una entrada del fichero /etc/ttytab
Se comprueba que la terminal no supera el nº máximo de errores
Se conecta la terminal (startup)
if (gotabrt) {
gotabrt = 0;
startup(0, &TT_REBOOT);
}
if (spawn && check) {
for (linenr = 0; linenr < PIDSLOTS; linenr++) {
slotp = &slots[linenr];
if ((ttyp = getttyent()) == NULL) break;
if (ttyp->ty_getty != NULL && ttyp->ty_getty[0] != NULL
&& slotp->pid == NO_PID && slotp->errct < ERRCT_DISABLE)
startup(linenr, ttyp);
}
endttyent();
}
check = 0;
}
Diseño de Sistemas Operativos
25
}
Funciones para el manejo de las señales:
void onhup(int sig)
{
gothup = 1;
spawn = 1;
}
void onterm(int sig)
{
spawn = 0;
}
void onabrt(int sig)
{
static int count;
if (++count == 2) reboot(RBT_HALT);
gotabrt = 1;
}
Diseño de Sistemas Operativos
26
Función startup. Se crea un proceso hijo.
Se crea un pipe (err) para la comunicación de errores del hijo al
padre
void startup(int linenr, struct ttyent *ttyp)
{
struct slotent *slotp;
pid_t pid;
int err[2];
char line[32];
int status;
slotp = &slots[linenr];
if (pipe(err) < 0) err[0] = err[1] = -1;
if ((pid = fork()) == -1 ) {
report(2, "fork()");
sleep(10);
return;
}
Diseño de Sistemas Operativos
27
Se crea una sesión
if (pid == 0) {
close(err[0]);
fcntl(err[1], F_SETFD, fcntl(err[1], F_GETFD) | FD_CLOEXEC);
setsid();
strcpy(line, "/dev/");
strncat(line, ttyp->ty_name, sizeof(line) - 6);
close(0);
close(1);
if (open(line, O_RDWR) < 0 || dup(0) < 0) {
write(err[1], &errno, sizeof(errno));
_exit(1);
}
Diseño de Sistemas Operativos
28
Se abren la entrada y salida estándar de la terminal
if (pid == 0) {
close(err[0]);
fcntl(err[1], F_SETFD, fcntl(err[1], F_GETFD) | FD_CLOEXEC);
setsid();
strcpy(line, "/dev/");
strncat(line, ttyp->ty_name, sizeof(line) - 6);
close(0);
close(1);
if (open(line, O_RDWR) < 0 || dup(0) < 0) {
write(err[1], &errno, sizeof(errno));
_exit(1);
}
Diseño de Sistemas Operativos
29
El hijo crea una nuevo proceso.
Este último inicializa la terminal.
La terminal debe iniciarse antes de 10 segundos
if (ttyp->ty_init != NULL && ttyp->ty_init[0] != NULL) {
if ((pid = fork()) == -1) { /*Error en el fork*/
report(2, "fork()");
errno= 0;
write(err[1], &errno, sizeof(errno));
_exit(1);
}
if (pid == 0) {
alarm(10);
execute(ttyp->ty_init);
report(2, ttyp->ty_init[0]);
_exit(1);
}
Diseño de Sistemas Operativos
30
El proceso hijo inicial espera a que se inicie la terminal
Se ejecuta el comando getty: Conexión de la terminal
while (waitpid(pid, &status, 0) != pid) {}
if (status != 0) {
tell(2, "init: ");
tell(2, ttyp->ty_name);
tell(2, ": ");
tell(2, ttyp->ty_init[0]);
tell(2, ": bad exit status\n");
errno = 0;
write(err[1], &errno, sizeof(errno));
_exit(1);
}
}
dup2(0, 2);
execute(ttyp->ty_getty);
Diseño de Sistemas Operativos
31
El padre comprueba si se produjeron errores en la inicialización o
en la conexión
fcntl(2, F_SETFL, fcntl(2, F_GETFL) | O_NONBLOCK);
if (linenr != 0) report(2, ttyp->ty_getty[0]);
write(err[1], &errno, sizeof(errno));
exit(1);
}
if (ttyp != &TT_REBOOT)
slotp->pid = pid;
close(err[1]);
if (read(err[0], &errno, sizeof(errno)) != 0) {
switch (errno) {
case ENOENT:
case ENODEV:
case ENXIO:
Diseño de Sistemas Operativos
32
Se gestionan los errores
Errores graves: Se deshabilita directamente la terminal
Errores simples: Se incrementa en una unidad el nº de errores
Si el nº de errores supera un umbral se deshabilita la terminal
slotp->errct = ERRCT_DISABLE;
close(err[0]);
return;
case 0:
break;
default:
report(2, ttyp->ty_name);
}
close(err[0]);
if (++slotp->errct >= ERRCT_DISABLE) {
tell(2, "init: ");
tell(2, ttyp->ty_name);
tell(2, ": excessive errors, shutting down\n");
} else {
sleep(5);
}
Diseño de Sistemas Operativos
33
Si no se produjeron errores se registra el inicio de la conexión en
/etc/utmp
return;
}
close(err[0]);
if (ttyp != &TT_REBOOT)
wtmp(LOGIN_PROCESS, linenr, ttyp->ty_name, pid);
slotp->errct = 0;
}
Diseño de Sistemas Operativos
34
Función execute.
Prueba a ejecutar un comando en cuatro rutas diferentes.
Si el comando empieza por ‘/’ se considera que el path ya está
completo
int execute(char **cmd)
{
static char *nullenv[] = { NULL };
char command[128];
char *path[] = { "/sbin", "/bin", "/usr/sbin", "/usr/bin" };
int i;
if (cmd[0][0] == '/') {
return execve(cmd[0], cmd, nullenv);
}
Diseño de Sistemas Operativos
35
Se prueba la ejecución del comando en cada una de las rutas.
Si se produce un error, y este no hace referencia a que no
existe el fichero, se prueba el siguiente path.
for (i = 0; i < 4; i++) {
if (strlen(path[i]) + 1 + strlen(cmd[0]) + 1 >
sizeof(command)) {
errno= ENAMETOOLONG;
return -1;
}
strcpy(command, path[i]);
strcat(command, "/");
strcat(command, cmd[0]);
execve(command, cmd, nullenv);
if (errno != ENOENT) break;
}
return -1;
}
Diseño de Sistemas Operativos
36
Función wtmp. Actualiza los ficheros wtmp y utmp.
Se escribe en la estructura utmp el nombre de la línea.
void wtmp(type, linenr, line, pid)
int type;
int linenr;
char *line;
pid_t pid;
{
struct utmp utmp;
int fd;
memset((void *) &utmp, 0, sizeof(utmp));
switch (type) {
case BOOT_TIME:
strcpy(utmp.ut_name, "reboot");
strcpy(utmp.ut_line, "~");
break;
case LOGIN_PROCESS:
strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
break;
Diseño de Sistemas Operativos
37
case DEAD_PROCESS:
if ((fd = open(PATH_UTMP, O_RDONLY)) < 0) {
if (errno != ENOENT) report(2, PATH_UTMP);
return;
}
if (lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET)
== -1 || read(fd, &utmp, sizeof(utmp)) == -1
) {
report(2, PATH_UTMP);
close(fd);
return;
}
close(fd);
if (utmp.ut_type != USER_PROCESS) return;
strncpy(utmp.ut_name, "", sizeof(utmp.ut_name));
break;
}
Diseño de Sistemas Operativos
38
Se completan el resto de los campos de utmp (hora, pid y tipo de
proceso).
El inicio y la muerte de los procesos asociados a una terminal se
registran en el fichero utmp.
utmp.ut_pid = pid;
utmp.ut_type = type;
utmp.ut_time = time((time_t *) 0);
switch (type) {
case LOGIN_PROCESS:
case DEAD_PROCESS:
if ((fd = open(PATH_UTMP, O_WRONLY)) < 0
|| lseek(fd, (off_t) (linenr+1) * sizeof(utmp),SEEK_SET)
== -1 || write(fd, &utmp, sizeof(utmp)) == -1){
if (errno != ENOENT) report(2, PATH_UTMP);
}
if (fd != -1) close(fd);
break;
}
Diseño de Sistemas Operativos
39
El inicio del sistema y la muerte de los procesos asociados a una
terminal se registran en el fichero wtmp..
switch (type) {
case BOOT_TIME:
case DEAD_PROCESS:
/* Escribe una nueva entrada en el fichero ‘wtmp’ */
if ((fd = open(PATH_WTMP, O_WRONLY | O_APPEND)) < 0
|| write(fd, &utmp, sizeof(utmp)) == -1
) {
if (errno != ENOENT) report(2, PATH_WTMP);
}
if (fd != -1) close(fd);
break;
}
}
Diseño de Sistemas Operativos
40
Funciones tell y report. Muestran los mensajes de error.
void tell(fd, s)
int fd;
char *s;
{
write(fd, s, strlen(s));
}
void report(fd, label)
int fd;
char *label;
{
int err = errno;
tell(fd, "init: ");
tell(fd, label);
tell(fd, ": ");
tell(fd, strerror(err));
tell(fd, "\n");
errno= err;
}
Diseño de Sistemas Operativos
41
¿En qué momento se ejecuta Init?
¿Qué tareas realiza Init?
¿Por qué Init se queda residente en memoria?
Diseño de Sistemas Operativos
42
Fin de la Presentación
struct sigaction {
__sighandler_t sa_handler; //nombre de la función
sigset_t sa_mask;
//señales a ser bloqueadas durante el manejo
int sa_flags;
// flags especiales
}
Diseño de Sistemas Operativos
44
Descargar