⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shutdown.c

📁 watchdog source watchdog source
💻 C
字号:
/* $Header: /cvsroot/watchdog/watchdog/src/shutdown.c,v 1.3 2007/02/12 09:42:07 meskes Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <mntent.h>#include <netdb.h>#include <paths.h>#include <setjmp.h>#include <signal.h>#include <string.h>#include <stdlib.h>#include <utmp.h>#include <sys/mman.h>#include <sys/param.h>#include <sys/stat.h>#include "watch_err.h"#include "extern.h"#if defined __GLIBC__#include "ext2_mnt.h"#include <sys/quota.h>#include <sys/swap.h>#include <sys/reboot.h>#else				/* __GLIBC__ */#include <linux/quota.h>#endif				/* __GLIBC__ */#include <unistd.h>#if USE_SYSLOG#include <syslog.h>#endif				/* USE_SYSLOG */#ifndef NSIG#define NSIG _NSIG#endifextern void umount_all(void *);extern int ifdown(void);#if 0extern int mount_one(char *, char *, char *, char *, int, int);static struct mntent rootfs;#endif#if defined(_POSIX_MEMLOCK)extern int mlocked, realtime;#endif /* _POSIX_MEMLOCK */jmp_buf ret2dog;/* Info about a process. */typedef struct _proc_ {    pid_t pid;			/* Process ID.                    */    int sid;			/* Session ID.                    */    struct _proc_ *next;	/* Pointer to next struct.        */} PROC;/* write a log entry on exit */static void log_end(){#if USE_SYSLOG    /* Log the closing message */    syslog(LOG_INFO, "stopping daemon (%d.%d)", MAJOR_VERSION, MINOR_VERSION);    closelog();    sleep(5);			/* make sure log is written */#endif				/* USE_SYSLOG */    return;}/* close the device and check for error */static void close_all(){    if (watchdog != -1) {        if ( write(watchdog, "V", 1) < 0 ) {		int err = errno;#if USE_SYSLOG		syslog(LOG_ERR, "write watchdog device gave error %d = '%m'!", err);#else				/* USE_SYSLOG */		perror(progname);#endif				/* USE_SYSLOG */	}        if (close(watchdog) == -1) {#if USE_SYSLOG            syslog(LOG_ALERT, "cannot close %s (errno = %d)", devname, errno);#else				/* USE_SYSLOG */            perror(progname);#endif				/* USE_SYSLOG */        }    }        if (load != -1 && close(load) == -1) {#if USE_SYSLOG	syslog(LOG_ALERT, "cannot close /proc/loadavg (errno = %d)", errno);#else				/* USE_SYSLOG */	perror(progname);#endif				/* USE_SYSLOG */    }        if (mem != -1 && close(mem) == -1) {#if USE_SYSLOG	syslog(LOG_ALERT, "cannot close /proc/meminfo (errno = %d)", errno);#else				/* USE_SYSLOG */	perror(progname);#endif				/* USE_SYSLOG */    }        if (temp != -1 && close(temp) == -1) {#if USE_SYSLOG	syslog(LOG_ALERT, "cannot close /dev/temperature (errno = %d)", errno);#else				/* USE_SYSLOG */	perror(progname);#endif				/* USE_SYSLOG */    }    if (hb != NULL && fclose(hb) == -1) {#if USE_SYSLOG	syslog(LOG_ALERT, "cannot close %s (errno = %d)", heartbeat, errno);#else				/* USE_SYSLOG */	perror(progname);#endif				/* USE_SYSLOG */    }}/* on exit we close the device and log that we stop */void terminate(int arg){#if defined(_POSIX_MEMLOCK)    if (realtime == TRUE && mlocked == TRUE)    {	/* unlock all locked pages */	if (munlockall() != 0) {#if USE_SYSLOG		syslog(LOG_ERR, "cannot unlock realtime memory (errno = %d)", errno);#else				/* USE_SYSLOG */		perror(progname);#endif				/* USE_SYSLOG */	}    }#endif		/* _POSIX_MEMLOCK */    close_all();    log_end();    if (timestamps != NULL)	    free(timestamps);    exit(0);}/* panic: we're still alive but shouldn't */static void panic(void){    /* if we are still alive, we just exit */    close_all();    fprintf(stderr, "WATCHDOG PANIC: Still alive after sleeping %d seconds!\n", 4 * TIMER_MARGIN);#if USE_SYSLOG    openlog(progname, LOG_PID, LOG_DAEMON);    syslog(LOG_ALERT, "still alive after sleeping %d seconds", 4 * TIMER_MARGIN);    closelog();#endif    exit(1);}static void mnt_off(){    FILE *fp;    struct mntent *mnt;    fp = setmntent(MNTTAB, "r");    while ((mnt = getmntent(fp)) != (struct mntent *) 0) {	/* First check if swap */	if (!strcmp(mnt->mnt_type, MNTTYPE_SWAP))	    if (swapoff(mnt->mnt_fsname) < 0)		perror(mnt->mnt_fsname);	/* quota only if mounted at boot time && filesytem=ext2 */	if (hasmntopt(mnt, MNTOPT_NOAUTO) || strcmp(mnt->mnt_type, MNTTYPE_EXT2))	    continue;	/* group quota? */	if (hasmntopt(mnt, MNTOPT_GRPQUOTA))	    if (quotactl(QCMD(Q_QUOTAOFF, GRPQUOTA), mnt->mnt_fsname, 0, (caddr_t) 0) < 0)		perror(mnt->mnt_fsname);	/* user quota */	if (hasmntopt(mnt, MNTOPT_USRQUOTA))	    if (quotactl(QCMD(Q_QUOTAOFF, USRQUOTA), mnt->mnt_fsname, 0, (caddr_t) 0) < 0)		perror(mnt->mnt_fsname);#if 0	/* not needed anymore */	/* while we're at it we add the remount option */	if (strcmp(mnt->mnt_dir, "/") == 0) {		/* save entry if root partition */		rootfs.mnt_freq = mnt->mnt_freq;		rootfs.mnt_passno = mnt->mnt_passno;		rootfs.mnt_fsname = strdup(mnt->mnt_fsname);		rootfs.mnt_dir = strdup(mnt->mnt_dir);		rootfs.mnt_type = strdup(mnt->mnt_type);		/* did we get enough memory? */		if (rootfs.mnt_fsname == NULL || rootfs.mnt_dir == NULL || rootfs.mnt_type == NULL) {#if USE_SYSLOG		    syslog(LOG_ERR, "out of memory");#else				/* USE_SYSLOG */		    fprintf(stderr, "%s: out of memory\n", progname);#endif		}		if ((rootfs.mnt_opts = malloc(strlen(mnt->mnt_opts) + strlen("remount,ro") + 2)) == NULL) {#if USE_SYSLOG			syslog(LOG_ERR, "out of memory");#else				/* USE_SYSLOG */			fprintf(stderr, "%s: out of memory\n", progname);#endif		} else			sprintf(rootfs.mnt_opts, "%s,remount,ro", mnt->mnt_opts);	}#endif    }    endmntent(fp);}/* Parts of the following two functions are taken from Miquel van *//* Smoorenburg's killall5 program. */static PROC *plist;/* get a list of all processes */static int readproc(){    DIR *dir;    struct dirent *d;    pid_t act_pid;    PROC *p;    /* Open the /proc directory. */    if ((dir = opendir("/proc")) == NULL) {#if USE_SYSLOG	syslog(LOG_ERR, "cannot opendir /proc");#else				/* USE_SYSLOG */	perror(progname);#endif	return (-1);    }    plist = NULL;    /* Walk through the directory. */    while ((d = readdir(dir)) != NULL) {	/* See if this is a process */	if ((act_pid = atoi(d->d_name)) == 0)	    continue;	/* Get a PROC struct . */	if ((p = (PROC *) calloc(1, sizeof(PROC))) == NULL) {#if USE_SYSLOG	    syslog(LOG_ERR, "out of memory");#else				/* USE_SYSLOG */	    fprintf(stderr, "%s: out of memory\n", progname);#endif	    return (-1);	}	p->sid = getsid(act_pid);	p->pid = act_pid;	/* Link it into the list. */	p->next = plist;	plist = p;    }    closedir(dir);    /* Done. */    return (0);}static void killall5(int sig){    PROC *p;    int sid = -1;    /*     *    Ignoring SIGKILL and SIGSTOP do not make sense, but     *    someday kill(-1, sig) might kill ourself if we don't     *    do this. This certainly is a valid concern for SIGTERM-     *    Linux 2.1 might send the calling process the signal too.     */    /* Since we ignore all signals, we don't have to worry here. MM */    /* Now stop all processes. */    kill(-1, SIGSTOP);    /* Find out our own 'sid'. */    if (readproc() < 0) {	kill(-1, SIGCONT);	return;    }    for (p = plist; p; p = p->next)	if (p->pid == pid) {	    sid = p->sid;	    break;	}    /* Now kill all processes except our session. */    for (p = plist; p; p = p->next)	if (p->pid != pid && p->sid != sid)	    kill(p->pid, sig);    /* And let them continue. */    kill(-1, SIGCONT);}/* shut down the system */void do_shutdown(int errorcode){    int i = 0, fd;    char *seedbck = RANDOM_SEED;    /* soft-boot the system */    /* first close the open files */    close_all();    /* if we will halt the system we should try to tell a sysadmin */    if (admin != NULL) {	/* send mail to the system admin */	FILE *ph;	char exe[128];	/* only can send an email if sendmail binary exists so make shell check	 * that first, or else we will get a broken pipe in pclose */	sprintf(exe, "[ -x %s ] && %s -i %s", PATH_SENDMAIL, PATH_SENDMAIL, admin);	ph = popen(exe, "w");	if (ph == NULL) {#if USE_SYSLOG	    syslog(LOG_ERR, "cannot start %s (errno = %d)", PATH_SENDMAIL, errno);#endif				/* USE_SYSLOG */	} else {	    char myname[MAXHOSTNAMELEN + 1];	    struct hostent *hp;	    /* get my name */	    gethostname(myname, sizeof(myname));	    fprintf(ph, "To: %s\n", admin);	    if (ferror(ph) != 0) {#if USE_SYSLOG		syslog(LOG_ERR, "cannot send mail (errno = %d)", errno);#endif				/* USE_SYSLOG */	    }	    /* if possible use the full name including domain */	    if ((hp = gethostbyname(myname)) != NULL)		fprintf(ph, "Subject: %s is going down!\n\n", hp->h_name);	    else		fprintf(ph, "Subject: %s is going down!\n\n", myname);	    if (ferror(ph) != 0) {#if USE_SYSLOG		syslog(LOG_ERR, "cannot send mail (errno = %d)", errno);#endif				/* USE_SYSLOG */	    }	    if (errorcode == ETOOHOT)		fprintf(ph, "Message from watchdog:\nIt is too hot to keep on working. The system will be halted!\n");	    else	    	fprintf(ph, "Message from watchdog:\nThe system will be rebooted because of error %d!\n", errorcode);	    if (ferror(ph) != 0) {#if USE_SYSLOG		syslog(LOG_ERR, "cannot send mail (errno = %d)", errno);#endif				/* USE_SYSLOG */	    }	    if (pclose(ph) == -1) {#if USE_SYSLOG		syslog(LOG_ERR, "cannot finish mail (errno = %d)", errno);#endif				/* USE_SYSLOG */	    }	    /* finally give the system a little bit of time to deliver */	}    }#if USE_SYSLOG    /* now tell syslog what's happening */    syslog(LOG_ALERT, "shutting down the system because of error %d", errorcode);    closelog();#endif				/* USE_SYSLOG */    sleep(10);			/* make sure log is written and mail is send */    /* We cannot start shutdown, since init might not be able to fork. */    /* That would stop the reboot process. So we try rebooting the system */    /* ourselves. Note, that it is very likely we cannot start any rc */    /* script either, so we do it all here. */    /* Start with closing the files. */    for (i = 0; i < 3; i++)	if (!isatty(i))	    close(i);    for (i = 3; i < 20; i++)	close(i);    close(255);    /* Ignore all signals. */    for (i = 1; i < NSIG; i++)	signal(i, SIG_IGN);    /* Stop init; it is insensitive to the signals sent by the kernel. */    kill(1, SIGTSTP);    /* Kill all processes. */    (void) killall5(SIGTERM);    sleep(5);    (void) killall5(SIGKILL);    /* Record the fact that we're going down */    if ((fd = open(_PATH_WTMP, O_WRONLY | O_APPEND)) >= 0) {	time_t t;	struct utmp wtmp;	time(&t);	strcpy(wtmp.ut_user, "shutdown");	strcpy(wtmp.ut_line, "~");	strcpy(wtmp.ut_id, "~~");	wtmp.ut_pid = 0;	wtmp.ut_type = RUN_LVL;	wtmp.ut_time = t;	write(fd, (char *) &wtmp, sizeof(wtmp));	close(fd);    }        /* save the random seed if a save location exists */    /* don't worry about error messages, we react here anyway */    if (strlen(seedbck) != 0) {	int fd_seed;	if ((fd_seed = open("/dev/urandom", O_RDONLY)) >= 0) {	    int fd_bck;	    if ((fd_bck = creat(seedbck, S_IRUSR | S_IWUSR)) >= 0) {		char buf[512];		if (read(fd_seed, buf, 512) == 512)		    write(fd_bck, buf, 512);		close(fd_bck);	    }	    close(fd_seed);	}    }        /* Turn off accounting */    if (acct(NULL) < 0)	perror(progname);    /* Turn off quota and swap */    mnt_off();    /* umount all partitions */    if (setjmp(ret2dog) == 0)	umount_all(NULL);#if 0    /* with the more recent version of mount code, this is not needed anymore */    /* remount / read-only */    if (setjmp(ret2dog) == 0)	mount_one(rootfs.mnt_fsname, rootfs.mnt_dir, rootfs.mnt_type,		  rootfs.mnt_opts, rootfs.mnt_freq, rootfs.mnt_passno);#endif    /* shut down interfaces (also taken from sysvinit source */    ifdown();    /* finally reboot */    if (errorcode != ETOOHOT) {#ifdef __GLIBC__	reboot(RB_AUTOBOOT);#else				/* __GLIBC__ */	reboot(0xfee1dead, 672274793, 0x01234567);#endif				/* __GLIBC__ */    } else {	/* rebooting makes no sense if it's too hot */	/* Turn on hard reboot, CTRL-ALT-DEL will reboot now */#ifdef __GLIBC__	reboot(RB_ENABLE_CAD);#else				/* __GLIBC__ */	reboot(0xfee1dead, 672274793, 0x89abcdef);#endif				/* __GLIBC__ */	/* And perform the `halt' system call. */#ifdef __GLIBC__	reboot(RB_HALT_SYSTEM);#else				/* __GLIBC__ */	reboot(0xfee1dead, 672274793, 0xcdef0123);#endif    }    /* okay we should never reach this point, */    /* but if we do we will cause the hard reset */    /* open the device again */    /* don't check for error, it won't help anyway here */    if (devname != NULL) {	open(devname, O_WRONLY);	sleep(TIMER_MARGIN * 4);    }    /* unbelievable: we're still alive */    panic();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -