Secuencia de arranque en una sesión de consola
Para consultar la dependencia jerárquica entre unos procesos y otros
existe en Linux el utilísimo comando pstree. No es esencial y quizas
no lo tenga usted instalado pero resulta muy práctico. Si dispone de
él pruebe los comandos 'pstree', y 'pstree -p'. Nosotros vamos a mostrar
el resultado de ambos comandos en el sistema que estamos usando en este
momento para que en cualquier caso pueda apreciar el resultado pero le
recomendamos que lo instale si no dispone de él ya que resulta muy
práctico. Tambien puede usar como sustituto de 'pstree' el comando
'ps axf' pero no espere un resultado tan bonito.
$ pstree
init-+-apache---7*[apache]
|-atd
|-bash---pstree
|-2*[bash]
|-bash---vi
|-bash---xinit-+-XF86_S3V
| `-mwm-+-.xinitrc---xterm---bash
| `-.xinitrc---xclock
|-cron
|-getty
|-gpm
|-inetd
|-kflushd
|-klogd
|-kpiod
|-kswapd
|-kupdate
|-lpd
|-portmap
|-postmaster
|-sendmail
|-sshd
|-syslogd
`-xfs
|
Este formato nos da un arbol de procesos abreviado en el que procesos
con el mismo nombre y que tengan un mismo padre aparecerán de forma
abreviada. En el ejemplo anterior aparece '2*[bash]' indicando que
hay dos procesos bash como hijos de init, y tambien hay algunos proceso
apache arrancados. El que existan muchos procesos arrancados no indica
necesariamente un alto consumo de CPU. Puede que estén todos ellos
haciendo el vago. Bueno en el caso de apache quizas estén haciendo
el indio. (Esto último es una broma que no he podido evitar).
$ pstree -p
init(1)-+-apache(204)-+-apache(216)
| |-apache(217)
| |-apache(218)
| |-apache(219)
| |-apache(220)
| |-apache(1680)
| `-apache(1682)
|-atd(196)
|-bash(210)---pstree(1779)
|-bash(211)
|-bash(212)---vi(1695)
|-bash(215)---xinit(1639)-+-XF86_S3V(1644)
| `-mwm(1647)-+-.xinitrc(1652)---xterm(1660)---bash(1661)
| `-.xinitrc(1655)---xclock(1673)
|-bash(214)
|-cron(199)
|-getty(213)
|-gpm(143)
|-inetd(138)
|-kflushd(2)
|-klogd(131)
|-kpiod(4)
|-kswapd(5)
|-kupdate(3)
|-lpd(153)
|-portmap(136)
|-postmaster(168)
|-sendmail(179)
|-sshd(183)
|-syslogd(129)
`-xfs(186)
|
En este otro formato. Aparece cada proceso con su PID. Podemos ver
que el Proceso 'init' tiene pid = 1 y ha realizado varios forks()
generando procesos con pid > 1.
En algunos sistemas la generación de números de PID para procesos
nuevos se realiza en secuencia. En otros resulta un número impredecible.
Entre los procesos
generados por 'init' están los procesos 'getty'. Se arrancará un 'getty'
por cada terminal. Este proceso configura la velocidad y otras cosas del
terminal, manda un saludo y luego se transforma con exec el proceso 'login'.
Todos estos
procesos se ejecutan con EUID y UID = 0, es decir como procesos del
superusuario root. Cuando el proceso 'login' conoce nuestra
identidad después de validar usuario password se transformará con exec
en la shell especificada e
para nuestro usuario el fichero /etc/passwd
Para ver la linea que contiene sus datos pruebe a hacer lo siguiente:
$ grep `whoami` /etc/passwd
|
La linea tiene el siguiente formato.
login:contraseña:UID:GID:nombre:dir:intérprete
Vamos a suponer que su shell por defecto sea la bash. Si esta shell
arrancara con el EUID = 0 tendríamos todos los privilegios del super usuario
pero esto no ocurre así. Esta shell ya tendrá nuestro UID y nuestro EUID.
Vamos a representar todo esto marcando los puntos en los que ocurre
algún fork() con un signo '+'.
[init]-+fork()->[getty]
|
+fork()->[getty]-exec()->[login]-exec()->[bash]+fork()-exec()->[comando]
|
+fork()->[getty]
|
La shell puede arrancar un comando mediante un fork() y luego un exec() y
esperar a que este muera. Recuerde que la función exec() no tiene retorno
posible ya que finaliza con la muerte del proceso. En ese momento
la shell detecta la muerte de su hijo y continua su ejecución solicitando
la entrada de un nuevo comando. Cuando introducimos el comando 'exit' estamos
indicando a la shell que finalice y su padre 'init' se encargará de lanzar
nuevo proceso 'getty'. Lógicamente 'exit' es un comando interno de la shell.
Quizas le llame la atención que la muerte de 'bash'
termine provocando un nuevo 'getty' cuando 'getty' pasó a 'login' y este a
'bash' pero en esta secuencia getty-login-bash no hay ningún fork() por eso
getty, login, y bash son en realidad el mismo proceso en distintos momentos
con el mismo PID obtenido en el fork() realizado por 'init' solo que ha ido
cambiando su personalidad manteniendo la misma identidad (mismo PID).
Para 'init' siempre se trató del mismo hijo y la muerte de cualquiera
de ellos (getty, login o bash) provoca que se arranque
un nuevo 'getty' sobre ese mismo terminal con el fin de que ese terminal
no quede sin servicio.
La presentación del mensaje de Login es mostrada por 'getty'.
Una vez introducido el identificador de usuario será 'login' quien
muestre la solicitud de introducción de la password, y una vez
introducido el password será la shell quien muestre el introductor
de comandos pero estamos hablando siempre del mismo proceso.
A modo de ejercicio compruebe estas cosas por usted mismo
usando algunos de los comandos que ya conoce. Para hacer
esta práctica no basta con usar un terminal remoto sino
que necesitará un PC completo para ir haciendo cosas desde
distintas sesiones.
Le proponemos hacerlo más o menos de la siguiente manera:
- Entre en cada uno de los terminales disponibles de forma que todos
los terminales esten ocupados por un interprete de comandos. Bastará
con hacer login en todos ellos.
- Luego compruebe que no hay ningún proceso 'getty'.
- Haga un exit desde uno de estos terminales.
- Compruebe desde otro termina que ahora si existe un proceso
'getty' y anote su pid.
- Introduzca el nombre de usuario en ese terminal que quedó libre.
- Compruebe ahora desde otra sesion que existe un proceso login con
el PID que usted anotó.
- Termine de indentificarse tecleando la password
- Compruebe desde otra sesión que ahora existe una shell con el PID
que anotamos.
Si no tiene el comando 'pstree' tendrá que usar 'ps' pero con pstree
puede ver más facilmente lo que ocurrirá ahora.
- Ahora teclee el comando 'sleep 222' desde la sesión que tiene el
PID anotado por usted.
- Compruebe desde otra sesión que el interprete de comandos ha
realizado un fork() generando un comando que está ejecutando el
comando indicado.
Si no ha podido realizar el ejercicio anterior tendrá que confiar en que
las cosas son como decimos y ya está.
Comando ps
Muestra los procesos activos. Este comando es muy util para saber que
comandos están funcionando en un determinado momento.
Siempre que se mencione un comando puede consultar la página man del mismo.
En el caso de 'ps' se lo recomendamos ya que es un comando muy util con
una gran cantidad de opciones. Nostros mencionaremos algunos ejemplos pero
se aconseja probar 'ps' probando las distintas opciones que se mencionan en
la página del manual.
Ejemplos:
# Para ver todos sus procesos que están
# asociados a algún terminal.
$ ps
PID TTY STAT TIME COMMAND
.......
# Para ver todos sus procesos y los de otros
# usuarios siempre asociados a algún terminal.
$ ps a
PID TTY STAT TIME COMMAND
.......
# Para ver todos sus procesos estén asociados o
# no a algún terminal.
$ ps x
PID TTY STAT TIME COMMAND
.......
# Para ver todos los proceso asociados al
# terminal 1
$ ps t1
PID TTY STAT TIME COMMAND
.......
# Para ver todos los procesos del sistema.
$ ps ax
PID TTY STAT TIME COMMAND
.......
|
Estos ejemplos que acabamos de ver obtienen un mismo formato de datos.
Explicaremos el significado de estos atributos.