static bool check_tempdir(bool do_mod) { mkdir_p(tempdir); if (!can_stat(tempdir)) return 0; if (do_mod && fixmod(tempdir)) return 0; /* test tempdir: it's vital */ Tempfile *testdir = new Tempfile("test"); /* There was an error creating a file in this directory, return to move on in list of dirs */ if (!testdir || testdir->error) { if (testdir) delete testdir; return 0; } fprintf(testdir->f, "\n"); int result = fflush(testdir->f); delete testdir; if (result) { sdprintf("%s: %s", tempdir, strerror(errno)); return 0; } return 1; }
char *move_bin(const char *ipath, const char *file, bool run) { char *path = strdup(ipath); expand_tilde(&path); /* move the binary to the correct place */ static char newbin[DIRMAX] = ""; char real[DIRMAX] = ""; simple_snprintf(newbin, sizeof newbin, "%s%s%s", path, path[strlen(path) - 1] == '/' ? "" : "/", file); ContextNote(STR("realpath()")); realpath(binname, real); /* get the realpath of binname */ ContextNote(STR("realpath(): Success")); /* running from wrong dir, or wrong bin name.. lets try to fix that :) */ sdprintf(STR("binname: %s"), binname); sdprintf(STR("newbin: %s"), newbin); sdprintf(STR("real: %s"), real); if (strcmp(binname, newbin) && strcmp(newbin, real)) { /* if wrong path and new path != current */ bool ok = 1; sdprintf(STR("wrong dir, is: %s :: %s"), binname, newbin); unlink(newbin); if (copyfile(binname, newbin)) ok = 0; if (ok && !can_stat(newbin)) { unlink(newbin); ok = 0; } if (ok && fixmod(newbin)) { unlink(newbin); ok = 0; } if (ok) { sdprintf(STR("Binary successfully moved to: %s"), newbin); unlink(binname); if (run) { simple_snprintf(newbin, sizeof newbin, "%s%s%s", path, path[strlen(path) - 1] == '/' ? "" : "/", shell_escape(file)); system(newbin); sdprintf(STR("exiting to let new binary run...")); exit(0); } } else { if (run) werr(ERR_WRONGBINDIR); sdprintf(STR("Binary move failed to: %s"), newbin); return binname; } } return newbin; }
int updatebin(int idx, char *par, int secs) { if (!par || !par[0]) { logidx(idx, "Not enough parameters."); return 1; } size_t path_siz = strlen(binname) + strlen(par) + 2; char *path = (char *) my_calloc(1, path_siz); char *newbin = NULL, buf[DIRMAX] = ""; const char* argv[5]; int i; strlcpy(path, binname, path_siz); newbin = strrchr(path, '/'); if (!newbin) { free(path); logidx(idx, STR("Don't know current binary name")); return 1; } newbin++; if (strchr(par, '/')) { *newbin = 0; logidx(idx, STR("New binary must be in %s and name must be specified without path information"), path); free(path); return 1; } strcpy(newbin, par); if (!strcmp(path, binname)) { free(path); logidx(idx, STR("Can't update with the current binary")); return 1; } if (!can_stat(path)) { logidx(idx, STR("%s can't be accessed"), path); free(path); return 1; } if (fixmod(path)) { logidx(idx, STR("Can't set mode 0600 on %s"), path); free(path); return 1; } /* Check if the new binary is compatible */ int initialized_code = check_bin_initialized(path); if (initialized_code == 2) { logidx(idx, STR("New binary is corrupted or the wrong architecture/operating system.")); free(path); return 1; } else if (initialized_code == 1 && !check_bin_compat(path)) { logidx(idx, STR("New binary must be initialized as pack structure has been changed in new version.")); free(path); return 1; } /* make a backup just in case. */ simple_snprintf(buf, sizeof(buf), STR("%s/.bin.old"), conf.datadir); copyfile(binname, buf); write_settings(path, -1, 0, initialized_code ? 0 : 1); /* re-write the binary with our packdata */ Tempfile *conffile = new Tempfile("conf"); if (writeconf(NULL, conffile->fd, CONF_ENC)) { logidx(idx, STR("Failed to write temporary config file for update.")); delete conffile; return 1; } /* The binary should return '2' when ran with -2, if not it's probably corrupt. */ putlog(LOG_DEBUG, "*", STR("Running for update binary test: %s -2"), path); argv[0] = path; argv[1] = "-2"; argv[2] = 0; i = simple_exec(argv); if (i == -1 || WEXITSTATUS(i) != 2) { logidx(idx, STR("Couldn't restart new binary (error %d)"), i); delete conffile; return i; } /* now to send our config to the new binary */ putlog(LOG_DEBUG, "*", STR("Running for update conf: %s -4 %s"), path, conffile->file); argv[0] = path; argv[1] = "-4"; argv[2] = conffile->file; argv[3] = 0; i = simple_exec(argv); delete conffile; if (i == -1 || WEXITSTATUS(i) != 6) { /* 6 for successfull config read/write */ logidx(idx, STR("Couldn't pass config to new binary (error %d)"), i); return i; } if (movefile(path, binname)) { logidx(idx, STR("Can't rename %s to %s"), path, binname); free(path); return 1; } if (updating == UPDATE_EXIT) { /* dont restart/kill/spawn bots, just die ! */ printf(STR("* Moved binary to: %s\n"), binname); fatal(STR("Binary updated."), 0); } if (updating == UPDATE_AUTO) { /* Make all other bots do a soft restart */ conf_checkpids(conf.bots); conf_killbot(conf.bots, NULL, NULL, SIGHUP); if (conf.bot->pid) kill(conf.bot->pid, SIGHUP); exit(0); } if (!conf.bot->hub && secs > 0) { /* Make all other bots do a soft restart */ conf_checkpids(conf.bots); conf_killbot(conf.bots, NULL, NULL, SIGHUP); /* invoked with -u */ if (updating == UPDATE_AUTO) { if (conf.bot->pid) kill(conf.bot->pid, SIGHUP); exit(0); } /* this odd statement makes it so specifying 1 sec will restart other bots running * and then just restart with no delay */ updating = UPDATE_AUTO; if (secs > 1) { egg_timeval_t howlong; howlong.sec = secs; howlong.usec = 0; timer_create_complex(&howlong, STR("restarting for update"), (Function) restart, (void *) (long) idx, 0); } else restart(idx); return 0; } else restart(idx); /* no timer */ /* this should never be reached */ return 2; }
void restart(int idx) { const char *reason = updating ? STR("Updating...") : STR("Restarting..."); Tempfile *socks = new Tempfile("socks"); int fd = 0; sdprintf("%s", reason); if (tands > 0) { botnet_send_chat(-1, conf.bot->nick, (char *) reason); botnet_send_bye(reason); } /* kill all connections except STDOUT/server */ for (fd = 0; fd < dcc_total; fd++) { if (dcc[fd].type && dcc[fd].type != &SERVER_SOCKET && dcc[fd].sock != STDOUT) { if (dcc[fd].sock >= 0) killsock(dcc[fd].sock); lostdcc(fd); } } const char salt1[] = SALT1; EncryptedStream stream(salt1); /* write out all leftover dcc[] entries */ for (fd = 0; fd < dcc_total; fd++) if (dcc[fd].type && dcc[fd].sock != STDOUT) dcc_write(stream, fd); /* write out all leftover socklist[] entries */ for (fd = 0; fd < MAXSOCKS; fd++) if (socklist[fd].sock != STDOUT) sock_write(stream, fd); if (server_online) { if (botname[0]) stream << bd::String::printf(STR("+botname %s\n"), botname); if (rolls) stream << bd::String::printf(STR("+rolls %d\n"), rolls); if (altnick_char) stream << bd::String::printf(STR("+altnick_char %c\n"), altnick_char); if (burst) stream << bd::String::printf(STR("+burst %d\n"), burst); if (flood_count) stream << bd::String::printf(STR("+flood_count %d\n"), flood_count); if (my_cookie_counter) stream << bd::String::printf(STR("+my_cookie_counter %lu\n"), my_cookie_counter); stream << bd::String::printf(STR("+server_online %li\n"), (long)server_online); } stream << bd::String::printf(STR("+online_since %li\n"), (long)online_since); if (floodless) stream << bd::String::printf(STR("+server_floodless %d\n"), floodless); if (in_deaf) stream << bd::String::printf(STR("+in_deaf\n")); if (in_callerid) stream << bd::String::printf(STR("+in_callerid\n")); for (struct chanset_t *chan = chanset; chan; chan = chan->next) if (shouldjoin(chan) && (channel_active(chan) || channel_pending(chan))) stream << bd::String::printf(STR("+chan %s\n"), chan->dname); stream << bd::String::printf(STR("+buildts %li\n"), (long)buildts); stream << bd::String::printf(STR("+ip4 %s\n"), myipstr(AF_INET)); stream << bd::String::printf(STR("+ip6 %s\n"), myipstr(AF_INET6)); replay_cache(-1, &stream); stream.writeFile(socks->fd); socks->my_close(); write_userfile(idx); /* if (server_online) { do_chanset(NULL, NULL, STR("+inactive"), DO_LOCAL); dprintf(DP_DUMP, STR("JOIN 0\n")); } */ fixmod(binname); /* replace image now */ char *argv[4] = { NULL, NULL, NULL, NULL }; argv[0] = strdup(binname); if (!backgrd || term_z || sdebug) { char shit[7] = ""; simple_snprintf(shit, sizeof(shit), STR("-%s%s%s"), !backgrd ? "n" : "", term_z ? "t" : "", sdebug ? "D" : ""); argv[1] = strdup(shit); argv[2] = strdup(conf.bot->nick); } else { argv[1] = strdup(conf.bot->nick); } unlink(conf.bot->pid_file); FILE *fp = NULL; if (!(fp = fopen(conf.bot->pid_file, "w"))) return; fprintf(fp, "%d %s\n", getpid(), socks->file); fclose(fp); execvp(argv[0], &argv[0]); /* hopefully this is never reached */ putlog(LOG_MISC, "*", STR("Could not restart: %s"), strerror(errno)); return; }