# # # patch "basic_io_serverlist_reader.cc" # from [a8b0c7c1f1f0e7a17921b96b458d69c4aa21500b] # to [1222bec508bf6134ef5d15165af8e0ebbde1bde3] # # patch "channel.cc" # from [52453ded4583458cee87bd5d1dcc9351e8a9a900] # to [52d8c79fb85d032b9e89cd6e5aa2413fad04f084] # # patch "server.cc" # from [c9ba01a8e9a4abf884f5fd02b803c831dd0efee1] # to [983365a52930c9f80d84d2caddeda31bab5245db] # # patch "server.hh" # from [750c094326121c1ddfc3c45f6fb9f9db43c57215] # to [3b06fa45604b1a9aea829006c630a5595e7dff96] # # patch "server_manager.cc" # from [14db3fb2467a58c5e363d956bad71385f7c6836e] # to [9966e481799456f287eb05efbad2122f80079628] # # patch "server_manager.hh" # from [9aa2f2417967bc2d7b360c320f2eec6a54aac602] # to [f388100b13bf156a491eed4985dafaf47a02d44d] # # patch "usher.cc" # from [f7c55b6b4e14aee45046b58b6990a223b3dec322] # to [562ce8fab28c2fd786800f5f5659fdbbcd3cd14b] # # patch "usher.txt" # from [c46389df6e6c49b81d83d05de68f546ccf4433cd] # to [0af49344524766ffdafa17efd7f33e5b4ecad483] # ============================================================ --- basic_io_serverlist_reader.cc a8b0c7c1f1f0e7a17921b96b458d69c4aa21500b +++ basic_io_serverlist_reader.cc 1222bec508bf6134ef5d15165af8e0ebbde1bde3 @@ -31,10 +31,14 @@ if (st.items.empty()) ok = false; else if (st.items[0].key != "server") - return get_next(); + { + return get_next(); + } ss.valid = ok; if (!ok) - return ss; + { + return ss; + } for (vector::iterator i = st.items.begin(); i != st.items.end(); ++i) { @@ -42,8 +46,7 @@ { if (i->values.empty()) { - ss.valid = false; - return ss; + return get_next(); } ss.name = i->values[0].parsed; } @@ -68,8 +71,7 @@ ss.local = false; if (i->values.empty()) { - ss.valid = false; - return ss; + return get_next(); } string str = i->values[0].parsed; unsigned int c = str.find(":"); @@ -88,8 +90,7 @@ } else { - ss.valid = false; - return ss; + return get_next(); } } return ss; @@ -101,6 +102,9 @@ if (ifs.is_open()) ifs.close(); ifs.open(filename.c_str()); + if (!ifs) + { + } vector delims; delims.push_back("server"); reader.reset(new basic_io::stanza_reader(ifs, delims)); ============================================================ --- channel.cc 52453ded4583458cee87bd5d1dcc9351e8a9a900 +++ channel.cc 52d8c79fb85d032b9e89cd6e5aa2413fad04f084 @@ -106,7 +106,7 @@ char * dat; int size; sbuf.getwrite(p, n); - make_packet(e.name, dat, size); + make_packet("!" + e.name, dat, size); if (n < size) size = n; memcpy(p, dat, size); sbuf.fixwrite(size); ============================================================ --- server.cc c9ba01a8e9a4abf884f5fd02b803c831dd0efee1 +++ server.cc 983365a52930c9f80d84d2caddeda31bab5245db @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include using boost::lexical_cast; @@ -26,7 +29,7 @@ int currport = 0; int curraddr[] = {0, 0, 0, 0}; -int fork_server(vector const & args); +int fork_server(string const &logfile, vector const & args); serverstate::serverstate(): state(unknown), num(0) {} serverstate const & serverstate::operator=(string const & s) @@ -99,6 +102,12 @@ yeskill(); } +shared_ptr +server::self() +{ + return me.lock(); +} + serverstate server::get_state() { @@ -191,6 +200,10 @@ { if (!enabled) throw errstr("This server is disabled."); + map, server_manager::serverdata>::iterator + i = manager.servers.find(self()); + string logfilename(manager.get_logdir() + "/"); + logfilename = i->second.name + ".log"; if (local && pid == -1) { // server needs to be started // we'll try 3 times, since there's a delay between our checking that @@ -205,9 +218,11 @@ for (vector::iterator j = arguments.begin(); j != arguments.end(); ++j) args.push_back(*j); - pid = fork_server(args); + pid = fork_server(logfilename, args); } } + if (pid == -1) + throw errstr("Cannot fork server."); sock s = make_outgoing(port, addr); ++connection_count; return s; @@ -252,26 +267,36 @@ } } -int fork_server(vector const & args) +int fork_server(string const &logfile, vector const & args) { int err[2]; - if (pipe(err) < 0) - return false; + if ((err[1]=open(logfile.c_str(),O_CREAT|O_APPEND|O_WRONLY,0644)) < 0) + return -1; + if ((err[0]=open(logfile.c_str(),O_RDONLY)) < 0) + { + close(err[1]); + return -1; + } + lseek(err[0], 0, SEEK_END); int pid = fork(); if (pid == -1) { close(err[0]); close(err[1]); cerr<<"Failed to fork server.\n"; - return false; + return -1; } else if (pid == 0) { close(err[0]); close(0); close(1); close(2); sock::close_all_socks(); - if (dup2(err[1], 2) < 0) { - exit(1); + if (dup2(err[1], 1) < 0) { + exit(4); } + close(err[1]); + if (dup2(1, 2) < 0) { + exit(5); + } char ** a = new char*[args.size()+1]; for (unsigned int i = 0; i < args.size(); ++i) { @@ -289,17 +314,22 @@ execvp(a[0], a); perror("execvp failed"); - exit(1); + exit(6); } else { close(err[1]); char head[256]; int got = 0; - int r = 0; + int r = 0, w = 0; bool line = false; // the first line output on the server's stderr will be either // "mtn: beginning service on : " or // "mtn: network error: bind(2) error: Address already in use" + // + // Now that reads a file instead of a pipe, we need to poll it + // until either we get our output or the server dies. This is + // because read() doesn't block on EOF. do { + usleep(10*1000); r = read(err[0], head + got, 256 - got); if (r) cerr<<"Read '"< 0 && !line && got < 256); + w = waitpid(pid, 0, WNOHANG); + } while((!w || r > 0) && !line && got < 256); head[got] = 0; if (string(head).find("beginning service") != string::npos) return pid; kill(pid, SIGKILL); - do {r = waitpid(pid, 0, 0);} while (r==-1 && errno == EINTR); + int status; + do {r = waitpid(pid, &status, 0);} while (r==-1 && errno == EINTR); return -1; } } ============================================================ --- server.hh 750c094326121c1ddfc3c45f6fb9f9db43c57215 +++ server.hh 3b06fa45604b1a9aea829006c630a5595e7dff96 @@ -8,6 +8,11 @@ #include using std::vector; +#include +using boost::shared_ptr; +#include +using boost::weak_ptr; + struct server_manager; struct serverstate @@ -33,6 +38,7 @@ int connection_count; int last_conn_time; server_manager &manager; + weak_ptr me; server(server_manager &sm); ~server(); serverstate get_state(); @@ -40,6 +46,7 @@ void disconnect(); void maybekill(); void yeskill(); + shared_ptr self(); }; #endif ============================================================ --- server_manager.cc 14db3fb2467a58c5e363d956bad71385f7c6836e +++ server_manager.cc 9966e481799456f287eb05efbad2122f80079628 @@ -23,8 +23,9 @@ } server_manager::server_manager(serverlist_reader &r) - : reader(r) + : reader(r), logdir(".") { + reload_servers(); } server_manager::prefix::prefix(string const &s) @@ -106,7 +107,9 @@ server_manager::reload_servers() { if (!reader.begin_reading()) - return; + { + return; + } serverspec ss; set all; for (map >::iterator i = by_name.begin(); @@ -124,7 +127,10 @@ preexist = true; } else - srv.reset(new server(*this)); + { + srv.reset(new server(*this)); + srv->me = srv; + } srv->local = ss.local; if (ss.local) { ============================================================ --- server_manager.hh 9aa2f2417967bc2d7b360c320f2eec6a54aac602 +++ server_manager.hh f388100b13bf156a491eed4985dafaf47a02d44d @@ -51,14 +51,18 @@ bool connections_allowed; int total_connections; serverlist_reader &reader; + string logdir; void add_replace_server(shared_ptr srv, serverdata const &dat); void delist_server(shared_ptr srv); + + friend class server; public: server_manager(serverlist_reader &r); bool get_connections_allowed() {return connections_allowed;} int get_total_connections() {return total_connections;} + string get_logdir() {return logdir;} void allow_connections(bool allow=true); string start_stop_server(string const &srv, bool start); ============================================================ --- usher.cc f7c55b6b4e14aee45046b58b6990a223b3dec322 +++ usher.cc 562ce8fab28c2fd786800f5f5659fdbbcd3cd14b @@ -105,9 +105,7 @@ int main (int argc, char **argv) { pidfile pf; - basic_io_serverlist_reader reader(conffile); - server_manager manager(reader); - administrator admin(manager, conffile); + string adminstr; { int i; for (i = 1; i < argc; ++i) { @@ -120,7 +118,7 @@ } else if (string(argv[i]) == "-m") monotone = argv[++i]; else if (string(argv[i]) == "-a") - admin.initialize(argv[++i]); + adminstr = argv[++i]; else if (string(argv[i]) == "-p") pf.initialize(argv[++i]); else @@ -132,7 +130,12 @@ exit (1); } } + basic_io_serverlist_reader reader(conffile); + server_manager manager(reader); + administrator admin(manager, conffile); admin.reload_conffile(); + if (!adminstr.empty()) + admin.initialize(adminstr); struct sigaction sa, sa_old; ============================================================ --- usher.txt c46389df6e6c49b81d83d05de68f546ccf4433cd +++ usher.txt 0af49344524766ffdafa17efd7f33e5b4ecad483 @@ -18,17 +18,17 @@ -a address and port to listen for admin commands -p a file (deleted on program exit) to record the pid of the usher in a file that looks like - userpass username password + userpass "username" "password" - server monotone - host localhost - pattern net.venge.monotone - remote 66.96.28.3:4691 + server "monotone" + host "localhost" + pattern "net.venge.monotone" + remote "66.96.28.3:4691" - server local - host 127.0.0.1 - pattern * - local -d /usr/local/src/managed/mt.db~ * + server "local" + host "127.0.0.1" + pattern "*" + local "-d" "/usr/local/src/managed/mt.db~" "*" or in general, one block of one or more lines of userpass