/* Copyright 2009 Nathan Phillip Brink This file is a part of DistRen. DistRen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. DistRen is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with DistRen. If not, see . */ #include "libremoteio.h" #include "execio.h" #include "asprintf.h" #include #include #include /* local */ int _remoteio_ssh_open(struct remoteio *rem, struct remoteio_server *server); int _remoteio_ssh_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread); int _remoteio_ssh_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten); int _remoteio_ssh_close(struct remoteio *rem); #ifndef WINDOWS int _remoteio_sock_open(struct remoteio *rem, struct remoteio_server *server); int _remoteio_sock_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread); int _remoteio_sock_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten); int _remoteio_sock_close(struct remoteio *rem); #endif /** lookup table for different methods of remoteio: the enum remoteio_method is the index of the entry to use for that method. Regardless, a NULL terminator is required because the configuration function searches through this table for the method specified in the config file. */ struct remoteio_method_funcmap funcmap[] = { /* [REMOTEIO_METHOD_SSH] */ {&_remoteio_ssh_open, &_remoteio_ssh_read, &_remoteio_ssh_write, &_remoteio_ssh_close, "ssh"}, #ifndef WINDOWS {&_remoteio_sock_open, &_remoteio_sock_read, &_remoteio_sock_write, &_remoteio_sock_close, "unix"}, #endif {NULL, NULL, NULL, NULL, NULL} }; struct remoteio_server *remoteio_getserver(const struct remoteio_opts *opts, const char *servername); int remoteio_config(cfg_t *cfg, struct remoteio_opts *opts) { size_t numservers; size_t counter; static int haslisted_methods = 0; struct remoteio_server *aserver; opts->servers = malloc(sizeof(struct remoteio_server)); if(!opts->servers) { fprintf(stderr, "@todo cleanup!\n"); abort(); } aserver = opts->servers; numservers = cfg_size(cfg, "server"); for(counter = 0; counter < numservers; counter ++) { cfg_t *cfg_aserver; char *method; cfg_aserver = cfg_getnsec(cfg, "server", counter); if(!aserver) /*< if the malloc in the previous loop failed */ abort(); aserver->name = strdup(cfg_title(cfg_aserver)); aserver->hostname = strdup(cfg_getstr(cfg_aserver, "hostname")); aserver->username = strdup(cfg_getstr(cfg_aserver, "username")); aserver->method = REMOTEIO_METHOD_MAX; method = cfg_getstr(cfg_aserver, "method"); for(counter = 0; funcmap[counter].name; counter ++) if(strcmp(method, funcmap[counter].name) == 0) aserver->method = REMOTEIO_METHOD_SSH; if(aserver->method == REMOTEIO_METHOD_MAX) { fprintf(stderr, "No such method as %s\n", method); if(!haslisted_methods) { fprintf(stderr, "Available methods:\n"); for(counter = 0; funcmap[counter].name; counter ++) fprintf(stderr, "\t%s\n", funcmap[counter].name); haslisted_methods ++; } abort(); } if(counter < numservers - 1) { aserver->next = malloc(sizeof(struct remoteio_server)); aserver = aserver->next; } } aserver->next = NULL; return 0; } int remoteio_open(struct remoteio **remoteio, struct remoteio_opts *opts, const char *servername) { struct remoteio_server *theserver; struct remoteio *rem; int tmp; if(!opts) { fprintf(stderr, "%s:%d: no null opts!\n\tThis is a bug, please report it (after making sure it isn't already reported)\n", __FILE__, __LINE__); return 1; } theserver = remoteio_getserver(opts, servername); if(!theserver) { fprintf(stderr, "%s:%d: Could not find server named ``%s''\n", __FILE__, __LINE__, servername); return 1; } if(theserver->method >= REMOTEIO_METHOD_MAX || theserver->method < 0) { fprintf(stderr, "%s:%d: Unsupported remoteio method %d\n\tThis is a bug, probably indicating memory corruption. This is, of course, probably my fault (not your hardware's) ;-)\n", __FILE__, __LINE__, theserver->method); return 1; } rem = malloc(sizeof(struct remoteio)); if(!rem) { fprintf(stderr, "OOM\n"); return 2; } *remoteio = rem; rem->method = theserver->method; rem->opts = opts; tmp = funcmap[theserver->method].open_func(rem, theserver); if(tmp) { fprintf(stderr, "Error using method %s for server ``%s''", funcmap[theserver->method].name, servername); free(rem); *remoteio = NULL; return tmp; } return 0; } int remoteio_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread) { return funcmap[rem->method].read_func(rem, buf, len, bytesread); } int remoteio_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten) { return funcmap[rem->method].write_func(rem, buf, len, byteswritten); } int remoteio_close(struct remoteio *rem) { int rtn; rtn = funcmap[rem->method].close_func(rem); free(rem); return rtn; } struct remoteio_server *remoteio_getserver(const struct remoteio_opts *opts, const char *servername) { struct remoteio_server *aserver; for(aserver = opts->servers; aserver; aserver = aserver->next) if(!strcmp(servername, aserver->name)) return aserver; return (struct remoteio_server *)NULL; } /** different remoteio methods' implementations: */ /* SSH, via execio */ int _remoteio_ssh_open(struct remoteio *rem, struct remoteio_server *server) { char *userhost; char *sshargs[] = {rem->opts->ssh_command, NULL /* userhost */, "distrend", "-d", (char *)NULL}; int rtn; if(server->username) _distren_asprintf(&userhost, "%s@%s", server->username, server->hostname); else userhost = strdup(server->hostname); sshargs[1] = userhost; rtn = execio_open( &rem->execio, "ssh", sshargs); if(rtn) { fprintf(stderr, "error opening remoteio channel to ssh userhost ``%s''\n" , userhost); free(userhost); return 1; } free(userhost); return 0; } int _remoteio_ssh_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread) { return execio_read(rem->execio, buf, len, bytesread); } int _remoteio_ssh_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten) { return execio_write(rem->execio, buf, len, byteswritten); } int _remoteio_ssh_close(struct remoteio *rem) { int rtn; rtn = execio_close(rem->execio); if(rtn) fprintf(stderr, "%s:%d: error closing execio\n", __FILE__, __LINE__); return rtn; } #ifndef WINDOWS /* local sockets implementation (``named pipes''), unix-only */ int _remoteio_sock_open(struct remoteio *rem, struct remoteio_server *server) { return 1; } int _remoteio_sock_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread) { return 1; } int _remoteio_sock_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten) { return 1; } int _remoteio_sock_close(struct remoteio *rem) { return 1; } #endif