Hace tiempo hablábamos de capturar señales, aunque en ocasiones, es necesario saber quién me envía esa señal, si por ejemplo nos envían un SIGINT o SIGTERM, tal vez queremos saber qué proceso nos quiere muerto y qué usuario lo ha invocado. O tal vez estamos esperando una señal de control (SIGUSR1, por ejemplo) por parte de un proceso cliente específico.
El problema es que por nuestro modo actual de direccionar señales (con signal(señal, funcion)) sólo comunicamos el número de señal que se ha recibido, sin más información.
Para capturar esta información necesitamos utilizar sigaction para establecer la función a la que llamaremos cuando llegue la señal, para utilizarla podemos utilizar el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <unistd.h> #include <signal.h> #include <string.h> void recibe_signal(int signum, siginfo_t *siginfo, void *context) { /* Mostramos toda la información necesaria */ printf ("[%d] Recibida %d (%s) de %d (UID: %d) ¿Error? %d \n", getpid(), signum, strsignal(signum), siginfo->si_pid, siginfo->si_uid, siginfo->si_errno); } int main(int argc, char *argv[]) { struct sigaction sact; sigfillset(&sact.sa_mask); /* Definimos la función callback */ sact.sa_sigaction = recibe_signal; /* Queremos usar el callback sigaction en lugar del dado por signal() */ sact.sa_flags = SA_SIGINFO; sigaction(SIGUSR1, &sact, NULL); /* Bucle infinito, para cerrar el proceso, utilizar kill -9 PID */ while (1) pause; return 0; } |
Como vemos sigaction tiene 3 parámetros:
- La señal que queremos capturar
- Un registro de tipo struct sigaction
- La acción que se ejecutaba antes, por si queremos guardarla para restaurarla más tarde
Dentro del registro, tendremos como valores importantes (struct sigaction act):
- sact.sa_sigaction : que especifica la función que la llamaremos, esta función será del tipo void funcion(int, siginfo_t*, void*), donde el primer int recibirá la señal que nos han enviado (tal y como hacía la función que asignábamos con signal), el segundo parámetro será información asociada a la señal, y la tercera el contexto de ejecución.
- sact.sa_handler : será la función a la que se llama, es la misma que cuando hacemos signal(señal, funcion)
- sact.sa_flags : Es un conjunto de flags, si especificamos SA_SIGINFO, estaremos dando paso a la función especificada por sa_sigaction, si no utilizaremos sa_handler. Aunque esta variable vale para más cosas, para esta práctica nos vale con saber esto. (man sigaction para más info)
- sact.sa_mask
: Nos proporciona una máscara de las señales que serán bloquedas, podemos utilizar sigfillset() para rellenar toda la máscara automáticamente. Si queremos que unas se bloqueen y otras no podemos utilizar sigaddset() y sigdelset()
Ahora bien, la función que se llamará cuando venga una señal tendrá el prototipo que hemos visto antes con tres parámetros: la señal recibida, la información de la señal con un puntero a siginfo_t y el contexto de ejecución, que se pasará con un puntero a void, que por ahora no utilizaremos. La estructura que controla la información de la señal entre otros muchos datos nos facilitará lo siguiente:
- si_pid : PID que nos envía la señal (y esta acción da título al post)
- si_uid : Usuario que ejecuta el proceso que nos manda la señal
- si_errno : Algún error que haya causado la señal
- … para más información, man sigaction
Para preparar la sentencia tendremos que escribir varias líneas definiendo los valores del registro así como la llamada a la función sigaction(), por lo tanto podremos crear una función que tenga los parámetros más comunes a la hora de definir este tipo de acciones, así lo llamamos como a signal():
1 2 3 4 5 6 7 8 9 10 11 12 | int sigact(int signum, void funcion(int, siginfo_t *, void *)) { struct sigaction sact; sigfillset(&sact.sa_mask); /* Definimos la función callback */ sact.sa_sigaction = funcion; /* Queremos usar el callback sigaction en lugar del dado por signal() */ sact.sa_flags = SA_SIGINFO; return sigaction(signum, &sact, NULL); } |
En esta función es importante poner bien el prototipo de la función como parámetro, eso lo comenté en un post anterior sobre callbacks
Ahora, vamos a dejar el código más bonito, este programa implementará el control de errores y nos permitirá salir cuando recibamos 5 SIGINT (pulsemos 5 veces control+C):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <unistd.h> #include <signal.h> #include <string.h> void error(char *cadena); int sigact(int signum, void funcion(int, siginfo_t *, void *)); void llegasigint(); void recibe_signal(int signum, siginfo_t *siginfo, void *context); int main(int argc, char *argv[]) { if (sigact(SIGUSR1, recibe_signal)==-1) error("No puedo establecer SIGUSR1"); if (sigact(SIGINT, recibe_signal)==-1) error("No puedo establecer SIGINT"); if (sigact(SIGTERM, recibe_signal)==-1) error("No puedo establecer SIGTERM"); if (sigact(SIGUSR2, recibe_signal)==-1) error("No puedo establecer SIGUSR2"); if (sigact(SIGQUIT, recibe_signal)==-1) error("No puedo establecer SIGQUIT"); /* Bucle infinito, para cerrar el proceso, utilizar kill -9 PID */ while (1) pause(); return 0; } void error(char *cadena) { fprintf(stderr, "ERROR: %s (errno: %d: %s)\n", cadena, errno, strerror(errno)); exit(1); } void llegasigint() { static int num=0; /* No he querido usar variables globales */ num++; if (num==5) { printf ("FIN del programa\n"); exit(1); } } void recibe_signal(int signum, siginfo_t *siginfo, void *context) { /* Mostramos toda la información necesaria */ printf ("[%d] Recibida %d (%s) de %d (UID: %d) ¿Error? %d \n", getpid(), /* PID del proceso actual */ signum, /* Número de señal recibida */ strsignal(signum), /* Señal escrita en texto (inglés) */ siginfo->si_pid, /* PID del proceso que nos manda la señal */ siginfo->si_uid, /* Usuario que nos manda la señal */ siginfo->si_errno); /* Error producido */ if (signum==SIGINT) llegasigint(); } int sigact(int signum, void funcion(int, siginfo_t *, void *)) { struct sigaction sact; sigfillset(&sact.sa_mask); /* Definimos la función callback */ sact.sa_sigaction = funcion; /* Queremos usar el callback sigaction en lugar del dado por signal() */ sact.sa_flags = SA_SIGINFO; return sigaction(signum, &sact, NULL); } |
Pingback: Bitacoras.com /
it’s really attractive and even meanful. it’s really nice web log. Associating is amazingly invaluable item. you have got certainly given a hand to plenty of people just who have a look at web log and allow them all usefull tips.
This is definitely the knowledge We are acquiring all over the place. Cheers for ones web site, I merely join your blog. This is the wonderful web site
The audio will be awesome. You might have several extremely skilled performers. My partner and i want an individual the most effective regarding accomplishment. ultra panda mobi
TrustSpot Playground: Dive into a secure gaming adventure at TrustSpot Playground. Rigorously screened for fraud, this Toto site guarantees safety. Backed by a robust operational track record, substantial capital, and swift withdrawals, your peace of mind is our priority. 안전놀이터
It is a great website.. The Design looks very good.. Keep working like that!. โปรโมชั่น ufabet
I appreciated your work very thanks ufabet.com ทางเข้า
Thanks for your post. I’ve been thinking about writing a very comparable post over the last couple of weeks, I’ll probably keep it short and sweet and link to this instead if thats cool. Thanks. ufabet.com ทางเข้า มือถือ
The writer has outdone himself this time. It is not at all enough; the website is also utmost perfect. I will never forget to visit your site again and again. 강남 룸
Great knowledge, do anyone mind merely reference back to it 홍대룸싸롱
Awesome article! I want people to know just how good this information is in your article. It’s interesting, compelling content. Your views are much like my own concerning this subject. 우리카지노
Yes, I am entirely agreed with this article, and I just want say that this article is very helpful and enlightening. I also have some precious piece of concerned info !!!!!!Thanks. 신촌고수익알바
This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work!. Casselberry personal trainer
This is a great post. I like this topic.This site has lots of advantage.I found many interesting things from this site. It helps me in many ways.Thanks for posting this again. router
If more people that write articles really concerned themselves with writing great content like you, more readers would be interested in their writings. Thank you for caring about your content. buy ambien online
Join PLAYSBO for an elite online football betting adventure! Enjoy quick service, fair play, and exclusive promotions that set us apart. Trust us for seamless transactions and unbeatable satisfaction in the world of online betting. sbobet88
Positive site, where did u come up with the information on this posting? I’m pleased I discovered it though, ill be checking back soon to find out what additional posts you include. tdtc
I think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article. 토토사이트 추천
Very interesting blog. Alot of blogs I see these days don’t really provide anything that I’m interested in, but I’m most definately interested in this one. Just thought that I would post and let you know. https://www.bsc.news/post/8-andab-ewbsl-t-opromchan-9rab100-r-ngrab-w-elth-thiiniymmaakthiisud-ainpii-2024
I read that Post and got it fine and informative. https://www.bsc.news/post/10-andab-ewbsl-t-opromchan-10rab100-thiiniymmaakthiisud-ainpii-2024
It’s appropriate time to make some plans for the future and it is time to be happy. I have read this post and if I could I wish to suggest you few interesting things or advice. Perhaps you could write next articles referring to this article. I desire to read even more things about it! Roses delivery abu dhabi
I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading. 강남 레깅스룸
Thanks so much for sharing this awesome info! I am looking forward to see more postsby you! Christy Rachel
Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with extra information? It is extremely helpful for me. 릴게임사이트
This is very interesting content! I have thoroughly enjoyed reading your points and have come to the conclusion that you are right about many of them. You are great. Thương hiệu okvip