make pid_of work with processes owned by other users, same method used as in 'ps'
authorGerd von Egidy <gerd.von.egidy@intra2net.com>
Sun, 10 May 2015 14:56:29 +0000 (16:56 +0200)
committerGerd von Egidy <gerd.von.egidy@intra2net.com>
Sun, 10 May 2015 14:56:29 +0000 (16:56 +0200)
src/daemonfunc.cpp

index ebeccfe..99f3be8 100644 (file)
@@ -121,7 +121,10 @@ bool pid_of(const std::string& name, std::vector< pid_t >& result)
    std::vector< pid_t > fuzz1_result;
    std::vector< pid_t > fuzz2_result;
    result.clear();
+
+   if (name.empty()) return false;
    if (!get_dir("/proc", entries)) return false;
+
    for (std::vector< std::string >::const_iterator it= entries.begin();
          it != entries.end();
          ++it)
@@ -133,21 +136,49 @@ bool pid_of(const std::string& name, std::vector< pid_t >& result)
       I2n::Stat stat(exe_path, false);
       if (not stat or not stat.is_link()) continue;
       std::string real_exe= read_link(exe_path);
-      if (real_exe == name)
+      if (!real_exe.empty())
       {
-         result.push_back( pid );
-         continue;
+         // we got the path of the exe
+         if (real_exe == name)
+         {
+               result.push_back( pid );
+               continue;
+         }
+
+         std::string proc_stat= read_file( base_path + "/stat");
+         if (proc_stat.empty()) continue; // process vanished
+
+         //TODO some more fuzz tests here?! (cmdline, stat(us))
+
+         if (basename(real_exe) == name)
+         {
+               fuzz2_result.push_back(pid);
+               continue;
+         }
       }
-
-      std::string proc_stat= read_file( base_path + "/stat");
-      if (proc_stat.empty()) continue; // process vanished
-
-      //TODO some more fuzz tests here?! (cmdline, stat(us))
-
-      if (basename(real_exe) == name)
+      else
       {
-         fuzz2_result.push_back(pid);
-         continue;
+         // we haven't got the path of the exe
+         // this can happen e.g. with processes owned by other users
+         // -> parse the commandline instead
+         std::string cmdline = read_file(base_path + "/cmdline");
+         if (cmdline.empty()) continue;
+
+         // in /proc/*/cmdline, the parameters are split by nullbytes, we only care for the first parameter
+         if (cmdline.find('\0') != string::npos)
+            cmdline.erase(cmdline.find('\0'));
+
+         if (cmdline == name)
+         {
+               result.push_back( pid );
+               continue;
+         }
+
+         if (basename(cmdline) == name)
+         {
+               fuzz2_result.push_back(pid);
+               continue;
+         }
       }
    }
    if (result.empty())