Skip to content

Instantly share code, notes, and snippets.

@Pikrass
Created April 27, 2013 00:54
Show Gist options
  • Save Pikrass/5471424 to your computer and use it in GitHub Desktop.
Save Pikrass/5471424 to your computer and use it in GitHub Desktop.
Programmes de lancement et de contrôle de mon site en FastCGI
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
char* arg0;
void drop_privileges() {
if(setreuid(geteuid(), -1) == -1) {
perror(arg0);
exit(5);
}
if(setregid(getegid(), -1) == -1) {
perror(arg0);
exit(5);
}
}
void usage(char *arg0) {
printf("Usage: %s stop|restart|pause|resume\n", arg0);
}
int main(int argc, char** argv) {
arg0 = argv[0];
if(argc != 2) {
usage(argv[0]);
exit(1);
}
// Oubli de l'uid et du gid réels
drop_privileges();
// Récupération du pid
char pidstr[10];
FILE* pidfile = fopen("/run/fastcgi/alliance-rainbow.pid", "r");
if(pidfile == NULL) {
perror(argv[0]);
exit(2);
}
int nbRead = fread(pidstr, sizeof(char), 9, pidfile);
fclose(pidfile);
pidstr[nbRead] = '\0';
pid_t pid = (pid_t) strtoimax(pidstr, NULL, 10);
// Choix du signal
if(strcmp(argv[1], "stop") == 0) {
kill(pid, SIGTERM);
}
else if(strcmp(argv[1], "restart") == 0) {
kill(pid, SIGUSR1);
}
else if(strcmp(argv[1], "pause") == 0) {
kill(pid, SIGUSR2);
}
else if(strcmp(argv[1], "resume") == 0) {
kill(pid, SIGCONT);
}
else {
usage(argv[0]);
exit(1);
}
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <errno.h>
#define UNIX_PATH_MAX 108
char *arg0;
int shutdowning = 0;
int pidMain = -1, pidAjax = -1;
/* ---------- Fonctions d'initialisation ---------- */
void drop_privileges() {
if(setreuid(geteuid(), -1) == -1) {
perror(arg0);
exit(5);
}
if(setregid(getegid(), -1) == -1) {
perror(arg0);
exit(5);
}
}
void daemonize() {
if(daemon(1, 1) == -1) {
perror(arg0);
exit(6);
}
}
void mkPidfile() {
FILE *pidfile = fopen("/run/fastcgi/alliance-rainbow.pid", "w");
if(!pidfile) {
perror(arg0);
exit(7);
}
fprintf(pidfile, "%d", getpid());
fclose(pidfile);
}
void rmPidfile() {
unlink("/run/fastcgi/alliance-rainbow.pid");
}
int openSocket(char *path) {
int pathlen = strlen(path);
if(pathlen + 1 > UNIX_PATH_MAX) {
fprintf(stderr, "Nom de socket trop long\n");
exit(7);
}
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, UNIX_PATH_MAX);
int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
unlink(path);
if(bind(fd, (struct sockaddr*)&addr, len) == -1) {
perror(arg0);
exit(8);
}
if(listen(fd, 20) == -1) {
perror(arg0);
exit(8);
}
chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
return fd;
}
void closeSocket(int fd, char *path) {
close(fd);
unlink(path);
}
/* ------------- Fonction de lancement ------------ */
pid_t spawn(char *path, int sock) {
pid_t pid = fork();
if(pid == -1) {
perror(arg0);
exit(9);
}
if(pid != 0) {
return pid;
}
dup2(sock, STDIN_FILENO);
execl(path, path, (char*)NULL);
perror(path);
exit(9);
}
void msg(char *msg) {
time_t tim = time(NULL);
struct tm *loc_tim = localtime(&tim);
char dat[18];
if(strftime(dat, 18, "%d/%m/%y %H:%M:%S", loc_tim) == 0) {
dat[0] = '\0';
}
printf("[%s] %s\n", dat, msg);
}
/* ------------ Gestionnaires de signal ----------- */
void init_shutdown(int sig) {
msg("Shutdown");
shutdowning = 1;
if(pidMain > 0) kill(pidMain, SIGUSR1);
if(pidAjax > 0) kill(pidAjax, SIGUSR1);
}
void restart(int sig) {
msg("Restart");
if(pidMain > 0) kill(pidMain, SIGUSR1);
if(pidAjax > 0) kill(pidAjax, SIGUSR1);
}
void enter_pause(int sig) {
msg("Pause");
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_SETMASK, &set, NULL);
if(pidMain > 0) {
kill(pidMain, SIGUSR1);
}
if(pidAjax > 0) {
kill(pidAjax, SIGUSR1);
}
sigsuspend(&set);
msg("Resume");
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
}
void resume(int sig) {
}
void register_signals() {
struct sigaction act;
sigset_t set;
sigemptyset(&set);
act.sa_mask = set;
act.sa_flags = 0;
act.sa_handler = init_shutdown;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
act.sa_handler = restart;
sigaction(SIGUSR1, &act, NULL);
act.sa_handler = enter_pause;
sigaction(SIGUSR2, &act, NULL);
act.sa_handler = resume;
sigaction(SIGCONT, &act, NULL);
}
/* ------------------------------------------------ */
int main(int argc, char** argv) {
arg0 = argv[0];
// Initialisation
drop_privileges();
daemonize();
mkPidfile();
register_signals();
fcntl(STDOUT_FILENO, F_SETFD, FD_CLOEXEC);
fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC);
// Création des sockets
int sockMain = openSocket("/run/fastcgi/alliance-rainbow.main.sock");
time_t timeMain = time(NULL);
int nbDeathsMain = 0;
int sockAjax = openSocket("/run/fastcgi/alliance-rainbow.ajax.sock");
time_t timeAjax = time(NULL);
int nbDeathsAjax = 0;
// Premier lancement
pidMain = spawn("./main.rb", sockMain);
pidAjax = spawn("./ajax.rb", sockAjax);
// Boucle principale
while(pidMain != -1 || pidAjax != -1) {
pid_t proc = wait(NULL);
time_t curTime = time(NULL);
if(proc == pidMain) {
pidMain = -1;
if(!shutdowning) {
msg("Main est mort, longue vie à Main !");
if(curTime - timeMain <= 10) {
nbDeathsMain++;
if(nbDeathsMain == 3) {
msg("Main meurt trop vite, mise en pause");
enter_pause(SIGUSR2);
}
}
else {
timeMain = curTime;
nbDeathsMain = 1;
}
pidMain = spawn("./main.rb", sockMain);
}
}
else if(proc == pidAjax) {
pidAjax = -1;
if(!shutdowning) {
msg("Ajax est mort, longue vie à Ajax !");
if(curTime - timeAjax <= 10) {
nbDeathsAjax++;
if(nbDeathsAjax == 3) {
msg("Ajax meurt trop vite, désactivation de ce worker");
continue;
}
}
else {
timeAjax = curTime;
nbDeathsAjax = 1;
}
pidAjax = spawn("./ajax.rb", sockAjax);
}
}
}
// Désinitialisation
closeSocket(sockMain, "/run/fastcgi/alliance-rainbow.main.sock");
closeSocket(sockAjax, "/run/fastcgi/alliance-rainbow.ajax.sock");
rmPidfile();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment