Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1163 → Rev 1164

/rebootd/trunk/rebootd.c
4,11 → 4,12
* A daemon which waits on specified TCP port for special string
* (password) and reboots the computer.
*
* Command line: rebootd [--port PORT] [--config CONFIG_FILE]
* Command line: rebootd [--version] [--help] [--interface IP] [--port PORT] [--config CONFIG_FILE]
* Defaults are port 19 and config /etc/rebootd.conf.
*
* Config file looks like:
* --------------------------
* interface=192.168.0.1
* port=19
* password="some password"
* --------------------------
67,17 → 68,21
#define PARAM_HELP_2 "--help"
#define PARAM_VERSION_1 "-v"
#define PARAM_VERSION_2 "--version"
#define PARAM_INTERFACE_1 "-i"
#define PARAM_INTERFACE_2 "--interface"
#define PARAM_PORT_1 "-p"
#define PARAM_PORT_2 "--port"
#define PARAM_CONFIG_1 "-c"
#define PARAM_CONFIG_2 "--config"
#define CONFIG_INTERFACE "interface"
#define CONFIG_PORT "port"
#define CONFIG_PASSWORD "password"
 
struct config {
char config_file[FILENAME_MAX];
ushort port;
char password[MAX_CONFIG_LINE];
char config_file[FILENAME_MAX];
struct in_addr interface;
ushort port;
char password[MAX_CONFIG_LINE];
};
 
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[]);
89,7 → 94,7
return (a < b) ? a : b;
}
 
static int establish(ushort port)
static int establish(const struct config *cfg)
{
int s;
struct sockaddr_in sa;
97,8 → 102,8
memset(&sa, 0, sizeof(struct sockaddr_in));
 
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(cfg->port);
sa.sin_addr.s_addr = (cfg->interface.s_addr ? cfg->interface.s_addr : INADDR_ANY);
 
if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
169,12 → 174,12
print_version();
printf("\nA daemon which waits on specified TCP port for special");
printf(" string (password) and reboots the computer.\n\n");
printf("Usage: %s [--port PORT] [--config CONFIG_FILE]\n", argv[0]);
printf("Usage: %s [--interface IP] [--port PORT] [--config CONFIG_FILE]\n", argv[0]);
printf(" or: %s --version\n", argv[0]);
printf(" or: %s --help\n\n", argv[0]);
printf("Defaults are port 19 and config /etc/rebootd.conf.\n\n");
printf("Config file looks like:\n--------------------------\n");
printf("port=19\npassword=\"some password\"\n--------------------------\n\n");
printf("interface=192.168.0.1\nport=19\npassword=\"some password\"\n--------------------------\n\n");
printf("Then run from any other host:\necho -n \"some password\" | nc host_to_rebot 19\n");
}
 
206,6 → 211,7
struct config cmd_cfg;
struct config file_cfg;
 
memset(cfg, 0, sizeof(struct config));
res_cmd_line = parse_cmd_line(&cmd_cfg, argc, argv);
if(res_cmd_line != RESULT_OK) return res_cmd_line;
 
221,6 → 227,11
/* save parsed values to general config */
strncpy(cfg->config_file, cmd_cfg.config_file, sizeof(cfg->config_file));
 
if(cmd_cfg.interface.s_addr)
cfg->interface = cmd_cfg.interface;
else if(file_cfg.interface.s_addr)
cfg->interface = file_cfg.interface;
 
if(cmd_cfg.port > 0)
cfg->port = cmd_cfg.port;
else if(file_cfg.port > 0)
233,6 → 244,28
return RESULT_OK;
}
 
static int parse_interface(const char *s, char **end, struct in_addr *ip)
{
char buf[MAX_CONFIG_LINE];
int count;
const char *c;
 
c = s;
count = 0;
while(c[0] != '\0' && !isspace(c[0])) c++, count++;
if(count > MAX_CONFIG_LINE) return RESULT_ERROR;
strncpy(buf, s, count);
buf[count] = '\0';
c++;
 
if(end) *end = (char *)c;
 
if(inet_aton(buf, ip) == 1)
return RESULT_OK;
else
return RESULT_ERROR;
}
 
