Subversion Repositories general

Rev

Rev 1177 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1140 dev 1
/******************************************************************
1159 dev 2
 * rebootd.
1140 dev 3
 *
1168 dev 4
 * A daemon which waits on specified UDP port for special string
1159 dev 5
 * (password) and reboots the computer.
1140 dev 6
 *
1171 dev 7
 * Run "./rebootd --help" to see options and parameters.
1140 dev 8
 *
9
 * Copyleft 2005 Anatoli Klassen
10
 *
11
 ******************************************************************/
12
 
13
#include <stdlib.h>
14
#include <stdio.h>
15
#include <string.h>
16
#include <errno.h>
1187 dev 17
#include <syslog.h>
1140 dev 18
#include <unistd.h>
1165 dev 19
#include <fcntl.h>
1144 dev 20
#include <sys/stat.h>
1140 dev 21
#include <sys/reboot.h>
22
 
1187 dev 23
#include "common.h"
24
#include "rebootd.h"
25
#include "config.h"
26
#include "signals.h"
27
#include "network.h"
1144 dev 28
 
1187 dev 29
int          daemonized        = 0; /* we are already a daemon */
30
volatile int reconfig_required = 0; /* we have to stop socket listening and reread config */
31
volatile int quit_required     = 0; /* we have to stop socket listening and exit */
1140 dev 32
 
1187 dev 33
void handle_command(const struct config *cfg, const char *cmd, const int cmd_len)		
1140 dev 34
{
1187 dev 35
	if(0 != strncmp(cmd, cfg->password, cmd_len)) return; /* wrong password */
1140 dev 36
 
1187 dev 37
	if(cfg->debug_mode) {
38
		syslog(LOG_INFO, "REBOOT, debug mode");
1140 dev 39
	}
1165 dev 40
	else {
1187 dev 41
		syslog(LOG_EMERG, "REBOOT");
42
		sleep(5);
43
		if(reboot(RB_AUTOBOOT) < 0) {
44
			syslog(LOG_ERR, "cannot reboot, %s", strerror(errno));
1164 dev 45
		}
1140 dev 46
	}
47
}
48
 
1165 dev 49
static int save_pid(const char *pid_file, const pid_t pid)
50
{
51
	int  fd;
52
	FILE *file;
53
 
54
	if(!pid_file || pid_file[0] == '\0') return RESULT_OK;
55
 
56
	unlink(pid_file);
57
 
58
	fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
59
	if(fd < 0) {
60
		syslog(LOG_ERR, "Can open PID file %s for write: %s\n", pid_file, strerror(errno));
61
		return RESULT_ERROR;
62
	}
63
 
64
	file = fdopen(fd, "w");
65
	if(!file) {
66
		syslog(LOG_ERR, "Can open PID file %s for write: %s\n", pid_file, strerror(errno));
67
		return RESULT_ERROR;
68
	}
69
 
70
	if(fprintf(file, "%d\n", pid) < 0) {
71
		syslog(LOG_ERR, "Can write PID to file %s: %s\n", pid_file, strerror(errno));
72
		return RESULT_ERROR;
73
	}
74
 
75
	if(fclose(file) != 0) {
76
		syslog(LOG_ERR, "Can not close PID file %s: %s\n", pid_file, strerror(errno));
77
		return RESULT_UNEXPECTED;
78
	}
79
 
80
	return RESULT_OK;
81
}
82
 
1156 dev 83
static int create_child(int soc)
1143 dev 84
{
85
	pid_t child;
86
 
87
	child = fork();
88
	if(child == -1) {
89
		fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
1145 dev 90
		return RESULT_UNEXPECTED; /* an unexpected error */
1143 dev 91
	}
92
	else if(child > 0) {
1156 dev 93
		if(close(soc) != 0) {
1143 dev 94
			fprintf(stderr, "Cannot close socket: %s\n", strerror(errno));
1145 dev 95
			return RESULT_UNEXPECTED; /* an unexpected error */
1143 dev 96
		}
1165 dev 97
 
1145 dev 98
		return RESULT_EXIT; /* we are the parent */
1143 dev 99
	}
100
	else {
1145 dev 101
		return RESULT_OK; /* we are the child */
1143 dev 102
	}
103
}
104
 
