Show remote.c syntax highlighted
/*
* Copyright (c) 2006 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* Remote storage controller
*/
#include "libmisc/misc.h"
#include "link/link.h"
#include <libdev/status_dev.h>
#include <sys/vfs.h>
#include <emrun/emrun.h>
#include <libdev/g_signals.h>
#include <wait.h>
#include <include/remote.h>
#define MAX_CHILDREN 5
#define SSH_OPTS "ssh -o BatchMode=yes -o StrictHostKeyChecking=no "
char *host = STORAGE_SERVER_HOST;
int children_out = 0;
char *current_cmd = NULL;
buf_t *current_buf = NULL;
remote_status_t curr_status = {};
status_context_t *status_ctx = NULL;
void ignore(int sig)
{
}
void print_current(int sig)
{
elog(LOG_WARNING, "currently processing cmd '%s', got '%s'",
current_cmd, current_buf ? current_buf->buf : "*NONE*");
}
void alarm_handler(int sig)
{
elog(LOG_CRIT, "ACK!!! we got an alarm. File system b0rked?");
print_current(sig);
exit(1);
}
static
int maybe_fork(char *str)
{
if (children_out < MAX_CHILDREN) {
children_out++;
if (fork() == 0) {
signal(SIGUSR1, print_current);
alarm(100);
current_cmd = str;
current_buf = buf_new();
FILE *f = popen(str, "r");
int status = 0;
do {
char buf[4096];
status = fread(buf, 1, sizeof(buf), f);
if (status > 0) {
bufcpy(current_buf, buf, status);
}
} while (status > 0);
pclose(f);
return 1;
}
}
else {
elog(LOG_CRIT, "Max children exceeded!");
killpg(0, SIGUSR1);
}
return 0;
}
static
int remote_save_status_print(status_context_t *info, buf_t *buf)
{
bufprintf(buf, "Remote storage (node %d)\n", my_node_id);
switch (curr_status.status) {
case REMOTE_UNK:
bufprintf(buf, "Unknown"); break;
case REMOTE_NOCARD:
bufprintf(buf, "No Card"); break;
case REMOTE_NOMOUNT:
bufprintf(buf, "Not Mounted"); break;
case REMOTE_READY:
bufprintf(buf, "Mounted, %.1fM avail",
curr_status.avail/10.0);
break;
}
bufprintf(buf, "\n\n");
return STATUS_MSG_COMPLETE;
}
static
int remote_save_status_bin(status_context_t *info, buf_t *buf)
{
bufcpy(buf, &curr_status, sizeof(curr_status));
return STATUS_MSG_COMPLETE;
}
static
int remote_save_status_write(status_context_t *info, char *command, size_t buf_size)
{
parser_state_t *ps = misc_parse_init(command, MISC_PARSE_COLON_SCHEME);
int retval = EVENT_RENEW;
while (misc_parse_next_kvp(ps) >= 0) {
if (strcmp(ps->key, "umount") == 0) {
char str[256];
sprintf(str, "%s %s \"sync && umount /mnt/cf\"", SSH_OPTS, host);
if (maybe_fork(str)) {
printf_to_file(REMOTE_SAVE_CONTROL, "update");
exit(0);
}
}
else if (strcmp(ps->key, "mount") == 0) {
char str[256];
sprintf(str, "%s %s mount /mnt/cf", SSH_OPTS, host);
if (maybe_fork(str)) {
printf_to_file(REMOTE_SAVE_CONTROL, "update");
exit(0);
}
}
else if (strcmp(ps->key, "update") == 0) {
if (ps->value) {
int status,avail;
sscanf(ps->value, "%d,%d", &status, &avail);
curr_status.status = status;
curr_status.avail = avail;
g_status_dev_notify(status_ctx);
}
else {
char str[256];
sprintf(str, "%s %s df -k", SSH_OPTS, host);
if (maybe_fork(str)) {
if (current_buf == NULL) {
elog(LOG_WARNING, "no data retuned!");
exit(1);
}
/* parse the df output */
elog(LOG_DEBUG(0), "got df='%s'", current_buf->buf);
strtok(current_buf->buf, "\n");
char *line = NULL;
do {
line = strtok(NULL, "\n");
if (line) {
if (strncmp(line, "/dev/hda1", 9) == 0) {
int avail;
sscanf(line, "%*s %*d %*d %d", &avail);
curr_status.status = REMOTE_READY;
curr_status.avail = avail/100;
goto got_state;
}
}
} while (line);
char cmd[512];
sprintf(cmd, "%s %s ls /dev/hda1", SSH_OPTS, host);
int result = system(cmd);
elog(LOG_DEBUG(0), "result %d", result);
if (result == 0) {
curr_status.status = REMOTE_NOMOUNT;
}
else {
curr_status.status = REMOTE_NOCARD;
}
got_state:
printf_to_file(REMOTE_SAVE_CONTROL, "update=%d,%d",
curr_status.status, curr_status.avail);
exit(0);
}
}
}
else {
elog(LOG_WARNING, "Unrecognized command: %s", command);
}
}
misc_parse_cleanup(ps);
return retval;
}
static
int remote_child(void *data, int sig, g_signal_context_t *ev)
{
int status;
int pid = waitpid(-1, &status, WNOHANG);
if (pid > 0) {
children_out--;
elog(LOG_DEBUG(0), "child process %d completed: %d, %d remain",
pid, status, children_out);
}
return EVENT_RENEW;
}
static int remote_update(void *data, int interval, g_event_t *ev)
{
elog(LOG_DEBUG(0), "triggered update");
remote_save_status_write(NULL, "update", 6);
return EVENT_RENEW;
}
/*
* main and initialization
*/
void remote_save_shutdown(void *data)
{
elog_g(LOG_NOTICE, "Remote storage monitor shutting down");
exit(0);
}
void usage(const char *name)
{
misc_print_usage
(name,
"", "");
exit(1);
}
int main(int argc, char *argv[])
{
signal(SIGUSR1, ignore);
/* generic init */
misc_init(&argc, argv, CVSTAG);
/* required arguments */
if (misc_parse_out_switch(&argc, argv, "help", 'h'))
usage(argv[0]);
/* ok, no more args */
if (misc_args_remain(&argc, argv)) {
elog(LOG_CRIT, "Extra args.. aborting");
usage(argv[0]);
}
status_dev_opts_t s_opts = {
device: {
devname: sim_path(REMOTE_SAVE_CONTROL),
device_info: NULL
},
printable: remote_save_status_print,
binary: remote_save_status_bin,
write: remote_save_status_write
};
if (g_status_dev(&s_opts, &status_ctx) < 0) {
elog(LOG_CRIT, "Unable to register status device %s: %m",
s_opts.device.devname);
exit(1);
}
/* set up a timer to periodically check the state of the card */
g_timer_add(10000, remote_update, NULL, NULL, NULL);
/* set up child process handler */
g_signal_opts_t opts = {
signo: SIGCHLD,
callback: remote_child,
data: NULL
};
g_signal_handler(&opts, NULL);
/* set alarm handler for fs check */
signal(SIGALRM, alarm_handler);
/* connect to emrun */
emrun_opts_t emrun_opts = {
shutdown: remote_save_shutdown
};
emrun_init(&emrun_opts); /* this init should be done last */
/* run */
elog_g(LOG_INFO, "Remote Storage Monitor Starting");
g_main();
return 0;
}
See more files for this project here