#include <stdlib.h>
- int system (cadena)
- const char *cadena;
- Ejemplo:
/* system.c - Listar los procesos del usuario usando system. */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int salida; /* Salida del comando */
char comando[100]; /* Comando a ejecutar */
printf ("Ejemplo de system.\n");
sprintf (comando, "/bin/ps -fu %s", getenv ("USER"));
salida = system (comando);
printf ("Salida del comando: %d\n", salida);
exit (salida);
}
Ejemplo de system. USER PID PPID TTY CMD ramon 3638 1 hft/0 -ksh ramon 10089 10600 hfp/0 /bin/ps -fu ramon ramon 10600 11623 hft/0 bsh bsh bsh ramon 11623 3638 hft/0 system.e Salida del comando: 0Suponiendo que no existe el comando MUSHO y sustituyendo la ejecución de system por la siguiente línea, se obtiene la salida mostrada a continuación.
salida = system ("MUSHO BETI");
Ejemplo de system. bsh: MUSHO: no encontrado. Salida del comando: 256
#include <unistd.h>
- int execl (camino, arg0 [, arg1, ...] , 0)
- const char *camino, *arg0, *arg1, ...;
- int execle (camino, arg0 [, arg1, ...] , 0, p_entorno)
- const char *camino, *arg0, *arg1, ...;
- char *const p_entorno[];
- int execlp (fichero, arg0 [, arg1, ...] , 0)
- const char *fichero, *arg0, *arg1, ...;
- int execv (camino, val_args)
- const char *camino;
- char *const val_args[];
- int execve (camino, val_arg, p_entorno)
- const char *camino;
- char *const val_args[], *p_entorno[];
- int execvp (fichero, val_args)
- const char *fichero;
- char *const val_args[];
- int exect (camino, val_arg, p_entorno)
- char *camino, *val_args, *p_entorno[];
int main (cont_args, val_args, p_entorno)
- int cont_args; /* Contador de argumentos. */
- char *val_args; /* Puntero a la matriz de argumentos. */
- char *p_entorno; /* Puntero a la matriz del entorno. */
- Ejemplo:
exit (salida);
}
/* exec.c - Listar los procesos del usuario usando exec. */
#include <stdio.h>
#include <unistd.h>
int main ()
{
int salida;/* Salida del comando */
printf ("Ejemplo de exec.\n");
execl ("/bin/ps", "ps", "-fu", getenv ("USER"), 0);
printf ("Salida del comando: %d\n", salida);
Ejemplo de system. USER PID PPID TTY CMD ramon 3638 1 hft/0 -ksh ramon 10739 3638 hft/0 /bin/ps -fu ramonSuponiendo que no existe el comando MUSHO y sustituyendo la ejecución de execl por la siguiente línea, se obtiene la salida mostrada a continuación.
salida = execl ("MUSHO", "BETI", 0);
Ejemplo de exec. Salida del comando: -1
#include <unistd.h>
- pid_t fork ();
int vfork ();
- Ejemplos:
printf ("Inicio del proceso padre. PID=%d\n", getpid ());
if (fork() == 0)
{ /* Proceso hijo */
printf ("Inicio proceso hijo. PID=%d, PPID=%d\n",
getpid (), getppid ());
sleep (1);
}
else
{ /* Proceso padre */
printf ("Continuación del padre. PID=%d\n", getpid ());
sleep (1);
}
printf ("Fin del proceso %d\n", getpid ());
exit (0);
}
/* fork.c - Ejecución conjunta de procesos padre e hijo */
#include <stdio.h>
#include <unistd.h>
main ()
{
printf ("Ejemplo de fork.\n");
Ejemplo de fork. Inicio proceso padre. PID=8153 Inicio proceso hijo. PID=6618, PPID=8153 Continuación proceso padre. PID=8153 Fin del proceso 6618 Fin del proceso 8153
- Ejemplo:
/* fork_huerf.c - Ejemplo de proceso huérfano *
#include <stdio.h>
#include <unistd.h>
main ()
{
printf ("Ejemplo de proceso huérfano.\n");
printf ("Inicio del proceso padre. PID=%d\n", getpid ());
if (fork () == 0)
{
printf ("Inicio proceso hijo. PID=%d, PPID=%d\n",
getpid (), getppid ());
sleep (1);
printf ("El proceso queda huérfano. PID=%d PPID=%d\n",
getpid (), getppid ());
}
else
printf ("Concinuación del padre. PID=%d\n", getpid ());
printf ("Fin del proceso %d\n", getpid ());
exit (0);
}
Ejemplo de proceso huérfano. Inicio proceso padre. PID=11330 Inicio proceso hijo. PID=6467, PPID=11330 Continuación proceso padre. PID=11330 Fin del proceso 11330 $punto indicativo> El proceso queda huérfano. PID=6467, PPID=1 Fin del proceso 6467Notas:
#include <sys/wait.h>
- pid_t wait (estados)
- int *estados;
- pid_t wait ((void *) 0);
- pid_t waitpid (PID, estados, opciones)
- pid_t PID;
- int *estados, opciones;
WIFSTOPPED (estado) /* !=0, si estado es de un hijo parado */
- pid_t estado;
- int WSTOPSIG (estado) /* Nú de señal que ha causado la parada */
- pid_t estado;
- WIFEXITED (estado) /* !=0, si estado es de salida normal */
- pid_t estado;
- int WEXITSTATUS (estado) /* 8 bits bajos del estado de salida */
- pid_t estado;
- WIFSIGNALED (estado) /* !=0, si estado es de salida anormal */
- pid_t estado;
- int WTERMSIG (estado) /* Nú de sañal que ha causado la slida */
- pid_t estado;
- Ejemplos:
/* waitpid.c - Esperar la terminación de un proceso hijo */
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
main ()
{
pid_t id_padre; /* PID del proceso padre */
pid_t id_hijo; /* PID del proceso hijo */
int estado; /* Estado de salida */
printf ("Ejemplo de waitpid.\n");
printf ("Inicio proceso padre. PID=%d\n", getpid ());
id_padre = getpid ();
if ((id_hijo = fork ()) == 0)
{ /* Proceso hijo */
printf ("Inicio proceso hijo. PID=%d, PPID=%d\n",
getpid (), id_padre);
sleep (3);
printf ("Salida proceso hijo. PID=%d\n", getpid ());
exit (getpid () > id_padre); /* 1, si PID > PPID */
}
else
{
signal (SIGINT, SIG_IGN); /* Ignorar CTRL-C */
while (waitpid (id_hijo, &estado, 0) != id_hijo);
if (WIFSIGNALED (estado))
printf ("El proceso hijo ha recibido la señal %d\n", WTERMSIG (estado));
if (WIFEXITED (estado))
{
printf ("Estado de salida del proceso hijo: %d\n", WEXITSTATUS (estado));
if (WEXITSTATUS (estado) == 1)
printf ("PID hijo > PID padre.\n");
else
printf ("PID padre > PID hijo.\n");
}
printf ("Fin del proceso %d\n", getpid ());
exit (0);
}
Ejemplo de waitpid. Inicio proceso padre. PID=24213 Inicio proceso hijo. PID=31638, PPID=24213 Fin proceso hijo. PID=31638 Estado de salida del proceso hijo: 1 PID hijo > PID padre Fin del proceso 24213La salida siguiente muestra el efecto de generar una señal de interrupción pulsando [CTRL][C]. Dicha señal provoca la terminación automática del proceso hijo, mientras que el proceso padre la ignora (ver signal).
Ejemplo de waitpid. Inicio proceso padre. PID=7240 Inicio proceso hijo. PID=5705, PPID=7240 ^CEl proceso hijo ha recibido la señal: 2 Fin del proceso 7240
#include <stdlib.h>
- void exit (estado)
- int estado;
#include <sys/limits.h>
- int atexit (función)
- void (*función) (void);
- Ejemplo:
/* atexic.c - Ejecución de una rutina al salir de un programa */
#include <stdio.h>
#include <sys/limits.h>
int bucle=0; /* Contador de vueltas del bucle */
void salida (); /* Prototipo de la función de salida */
int main ()
{
int n;
atexit (salida);
printf ("Ejemplo de atexit.\n");
for (bucle=1; bucle<255; bucle++)
{
n=rand ();
printf ("%d-%d\t", bucle, n);
if (n > 30000)
exit (1);
}
exit (0);
}
void salida ()
{
printf ("El bucle ha dado %d vueltas.\n");
printf ("Hasta luega Lucas.\n");
}
Ejemplo de atexit. 1-16838 2-5758 3-10113 4-17515 5-31051 El bucle ha dado 5 vueltas. Hasta luego Lucas.
2. SEÑALES.
2,1. Conceptos generales.
Núm. | Nombre | Comentarios |
---|---|---|
1 | SIGHUP | Colgar. Generada al desconectar el terminar. |
2 | SIGINT | Interrupción. Generada por teclado. |
3 | SIGQUIT1 | Salir. Generada por teclado. |
4 | SIGILL1 | Instrucción ilegal. No se puede recapturar. |
5 | SIGTRAP1 | Trazado. No se puede recapturar. |
6 | SIGABRT1 | Abortar proceso. |
8 | SIGFPE1 | Excepción aritmética, de coma flotante o división por cero. |
9 | SIGKILL1 | Matar proceso. No puede capturarse, ni ignorarse. |
10 | SIGBUS1 | Error en el bus. |
11 | SIGSEGV1 | Violación de segmentación. |
12 | SIGSYS1 | Argumento erróneo en llamada al sistema. |
13 | SIGPIPE | Escritura en una tubería que otro proceso no lee. |
14 | SIGALRM | Alarma de reloj. |
15 | SIGTERM | Terminación del programa. |
16 | SIGURG2 | Urgencia en canal de E/S. |
17 | SIGSTOP3 | Parada de proceso. No puede capturarse, ni ignorarse. |
18 | SIGTSTP3 | Parada interactiva. Generada por teclado. |
19 | SIGCONT4 | Continuación. Generada por teclado. |
20 | SIGCHLD2 | Parada o salida de proceso hijo. |
21 | SIGTTIN3 | Un proceso en 2o plano intenta leer del terminal. |
22 | SIGTTOU3 | Un proceso en 2o plano intenta escribir en el terminal. |
23 | SIGIO2 | Operación de E/S posible o completada. |
24 | SIGXCPU | Tiempo de UCP excedido. |
25 | SIGXFSZ | Excedido el límite de tamaño de fichero. |
30 | SIGUSR1 | Definida por el usuario número 1. |
31 | SIGUSR2 | Definida por el usuario número 2. | 34 | SIGVTALRM | Alarma de tiempo virtual. |
36 | SIGPRE | Excepción programada. Definida por el usuario. |
Notas sobre la acción por defecto para la señal.
El rango de señales en el UNIX de Berkeley (BSD) es de 1 a 31.
2,3. Capturar señales.
2,3,1. Subrutina signal:
#include <signal.h>
- void (*signal (señal, acción)) ()
- int señal;
- void (*accón) ();
- Ejemplo:
/* signal.c - Contar el número de CTRL-C en 15 segundos */
#include <stdlib.h>
#include <signal.h>
int numcortes=0; /* Contador de CTRL-C */
int enbucle=1; /* Controlador de salida del bucle de espera */
void alarma (); /* Captura la señal de alarma SIGALRM */
void cortar (); /* Captura la señal de interrupción SIGINT */
int main ()
{
signal (SIGINT, cortar);
signal (SIGALRM, alarma);
printf ("Ejemplo de signal.\n");
printf ("Pulsa varias veces CTRL-C durante 15 segundos.\n");
alarm (15);
while (bucle);
signal (SIGINT, SIG_IGN);
printf ("Has intentado cortar %d veces.\n", numcortes);
printf ("Hasta luego Lucas.\n");
exit (0);
}
void alarma ()
{
signal (SIGALRM, SIG_IGN);
bucle=0; /* Salir del bucle */
printf ("¡Alarma!\n");
}
void cortar ()
{
signal (SIGINT, SIG_IGN);
printf ("Has pulsado CTRL-C\n");
numcortes++;
signal (SIGINT, cortar);
}
Ejemplo de signal. Pulsa CTRL-C varias veces durante 15 segundo. ^CHas pulsado CTRL-C ^CHas pulsado CTRL-C ^CHas pulsado CTRL-C ^CHas pulsado CTRL-C ^CHas pulsado CTRL-C ¡Alarma! Has intentado cortar 5 veces. Hasta luego Lucas.
#include <signal.h>
- int sigaction (señal, acción, acción_salida) ()
- int señal;
- struct sigaction *accón, *acción_salida;
void (*sa_handler) ();
Puntero a la rutina asociada con la señal o uno de los valores:
sigset_t sa_mask;
Especifica la máscara de las señales que serán bloqueadas durante la captura de la señal especificada.
int sa_flags;
_exit access alarm
chdir chmod chown
close creat dup
dup2 exec fcntl
fork fstat getegid
geteuid getgid getgroups
getpgrp getpid getppid
getuid kill link
lseek mkdir mkfifo
open pause pipe
readx rename rmdir
setgid setpgrp setuid
sigaction sigaddset sigdelset
sigfillset sigismember signal
sigpending sigprocmask sigsuspend
sleep statx tcdrain
tcflow tcflush tcgetattr
tcgetpgrp tcsendbreak tcsetattr
tcsetpgrp time times
umask uname unlink
ustat utime write
#include <signal.h>
- int kill (proceso, señal)
- pid_t proceso;
- int señal;
#include <sys/signal.h>
- int raise (señal)
- int señal;
error = kill (getpid (), señal);
#include <signal.h>
- int killpg (int grupo_procesos, int señal);
if (grupo_procesos < 0) { errno = ESRCH; return (-1); } return (kill(-grupo_procesos, señal));
- Ejemplo:
/* kill.c - Ejecución con tiempo de espera usando kill */
#include <stdlib.h>
#include <signal.h>
int espera; /* Tiempo de espera */
void hijo (); /* Controlador de fin de proceso hijo */
int main (int contargs, char *args[]);
{
pid_t pid;
if (contargs < 3)
{
printf ("Formato: %s segundos comando [opciones].\n", args[0]);
exit (1);
}
printf ("Ejemplo de kill.\n");
printf ("Ejecución con tiempo de espera.\n");
signal (SIGCHLD, hijo);
pid = fork ();
if (pid == 0)
{
execvp (args[2]; &args[2]);
perror (args[0]);
}
else
{
espera = atoi (args[1]);
sleep (espera);
printf ("El hijo %d ha excedido el tiempo de %d s.\n",
pid, espera);
signal (SIGCHLD, SIG_IGN);
kill (pid, SIGINT);
}
exit (1);
}
void espera ()
{
int id_hijo, est_hijo;
id_hijo = wait (&est_hijo);
printf ("El hijo %d ha terminado antes de %d s.\n",
id_hijo, espera);
exit (0);
}
$ kill.e 3 wc kill.c Ejemplo de kill. Ejecución de un comando con tiempo de espera. 45 132 1065 kill.c El hijo 10489 ha terminado antes de 3 s. $ kill.e 3 sleep 5 Ejemplo de kill. Ejecución de un comando con tiempo de espera. El hijo 10851 ha excedido el tiempo de espera de 3 s.
2,4. Alarmas y temporizadores.
2,4,1. Subrutinas alarm y ualarm:
#include <unistd.h>
- unsigned int alarm (segundos)
- unsigned int segundos;
- unsigned int ualarm (valor, intervalo)
- unsigned int valor, intervalo;
- Ejemplo:
/* alarm.c - Esperar una alarma */
#include <stdlib.h>
#include <unistd.h>
int main ()
{
printf ("Una alarma en 3 segundos.\n");
alarm (3);
printf ("Esperando...\n");
while (1);
printf ("Esta línea no se ejecutará nunca.\n");
exit (0);
}
Una alarma en 3 segundos. Esperando... Alarm clock
Núm. | Nombre | Descripción |
---|---|---|
1 | EPERM | Operación no permitida. |
2 | ENOENT | El archivo o directorio no existe. |
3 | ESRCH | El proceso no existe. |
4 | EINTR | Llamada al sistema interrumpida. |
5 | EIO | Error de E/S. |
6 | ENXIO | No existe dispositivo o dirección. |
7 | E2BIG | Lista de argumentos demasiado larga. |
8 | ENOEXEC | Error en formato de ejecución. |
9 | EBADF | Descriptor de fichero erróneo. |
10 | ECHILD | No existe el proceso hijo. |
11 | EGAIN | Recurso no disponible temporalmente. |
12 | ENOMEM | No hay suficiente espacio de memoria. |
13 | EACCES | Permiso denegado. |
14 | EFAULT | Dirección de memoria errónea. |
15 | ENOTBLK | Se necesita un fichero de bloques. |
16 | EBUSY | Recurso ocupado. |
17 | EEXIST | Fichero existente. |
18 | EXDEV | Enlace impropio. |
19 | ENODEV | Dispositivo inexistente. |
20 | ENOTDIR | No es un directorio. |
21 | EISDIR | Es un directorio. |
22 | EINVAL | Argumento no válido. |
23 | ENFILE | Demasiados ficheros abiertos en el sistema. |
24 | EMFILE | Demasiados ficheros abiertos. | 26 | ETXBUSY | Fichero de texto ocupado. |
27 | EFBIG | Fichero demasiado largo. |
28 | ENOSPC | No queda espacio en el dispositivo. |
29 | ESPIPE | Búsqueda no válida. |
30 | EROFS | Fichero sólo de lectura. |
32 | EPIPE | Tubería rota. |
33 | EDOM | Error de dominio matemático. |
34 | ERANGE | Resultado fuera de rango. |
78 | ETIMEDOUT | Excedido tiempo de conexión (NFS). |
88 | EDQUOT | Cuota de disco excedida. |
Nota: No se tratan aquí los errores relativos a comunicaciones, ni a sockets.
#include <errno.h>
- void perror (cadne)
- char *cadena;
extern int errno;
Número de error.
extern char *sys_errlist[];
Tabla con la descripción de los errores del sistema.
printf ("%s: %s\n", cadena, sys_errlist[errno]);
3. PIPES (TUBERÍAS).
3,1. Conceptos generales.
#include <unistd.h>
- #include <fcntl.h>
- #include <sys/types>
- int dup (desc_abierto)
- int desc_abierto;
- int dup2 (desc_abierto, desc_nuevo)
- int desc_abierto, desc_nuevo;
dup: | fcntl (desc_abierto, F_DUPFD, 0);
|
---|---|
dup2: | close (desc_nuevo);
fcntl (desc_abierto, F_DUPFD, desc_nuevo);
|
- Ejemplo:
/* dup2.c - Redirección usando dup2 */
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main (int contargs, char *args[])
{
int desc_fich;
if contargs < 3)
{
printf ("Formato: %s fichero comando [opciones].\n", args[0]);
exit (1);
}
printf ("Ejemplo de redirección.\n");
desc_fich = open (args[1], O_CREAT|O_TRUNC|O_WRONLY, 0);
dup2 (desc_fich, 1); /* Redirige la salida normal */
close (desc_fich);
execvp (args[2], &args[2]; /* Ejecuta comando */
exit (1);
}
$ dup2.e dup2.sal ls *.c Ejemplo de redirección. $ chmod 600 dup2.sal; cat dup2.sal alarm.c atexit.c dup2.c escritor_fifo.c exec.c fork.c fork_huerf.c kill.c lector_fifo.c pipe.c pipe_conec.c signal.c system.c waitpid.c
#include <unistd.h>
- #include <fcntl.h>
- #include <sys/types>
- int fcntl (descriptor, comando, argumento)
- int descriptor, comando, argumento);
F_DUPFD: | Obtener el menor descriptor de fichero disponible que sea mayor que el parámetro descriptor. Mantiene el mismo puntero y las mismas características del fichero original. |
---|---|
F_GETFD: | Obtener características del descriptor. |
F_SETFD: | Poner características del descriptor. |
F_GETFL: | Obtener estado del fichero. |
F_SETFL: | Poner estado del fichero. |
F_GETLK: | Obtener información de bloqueo. |
F_SETLK: | Poner bloqueo. |
F_SETLKW: | Poner bloqueo en una zona bloqueada. |
F_GETOWN: | Obtener PID (>0) o PGID (<0) del proceso que recibe las señales SIGIO o SIGURG. |
F_SETOWN: | Poner PID (>0) o PGID (<0) del proceso gestor de la E/S asíncrona. |
F_CLOSEM: | Cierra todos los descriptores desde descriptor hasta el valor máximo (OPEN_MAX). |
O_RDONLY: | Abierto sólo para lectura. |
---|---|
O_RDWR: | Abierto para lectura y escritura. |
O_WRONLY: | Abierto sólo para escritura. |
F_RDLCK: | Bloqueo de lectura (compartido). |
---|---|
F_WRLCK: | Bloqueo de escritura (exclusivo). |
F_UNLCK: | Sin bloqueo. |
#include <unistd.h>
- int pipe (descriptores)
- int descriptores[2];
- Ejemplos:
/* pipe.c - Tubería sin nombre entre procesos padre e hijo */
#include <stdlib.h>
#include <unistd.h>
#define LEER 0
#define ESCRIBIR 1
int main ()
{
int descr[2]; /* Descriptores de E y S de la turbería */
int bytesleidos;
char mensaje[100],
*frase="Veremos si la transferecia es buena.";
printf ("Ejemplo de tuberÍa entre padre e hijo.\n");
pipe (descr);
if (fork () == 0)
{
close (descr[LEER]);
write (descr[ESCRIBIR], frase, strlen(frase));
close (descr[ESCRIBIR]);
}
else
{
close (descr[ESCRIBIR]);
bytesleidos = read (descr[LEER], mensaje, 100);
printf ("Bytes leidos: %d\n");
printf ("Mensaje: %s\n", bytesleidos, mensaje);
close (descr[LEER]);
}
}
Ejemplo de tubería entre padre e hijo. Bytes leídos: 36 Mensaje: Veremos si la transferencia es buena.
/* pipe_conec.c - Tubería entre 2 comandos usando pipe. */
#include <stdlib.h>
#include <unistd.h>
#define LEER 0
#define ESCRIBIR 1
int main (int contargs, char *args[])
{
int descr[2]; /* Descriptores de E y S de la turbería */
if (contargs != 3)
{
printf ("Formato: %s comando_ent comando_sal.\n", args[0]);
exit (1);
}
pipe (descr);
if (fork () == 0)
{
close (descr[LEER]);
dup2 (descr[ESCRIBIR], 1);
close (descr[ESCRIBIR]);
execlp (args[1], args[1], NULL);
perror (args[0]);
}
else
{
close (descr[ESCRIBIR]);
dup2 (descr[LEER], 0);
close (descr[LEER]);
execlp (args[2], args[2], NULL);
perror (args[0]);
}
}
$ pipe_conec.e ls wc 37 37 354
#include <sys/mode.h>
- int mkfifo (camino, modo)
- const char *camino;
- int modo;
- Ejemplos:
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mode.h>
int main ()
{
int descr, longmens, i;
char mensaje[100];
sprintf (mensaje, "Un saludo desde el proceso %d", getpid ());
longmens = strlen (mensaje) + 1;
do
{ /* intentar la conexion */
descr = open ("tuberia", O_WRONLY);
if (descr == -1) sleep (1);
}
while (descr == -1);
for (i=0; i<3; i++)
{
write (descr, mensaje, longmens);
sleep (3);
}
close (descr);
printf "Fin del escritor %d\n", getpid ());
}
#!/bin/ksh
# fifo - Carga los procesos lector y escritor en 2o plano.
lector_fifo.e &
escritor_fifo.e &
escritor_fifo.e &
/* lector_fifo.c - Tuberia con nombre usando mkfifo */
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mode.h>
int linea (int df, char *cad);
int main ()
{
int descr;
char cadena[100];
unlink ("tuberia");
mkfifo ("tuberia", 0);
chmod ("tuberia", 460);
descr = open ("tuberia", O_RDONLY);
while (linea (descr, cadena))
printf ("%s\n", cadena);
close (descr);
pritnf ("Fin del lector.\n");
}
int linea (int df, char *cad)
{
int n;
do
{
n = read (df, cad, 1);
}
while (n > 0 && *cad++ != NULL);
return (n > 0);
}
$ fifo $Un saludo desde el proceso 11996 Un saludo desde el proceso 10971 Un saludo desde el proceso 11996 Un saludo desde el proceso 10971 Un saludo desde el proceso 11996 Un saludo desde el proceso 10971 Fin del escritor 10971 Fin del escritor 11996 Fin del lector