static int parse_cmd_line(struct config *cfg, int argc, const char* argv[])
{
char *end;
242,8 → 275,21
memset(cfg, 0, sizeof(struct config));
 
for(i = 1; i < argc; i++) {
if(0 == strcmp(argv[i], PARAM_PORT_1) || 0 == strcmp(argv[i], PARAM_PORT_2)) {
if(cfg->port > 0)
if(0 == strcmp(argv[i], PARAM_INTERFACE_1) || 0 == strcmp(argv[i], PARAM_INTERFACE_2)) {
if(cfg->interface.s_addr)
return print_cmd_error(argc, argv, "Interface is already set", NULL);
 
if(++i < argc) {
if(parse_interface(argv[i], (char **)NULL, &cfg->interface) != RESULT_OK)
return print_cmd_error(argc, argv,
"Cannot parse interface", argv[i]);
}
else {
return print_cmd_error(argc, argv, "Interface expected", NULL);
}
}
else if(0 == strcmp(argv[i], PARAM_PORT_1) || 0 == strcmp(argv[i], PARAM_PORT_2)) {
if(cfg->port)
return print_cmd_error(argc, argv, "Port is already set", NULL);
 
if(++i < argc) {
287,7 → 333,59
return RESULT_OK;
}
 
static int validate_equal_sign(const char *config_name, const int count, const char *line,
uint name_len, char **subline)
{
const char *c;
 
c = line + name_len - 1;
if('=' != c[0] && !isspace(c[0]))
return print_config_error(config_name, count, "Unknown config parameter", line);
while(c[0] != '\0' && isspace(c[0])) c++;
if('=' != c[0])
return print_config_error(config_name, count, "Equal sign expected", NULL);
c++;
 
if(subline) *subline = (char *)c;
 
return RESULT_OK;
}
 
static int validate_eol(const char *config_name, const int count, const char *line)
{
while(line[0] != '\0' && isspace(line[0])) line++;
if('\0' != line[0] && '#' != line[0])
return print_config_error(config_name, count, "End of line expected", NULL);
 
return RESULT_OK;
}
 
static int extract_quoted(const char *config_name, const int count, char **subline, char *string, uint len)
{
uint cur_len;
 
while(*subline[0] != '\0' && isspace(*subline[0])) (*subline)++;
if('"' != *subline[0])
return print_config_error(config_name, count, "Open quot expected", NULL);
(*subline)++;
 
cur_len = 0;
while(cur_len < len && *subline[0] != '\0' && *subline[0] != '"')
{
string[0] = *subline[0];
string++;
(*subline)++;
cur_len++;
}
 
string[0] = '\0';
if('"' != *subline[0])
return print_config_error(config_name, count, "Close quot expected", NULL);
(*subline)++;
 
return RESULT_OK;
}
 
static int parse_config_file(struct config *cfg, const char *config_name)
{
FILE *config_file;
294,11 → 392,10
char buf[MAX_CONFIG_LINE];
char *line;
char *subline;
char *cur;
int count;
uint len;
uint password_len;
long port;
int res;
 
memset(cfg, 0, sizeof(struct config));
 
327,59 → 424,44
if('#' == line[0]) { /* skip comment lines */
continue;
}
else if(strncmp(line, CONFIG_INTERFACE, min(sizeof(CONFIG_INTERFACE) - 1, len)) == 0) {
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_INTERFACE), &subline)) != RESULT_OK) return res;
 
if(parse_interface(subline, &subline, &cfg->interface) != RESULT_OK)
return print_config_error(config_name, count,
"Cannot parse interface", NULL);
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else if(strncmp(line, CONFIG_PORT, min(sizeof(CONFIG_PORT) - 1, len)) == 0) {
subline = line + sizeof(CONFIG_PORT) - 1;
if('=' != subline[0] && !isspace(subline[0]))
return print_config_error(config_name, count, "Unknown config parameter", line);
while(subline[0] != '\0' && isspace(subline[0])) subline++;
if('=' != subline[0])
return print_config_error(config_name, count, "Equal sign expected", NULL);
subline++;
if((res = validate_equal_sign(config_name, count, line, sizeof(CONFIG_PORT),
&subline)) != RESULT_OK) return res;
 
port = strtol(subline, &subline, 10);
if(port < PORT_MIN || port > PORT_MAX)
return print_config_error(config_name, count,
"Port number must be integer between 1 and 65535", NULL);
while(subline[0] != '\0' && isspace(subline[0])) subline++;
if('\0' != subline[0] && '#' != subline[0])
return print_config_error(config_name, count, "End of line expected", NULL);
 
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
cfg->port = (ushort)port;
}
else if(strncmp(line, CONFIG_PASSWORD, min(sizeof(CONFIG_PASSWORD) - 1, len)) == 0) {
subline = line + sizeof(CONFIG_PASSWORD) - 1;
if('=' != subline[0] && !isspace(subline[0]))
return print_config_error(config_name, count, "Unknown config parameter", line);
while(subline[0] != '\0' && isspace(subline[0])) subline++;
if('=' != subline[0])
return print_config_error(config_name, count, "Equal sign expected", NULL);
subline++;
while(subline[0] != '\0' && isspace(subline[0])) subline++;
if('"' != subline[0])
return print_config_error(config_name, count, "Open quot expected", NULL);
subline++;
if((res = validate_equal_sign(config_name, count, line,
sizeof(CONFIG_PASSWORD), &subline)) != RESULT_OK) return res;
 
cur = cfg->password;
password_len = 0;
while(password_len < sizeof(cfg->password) - 1
&& subline[0] != '\0' && subline[0] != '"')
{
cur[0] = subline[0];
cur++;
subline++;
password_len++;
}
if((res = extract_quoted(config_name, count, &subline,
cfg->password, sizeof(cfg->password))) != RESULT_OK) return res;
 
cur[0] = '\0';
if('"' != subline[0])
return print_config_error(config_name, count, "Close quot expected", NULL);
subline++;
while(subline[0] != '\0' && isspace(subline[0])) subline++;
if('\0' != subline[0] && '#' != subline[0])
return print_config_error(config_name, count, "End of line expected", NULL);
if((res = validate_eol(config_name, count, subline)) != RESULT_OK) return res;
}
else {
return print_config_error(config_name, count, "Unknown config parameter", line);
}
}
if(ferror(config_file)) {
fprintf(stderr, "Config file %s reading failed\n", config_name);
}
 
if(fclose(config_file) != 0) {
fprintf(stderr, "Can not close config file %s: %s\n", config_name, strerror(errno));
446,7 → 528,7
}
 
/* try to listen the port */
if((soc = establish(cfg.port)) < 0) {
if((soc = establish(&cfg)) < 0) {
fprintf(stderr, "Cannot listen to port %i\n", cfg.port);
return EXIT_USER_ERROR;
}
/rebootd/trunk/rebootd.conf
1,5 → 1,6
# rebootd configuration
 
interface=127.0.0.1
port=2019
password="password"
password="some password"