105
static int close_descr(int d)
106
{
107
	if(close(d) != 0) {
108
		syslog(LOG_ERR, "Cannot close descriptor %d: %s\n", d, strerror(errno));
1145 dev 109
		return RESULT_UNEXPECTED;
1143 dev 110
	}
1145 dev 111
	return RESULT_OK;
1143 dev 112
}
113
 
1187 dev 114
static void delete_pid_file(const char *pid_file)
1165 dev 115
{
1187 dev 116
	if(pid_file && pid_file[0] != '\0') {
117
		if(unlink(pid_file) != 0) {
118
			syslog(LOG_ERR, "Cannot delete PID file %s: %s\n", pid_file, strerror(errno));
1165 dev 119
		}
120
	}
121
}
122
 
1187 dev 123
static void check_return(int res, const struct config *cfg)
1169 dev 124
{
1165 dev 125
	if(daemonized && res != RESULT_OK) {
1187 dev 126
		delete_pid_file(cfg->pid_file);
1165 dev 127
		syslog(LOG_WARNING, "quit");
128
	}
129
 
130
	switch(res) {
131
		case RESULT_EXIT:       exit(EXIT_OK);         return;  /* no error but exit */
132
		case RESULT_ERROR:      exit(EXIT_USER_ERROR); return;  /* user error */
133
		case RESULT_UNEXPECTED: exit(EXIT_UNEXPECTED); return;  /* unexpected error */
134
	}
135
}
136
 
1156 dev 137
int main(int argc, const char* argv[])
1140 dev 138
{
1187 dev 139
	int           soc;
140
	int           reinit_needed;
141
	struct config cfg;
1140 dev 142
 
1143 dev 143
	/* get config */
1187 dev 144
	check_return(read_config(&cfg, argc, argv), &cfg);
1143 dev 145
 
146
	/* try to listen the port */
1187 dev 147
	if((soc = establish(&cfg)) < 0) {
148
		fprintf(stderr, "Cannot listen to port %i\n", cfg.port);
1145 dev 149
		return EXIT_USER_ERROR;
1140 dev 150
	}
151
 
1143 dev 152
	/* fork and release the console */
1187 dev 153
	check_return(create_child(soc), &cfg);
1140 dev 154
 
1143 dev 155
	/* continue as first child */
156
	if(setsid() == -1) {
157
		fprintf(stderr, "Cannot create session: %s\n", strerror(errno));
1145 dev 158
		return EXIT_UNEXPECTED;
1143 dev 159
	}
160
 
161
	/* fork the second time */
1187 dev 162
	check_return(create_child(soc), &cfg);
1165 dev 163
 
164
	/* continue as final child */
165
	if(init_signals() != RESULT_OK) return EXIT_UNEXPECTED;
166
 
167
	if(chdir("/") < 0) {
168
		fprintf(stderr, "Cannot chdir to /: %s\n", strerror(errno));
169
		return EXIT_UNEXPECTED;
1143 dev 170
	}
1165 dev 171
	umask(0);
1187 dev 172
	check_return(save_pid(cfg.pid_file, getpid()), &cfg);
1165 dev 173
	daemonized = 1;
1143 dev 174
 
1165 dev 175
	/* from now do not use console for error output */
1145 dev 176
	if(close_descr(0) != RESULT_OK) return EXIT_UNEXPECTED;
177
	if(close_descr(1) != RESULT_OK) return EXIT_UNEXPECTED;
178
	if(close_descr(2) != RESULT_OK) return EXIT_UNEXPECTED;
1143 dev 179
 
1165 dev 180
	for(;;) {
1187 dev 181
		syslog(LOG_INFO, "listen on %d", cfg.port);
182
		listen_socket(&cfg, soc);
1143 dev 183
 
1169 dev 184
		if(quit_required) {
185
			break;
186
		}
187
		else if(reconfig_required) {
188
			reconfig_required = 0;
1187 dev 189
			check_return(reread_config(&cfg, &reinit_needed), &cfg);
1165 dev 190
			if(reinit_needed) {
191
				close(soc);
192
 
1187 dev 193
				if((soc = establish(&cfg)) < 0) {
194
					syslog(LOG_ERR, "Cannot listen to port %i\n", cfg.port);
195
					check_return(RESULT_ERROR, &cfg);
1165 dev 196
				}
197
			}
198
		}
199
	}
200
 
1187 dev 201
	delete_pid_file(cfg.pid_file);
1169 dev 202
	return EXIT_OK;
1140 dev 203
}
204