Parcourir la source

Merge branch 'spawning-cleanups'

* spawning-cleanups:
  * Add missing NULL-terminator
  * Simply last checking
  * Simplify crontab handling
  * Use execvp() to search PATH if needed
  * Close file descriptors when spawning new processes
  * Cleanup update spawning
  * Cleanup config editor spawning
  * No need to escape botnick while restarting now
  * Use new simple_exec() instead of system() in some places
  * Remove old debugging/cygwin code
  * Add a simple_exec() which directly executes the given file.
Bryan Drewery il y a 16 ans
Parent
commit
14cdae2440
10 fichiers modifiés avec 148 ajouts et 151 suppressions
  1. 3 9
      src/binary.c
  2. 12 4
      src/cmds.c
  3. 0 5
      src/common.h
  4. 4 12
      src/conf.c
  5. 2 2
      src/debug.c
  6. 2 0
      src/eggdrop.h
  7. 0 6
      src/main.c
  8. 16 13
      src/misc.c
  9. 102 98
      src/shell.c
  10. 7 2
      src/shell.h

+ 3 - 9
src/binary.c

@@ -560,14 +560,8 @@ check_sum(const char *fname, const char *cfgfile, bool read_stdin)
 
 bool check_bin_initialized(const char *fname)
 {
-  int i = 0;
-  size_t len = strlen(shell_escape(fname)) + 3 + 1;
-  char *path = (char *) my_calloc(1, len);
-
-  simple_snprintf(path, len, STR("%s -p"), shell_escape(fname));
-
-  i = system(path);
-  free(path);
+  const char* argv[] = {fname, "-p", 0};
+  int i = simple_exec(argv);
   if (i != -1 && WEXITSTATUS(i) == 4)
     return 1;
 
@@ -582,7 +576,7 @@ bool check_bin_compat(const char *fname)
   char *out = NULL;
 
   simple_snprintf(path, len, STR("%s -3"), shell_escape(fname));
-  if (shell_exec(path, NULL, &out, NULL)) {
+  if (shell_exec(path, NULL, &out, NULL, 1)) {
     if (out) {
       char *buf = out;
       size_t settings_ver = atoi(newsplit(&buf)), settings_len = atoi(newsplit(&buf));

+ 12 - 4
src/cmds.c

@@ -63,6 +63,8 @@
 #include "src/mod/update.mod/update.h"
 #include "src/mod/channels.mod/channels.h"
 #include "src/mod/share.mod/share.h"
+#include <bdlib/src/String.h>
+#include <bdlib/src/Stream.h>
 
 #include <ctype.h>
 #include <stdlib.h>
@@ -3990,8 +3992,14 @@ static void cmd_netlast(int idx, char * par) {
 void crontab_show(struct userrec *u, int idx) {
   dprintf(idx, "Showing current crontab:\n");
 #ifndef CYGWIN_HACKS
-  if (!exec_str(idx, "crontab -l | grep -v \"^#\""))
-    dprintf(idx, "Exec failed");
+  bd::Stream crontab;
+  bd::String line;
+  crontab_exists(&crontab);
+  crontab.seek(0, SEEK_SET);
+  while (crontab.tell() < crontab.length()) {
+    line = crontab.getline();
+    dprintf(idx, "%s\n", line.c_str());
+  }
 #endif /* !CYGWIN_HACKS */
 }
 
@@ -4128,7 +4136,7 @@ static void rcmd_exec(char * frombot, char * fromhand, char * fromidx, char * pa
     char *code = newsplit(&par);
 
     if (!strcmp(code, "show")) {
-      strlcpy(scmd, "crontab -l | grep -v \"^#\"", sizeof(scmd));
+      strlcpy(scmd, "crontab -l", sizeof(scmd));
     } else if (!strcmp(code, "delete")) {
       crontab_del();
     } else if (!strcmp(code, "new")) {
@@ -4153,7 +4161,7 @@ static void rcmd_exec(char * frombot, char * fromhand, char * fromidx, char * pa
   }
   if (!scmd[0])
     return;
-  if (shell_exec(scmd, NULL, &out, &err)) {
+  if (shell_exec(scmd, NULL, &out, &err, 1)) {
     if (out) {
       char *p = NULL, *np = NULL;
 

+ 0 - 5
src/common.h

@@ -44,11 +44,6 @@
 #endif /* WIN32 */
 
 
-//# undef system
-int system(const char *);		
-//# define system(_run) 	my_system(_run)
-
-
 #define BIT0    (uint32_t) 0x000000001
 #define BIT1    (uint32_t) 0x000000002
 #define BIT2    (uint32_t) 0x000000004

+ 4 - 12
src/conf.c

@@ -83,16 +83,13 @@ tellconf()
 
 void spawnbot(const char *nick)
 {
-  size_t size = strlen(shell_escape(nick)) + strlen(shell_escape(binname)) + 20;
-  char *run = (char *) my_calloc(1, size);
   int status = 0;
 
-  simple_snprintf(run, size, "%s %s", shell_escape(binname), shell_escape(nick));
-  sdprintf("Spawning '%s': %s", nick, run);
-  status = system(run);
+  sdprintf("Spawning '%s'", nick);
+  const char* argv[] = {binname, nick, 0};
+  status = simple_exec(argv);
   if (status == -1 || WEXITSTATUS(status))
     sdprintf("Failed to spawn '%s': %s", nick, strerror(errno));
-  free(run);
 }
 
 /* spawn and kill bots accordingly
@@ -234,13 +231,8 @@ confedit()
       fatal(STR("Cannot fork"), 0);
     case 0:
     {
-      char *run = NULL;
-      size_t size = tmpconf.len + strlen(editor) + 5;
-
-      run = (char *) my_calloc(1, size);
       /* child */
-      simple_snprintf(run, size, "%s %s", editor, tmpconf.file);
-      execlp("/bin/sh", "/bin/sh", "-c", run, (char*)NULL);
+      execlp(editor, editor, tmpconf.file, (char*)NULL);
       perror(editor);
       exit(1);
      /*NOTREACHED*/}

+ 2 - 2
src/debug.c

@@ -89,8 +89,8 @@ void setlimits()
 #ifndef __sun__
   setrlimit(RLIMIT_NPROC, &plim);
 #endif
-  fdlim.rlim_cur = 300;
-  fdlim.rlim_max = 300;
+  fdlim.rlim_cur = MAX_SOCKETS;
+  fdlim.rlim_max = MAX_SOCKETS;
   setrlimit(RLIMIT_NOFILE, &fdlim);
 #endif /* !CYGWIN_HACKS */
 }

+ 2 - 0
src/eggdrop.h

@@ -27,6 +27,8 @@
 #define HANDLEN		  9	/* valid values 9->NICKMAX		*/
 #define NICKMAX		 32	/* valid values HANDLEN->32		*/
 
+#define MAX_SOCKETS	300
+
 
 /* Handy string lengths */
 

+ 0 - 6
src/main.c

@@ -724,12 +724,6 @@ int main(int argc, char **argv)
 
   srandom(now % (mypid + getppid()) * randint(1000));
 
-/*
-  char *out = NULL;
-printf("ret: %d\n", system("c:/wraith/leaf.exe"));
-  shell_exec("c:\\windows\\notepad.exe", NULL, &out, &out);
-printf("out: %s\n", out);
-*/
   setlimits();
   init_debug();
   init_signals();

+ 16 - 13
src/misc.c

@@ -753,16 +753,16 @@ restart(int idx)
   /* replace image now */
   char *argv[4] = { NULL, NULL, NULL, NULL };
 
-  argv[0] = strdup(shell_escape(binname));
+  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(shell_escape(conf.bot->nick));
+    argv[2] = strdup(conf.bot->nick);
   } else {
-    argv[1] = strdup(shell_escape(conf.bot->nick));
+    argv[1] = strdup(conf.bot->nick);
   }
 
   unlink(conf.bot->pid_file);
@@ -783,8 +783,6 @@ restart(int idx)
 void 
 hard_restart(int idx)
 {
-  char buf[1024] = "";
-
   write_userfile(idx);
   if (!conf.bot->hub) {
     nuke_server((char *) reason);		/* let's drop the server connection ASAP */
@@ -792,9 +790,8 @@ hard_restart(int idx)
   }
   fatal(idx <= 0x7FF0 ? reason : NULL, 1);
   usleep(2000 * 500);
-  simple_snprintf(buf, sizeof(buf), "%s -B %s\n", shell_escape(binname), shell_escape(conf.bot->nick));
   unlink(conf.bot->pid_file); /* if this fails it is ok, cron will restart the bot, *hopefully* */
-  system(buf); /* start new bot. */
+  simple_exec(binname, conf.bot->nick);
   exit(0);
 }
 #endif
@@ -809,6 +806,7 @@ int updatebin(int idx, char *par, int secs)
   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];
 #ifndef CYGWIN_HACKS
   int i;
 #endif /* !CYGWIN_HACKS */
@@ -878,9 +876,11 @@ int updatebin(int idx, char *par, int secs)
 
   /* The binary should return '2' when ran with -2, if not it's probably corrupt. */
 #ifndef CYGWIN_HACKS
-  simple_snprintf(buf, sizeof(buf), STR("%s -2"), shell_escape(path));
-  putlog(LOG_DEBUG, "*", STR("Running for update binary test: %s"), buf);
-  i = system(buf);
+  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) {
     dprintf(idx, STR("Couldn't restart new binary (error %d)\n"), i);
     putlog(LOG_MISC, "*", STR("Couldn't restart new binary (error %d)"), i);
@@ -891,9 +891,12 @@ int updatebin(int idx, char *par, int secs)
 
   /* now to send our config to the new binary */
 #ifndef CYGWIN_HACKS
-  simple_snprintf(buf, sizeof(buf), STR("%s -4 %s"), shell_escape(path), conffile->file);
-  putlog(LOG_DEBUG, "*", STR("Running for update conf: %s"), buf);
-  i = system(buf);
+  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 */
     dprintf(idx, STR("Couldn't pass config to new binary (error %d)\n"), i);

+ 102 - 98
src/shell.c

@@ -29,6 +29,8 @@
 #include "users.h"
 #include "botnet.h"
 #include "src/mod/server.mod/server.h"
+#include <bdlib/src/String.h>
+#include <bdlib/src/Stream.h>
 
 #include <sys/types.h>
 #include <pwd.h>
@@ -51,36 +53,6 @@
 
 bool clear_tmpdir = 0;
 
-int my_system(const char *run)
-{
-#ifdef WIN32NOFUCK
-  int ret = -1;
-
-  PROCESS_INFORMATION pinfo;
-  STARTUPINFO sinfo;
-
-  memset(&sinfo, 0, sizeof(STARTUPINFO));
-  sinfo.cb = sizeof(sinfo);
-
-  sinfo.wShowWindow = SW_HIDE;
-  sinfo.dwFlags |= STARTF_USESTDHANDLES;
-  sinfo.hStdInput =
-  sinfo.hStdOutput =
-  sinfo.hStdError =
-
-  ret =
-    CreateProcess(NULL, (char *) run, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS | DETACHED_PROCESS, NULL, NULL,
-                  (STARTUPINFO *) &sinfo, (PROCESS_INFORMATION *) &pinfo);
-
-  if (ret == 0)
-    return -1;
-  else
-    return 0;
-#else
-  return system(run);
-#endif /* WIN32 */
-}
-
 void clear_tmp()
 {
   if (!clear_tmpdir)
@@ -190,7 +162,7 @@ void check_last() {
     char *out = NULL, buf[50] = "";
 
     simple_snprintf(buf, sizeof(buf), STR("last -10 %s"), conf.username);
-    if (shell_exec(buf, NULL, &out, NULL)) {
+    if (shell_exec(buf, NULL, &out, NULL, 1)) {
       if (out) {
         char *p = NULL;
 
@@ -342,7 +314,7 @@ void check_trace(int start)
 }
 #endif /* !CYGWIN_HACKS */
 
-int shell_exec(char *cmdline, char *input, char **output, char **erroutput)
+int shell_exec(char *cmdline, char *input, char **output, char **erroutput, bool simple)
 {
   if (!cmdline)
     return 0;
@@ -444,11 +416,10 @@ int shell_exec(char *cmdline, char *input, char **output, char **erroutput)
   } else {
     /* Child: make fd's and set them up as std* */
 //    int ind, outd, errd;
-    char *argv[4] = { NULL, NULL, NULL, NULL };
-
 //    ind = fileno(inpFile);
 //    outd = fileno(outFile);
 //    errd = fileno(errFile);
+
     if (dup2(in->fd, STDIN_FILENO) == (-1)) {
       kill(parent, SIGCHLD);
       exit(1);
@@ -461,16 +432,54 @@ int shell_exec(char *cmdline, char *input, char **output, char **erroutput)
       kill(parent, SIGCHLD);
       exit(1);
     }
-    argv[0] = "/bin/sh";
-    argv[1] = "-c";
-    argv[2] = cmdline;
-    argv[3] = NULL;
+
+    char *argv[15];
+    if (simple) {
+      char *p = NULL;
+      int n = 0;
+      char *mycmdline = strdup(cmdline);
+
+      while (mycmdline[0] && (p = newsplit(&mycmdline)))
+        argv[n++] = p;
+      argv[n] = NULL;
+
+      // Close all sockets
+      for (int fd = 3; fd < MAX_SOCKETS; ++fd) close(fd);
+    } else {
+      argv[0] = "/bin/sh";
+      argv[1] = "-c";
+      argv[2] = cmdline;
+      argv[3] = NULL;
+    }
+
     execvp(argv[0], &argv[0]);
     kill(parent, SIGCHLD);
     exit(1);
   }
 }
 
+int simple_exec(const char* argv[]) {
+  pid_t pid, savedpid;
+  int status;
+
+  switch ((pid = fork())) {
+    case -1:
+      break;
+    case 0:		//child
+      // Close all sockets
+      for (int fd = 3; fd < MAX_SOCKETS; ++fd) close(fd);
+      execvp(argv[0], (char* const*) &argv[0]);
+      _exit(127);
+    default:		//parent
+      savedpid = pid;
+      do {
+        pid = wait4(savedpid, &status, 0, (struct rusage *)0);
+      } while (pid == -1 && errno == EINTR);
+      break;
+  }
+  return(pid == -1 ? -1 : status);
+}
+
 void suicide(const char *msg)
 {
   char tmp[512] = "";
@@ -775,84 +784,79 @@ void check_crontab()
   }
 }
 
-void crontab_del() {
-  char *tmpFile = NULL, *p = NULL, buf[2048] = "";
+static void crontab_install(bd::Stream& crontab) {
+  // Write out the new crontab
+  Tempfile new_crontab = Tempfile("crontab");
+  crontab.writeFile(new_crontab.fd);
 
-  size_t tmplen = strlen(binname) + 100;
-  tmpFile = (char *) my_calloc(1, tmplen);
+  // Install new crontab
+  const char* argv[] = {"crontab", new_crontab.file, 0};
+  simple_exec(argv);
+}
 
-  strlcpy(tmpFile, shell_escape(binname), tmplen);
-  if (!(p = strrchr(tmpFile, '/')))
-    return;
-  p++;
-  strcpy(p, STR(".ctb"));
-  simple_snprintf(buf, sizeof(buf), STR("crontab -l | grep -v '%s' | grep -v \"^#\" | grep -v \"^\\$\" > %s"), binname, tmpFile);
-  if (shell_exec(buf, NULL, NULL, NULL)) {
-    simple_snprintf(buf, sizeof(buf), STR("crontab %s"), tmpFile);
-    shell_exec(buf, NULL, NULL, NULL);
-  }
-  unlink(tmpFile);
+void crontab_del() {
+  bd::Stream crontab;
+  if (crontab_exists(&crontab, 1) == 1)
+    crontab_install(crontab);
 }
 
 #ifndef CYGWIN_HACKS
-int crontab_exists() {
-  char buf[2048] = "", *out = NULL;
+int crontab_exists(bd::Stream* crontab, bool excludeSelf) {
+  char *out = NULL;
+  int ret = -1;
+
+  if (shell_exec("crontab -l", NULL, &out, NULL, 1)) {
+    if (out) {
+      bd::Stream stream(out);
+      bd::String line;
+
+      ret = 0;
+      while (stream.tell() < stream.length()) {
+        line = stream.getline();
+        if (line[0] != '#' && line.find(binname) != bd::String::npos) {
+          ret = 1;
+
+          // Need to continue if the existing crontab is requested
+          if (crontab && !excludeSelf)
+            (*crontab) << line;
+          else if (!crontab)
+            break;
+        } else if (crontab)
+          (*crontab) << line;
+      }
 
-  simple_snprintf(buf, sizeof buf, STR("crontab -l | grep '%s' | grep -v \"^#\""), binname);
-  if (shell_exec(buf, NULL, &out, NULL)) {
-    if (out && strstr(out, binname)) {
       free(out);
-      return 1;
-    } else {
-      if (out)
-        free(out);
-      return 0;
     }
-  } else
-    return (-1);
+  }
+  return ret;
 }
 
 char s1_2[3] = "",s1_8[3] = "",s2_5[3] = "";
 
 void crontab_create(int interval) {
-  char tmpFile[161] = "";
-  FILE *f = NULL;
-  int fd;
+  bd::Stream crontab;
 
-  simple_snprintf(tmpFile, sizeof tmpFile, STR("%s.crontab-XXXXXX"), tempdir);
-  if ((fd = mkstemp(tmpFile)) == -1) {
-    unlink(tmpFile);
+  if (crontab_exists(&crontab) == 1)
     return;
-  }
-
-  char buf[256] = "";
 
-  simple_snprintf(buf, sizeof buf, STR("crontab -l | grep -v \"%s\" | grep -v \"^#\" | grep -v \"^\\$\"> %s"), 
-                  binname, tmpFile);
-  if (shell_exec(buf, NULL, NULL, NULL) && (f = fdopen(fd, "a")) != NULL) {
-    buf[0] = 0;
-    if (interval == 1)
-      strlcpy(buf, "*", 2);
-    else {
-      int i = 1;
-      int si = randint(interval);
-
-      while (i < 60) {
-        if (buf[0])
-          strlcat(buf, ",", sizeof(buf));
-        simple_snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "%i", (i + si) % 60);
-        i += interval;
-      }
+  char buf[1024] = "";
+  if (interval == 1)
+    strlcpy(buf, "*", 2);
+  else {
+    int i = 1;
+    int si = randint(interval);
+
+    while (i < 60) {
+      if (buf[0])
+        strlcat(buf, ",", sizeof(buf));
+      simple_snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "%i", (i + si) % 60);
+      i += interval;
     }
-    simple_snprintf(buf + strlen(buf), sizeof buf, STR(" * * * * %s > /dev/null 2>&1"), binname);
-    fseek(f, 0, SEEK_END);
-    fprintf(f, "\n%s\n", buf);
-    fclose(f);
-    simple_snprintf(buf, sizeof(buf), STR("crontab %s"), tmpFile);
-    shell_exec(buf, NULL, NULL, NULL);
   }
-  close(fd);
-  unlink(tmpFile);
+  simple_snprintf(buf + strlen(buf), sizeof buf, STR(" * * * * %s > /dev/null 2>&1\n"), shell_escape(binname));
+
+  crontab << buf;
+  crontab_install(crontab);
 }
 #endif /* !CYGWIN_HACKS */
 

+ 7 - 2
src/shell.h

@@ -40,6 +40,10 @@
 
 #define DETECTED_LEN	8		/* 'suicide' is longest word */
 
+namespace bd {
+  class Stream;
+}
+
 void check_maxfiles();
 void check_mypid();
 void clear_tmp();
@@ -47,14 +51,15 @@ char *homedir(bool = 1);
 char *my_username();
 void expand_tilde(char **);
 int email(char *, char *, int);
-int shell_exec(char *, char *, char **, char **);
+int shell_exec(char *, char *, char **, char **, bool = 0);
+int simple_exec(const char* argv[]);
 #ifndef CYGWIN_HACKS
 void check_last();
 void check_promisc();
 void check_trace(int);
 void check_crontab();
 void crontab_del();
-int crontab_exists();
+int crontab_exists(bd::Stream* = NULL, bool = 0);
 void crontab_create(int);
 void detected(int, const char *);
 #endif /* !CYGWIN_HACKS */