Esempio n. 1
0
        public static string PrepareDebuggerCommandString(ProcessGovernor procgov, string appImageExe)
        {
            var buffer      = new StringBuilder();
            var procgovPath = Assembly.GetAssembly(typeof(ProcessGovernor)).Location;

            buffer.Append('"').Append(procgovPath).Append('"').Append(" --nogui --debugger");

            if (procgov.AdditionalEnvironmentVars.Count > 0)
            {
                // we will create a file in the procgov folder with the environment variables
                string appEnvironmentFilePath = GetAppEnvironmentFilePath(appImageExe);
                using (var writer = new StreamWriter(appEnvironmentFilePath, false)) {
                    foreach (var kv in procgov.AdditionalEnvironmentVars)
                    {
                        writer.WriteLine("{0}={1}", kv.Key, kv.Value);
                    }
                }
                buffer.AppendFormat(" --env=\"{0}\"", appEnvironmentFilePath);
            }

            if (procgov.CpuAffinityMask != 0)
            {
                buffer.AppendFormat(" --cpu=0x{0:X}", procgov.CpuAffinityMask);
            }

            if (procgov.MaxProcessMemory > 0)
            {
                buffer.AppendFormat(" --maxmem={0}", procgov.MaxProcessMemory);
            }

            return(buffer.ToString());
        }
Esempio n. 2
0
 public static void LoadCustomEnvironmentVariables(ProcessGovernor procgov, string file)
 {
     if (file == null || !File.Exists(file))
     {
         throw new ArgumentException("the text file with environment variables does not exist");
     }
     try {
         using (var reader = File.OpenText(file)) {
             int    linenum = 1;
             string line;
             while ((line = reader.ReadLine()) != null)
             {
                 var ind = line.IndexOf("=");
                 if (ind > 0)
                 {
                     var key = line.Substring(0, ind).Trim();
                     if (!string.IsNullOrEmpty(key))
                     {
                         var val = line.Substring(ind + 1, line.Length - ind - 1).Trim();
                         procgov.AdditionalEnvironmentVars.Add(key, val);
                         linenum++;
                         continue;
                     }
                 }
                 throw new ArgumentException(string.Format("the environment file contains invalid data (line: {0})", linenum));
             }
         }
     } catch (IOException ex) {
         throw new ArgumentException("can't read the text file with environment variables, {0}", ex.Message);
     }
 }
Esempio n. 3
0
        public static void SetupRegistryForProcessGovernor(ProcessGovernor procgov, string appImageExe, RegistryOperation oper)
        {
            if (!IsUserAdmin())
            {
                Console.Error.WriteLine("You must be admin to do that. Run the app from the administrative console.");
                return;
            }
            // extrace image.exe if path is provided
            appImageExe = Path.GetFileName(appImageExe);
            var regkey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options", true);

            // add to image file execution path
            if (oper == RegistryOperation.INSTALL)
            {
                regkey = regkey.CreateSubKey(appImageExe);
                regkey.SetValue("Debugger", PrepareDebuggerCommandString(procgov, appImageExe));
            }
            else if (oper == RegistryOperation.UNINSTALL)
            {
                regkey.DeleteSubKey(appImageExe, false);

                var appEnvironmentFilePath = GetAppEnvironmentFilePath(appImageExe);
                if (File.Exists(appEnvironmentFilePath))
                {
                    File.Delete(appEnvironmentFilePath);
                }
            }
        }
Esempio n. 4
0
        public void PrepareDebuggerCommandStringTest()
        {
            var procgov = new ProcessGovernor()
            {
                CpuAffinityMask  = 0x2,
                MaxProcessMemory = 1024 * 1024
            };

            procgov.AdditionalEnvironmentVars.Add("TEST", "TESTVAL");
            procgov.AdditionalEnvironmentVars.Add("TEST2", "TESTVAL2");

            var appImageExe = Path.GetFileName(@"C:\temp\test.exe");
            var debugger    = Program.PrepareDebuggerCommandString(procgov, appImageExe);

            var envFilePath = Program.GetAppEnvironmentFilePath(appImageExe);

            Assert.True(File.Exists(envFilePath));

            try {
                var txt = File.ReadAllText(envFilePath);
                Assert.Equal("TEST=TESTVAL\r\nTEST2=TESTVAL2\r\n", txt);

                Assert.Equal(string.Format("\"{0}\" --nogui --debugger --env=\"{1}\" --cpu=0x2 --maxmem=1048576",
                                           Assembly.GetAssembly(typeof(ProcessGovernor)).Location, envFilePath), debugger);
            } finally {
                File.Delete(envFilePath);
            }
        }
Esempio n. 5
0
        public void LoadCustomEnvironmentVariablesTest()
        {
            var envVarsFile = Path.GetTempFileName();

            try {
                using (var writer = new StreamWriter(envVarsFile, false)) {
                    writer.WriteLine("TEST=TESTVAL");
                    writer.WriteLine("  TEST2 = TEST VAL2  ");
                }

                var procgov = new ProcessGovernor();
                Program.LoadCustomEnvironmentVariables(procgov, envVarsFile);
                Assert.Equal <KeyValuePair <string, string> >(new Dictionary <string, string>()
                {
                    { "TEST", "TESTVAL" },
                    { "TEST2", "TEST VAL2" }
                }, procgov.AdditionalEnvironmentVars);


                using (var writer = new StreamWriter(envVarsFile, false)) {
                    writer.WriteLine("  = TEST VAL2  ");
                }

                Assert.Throws <ArgumentException>(() => {
                    Program.LoadCustomEnvironmentVariables(procgov, envVarsFile);
                });
            } finally {
                if (File.Exists(envVarsFile))
                {
                    File.Delete(envVarsFile);
                }
            }
        }
Esempio n. 6
0
        static void ShowLimits(ProcessGovernor procgov)
        {
            Console.WriteLine("CPU affinity mask:                      {0}", procgov.CpuAffinityMask != 0 ?
                              $"0x{procgov.CpuAffinityMask:X}" : "(not set)");
            Console.WriteLine("Max CPU rate:                           {0}", procgov.CpuMaxRate > 0 ?
                              $"{procgov.CpuMaxRate}%" : "(not set)");
            Console.WriteLine("Maximum committed memory (MB):          {0}", procgov.MaxProcessMemory > 0 ?
                              $"{(procgov.MaxProcessMemory / 1048576):0,0}" : "(not set)");
            Console.WriteLine("Maximum WS memory (MB):                 {0}", procgov.MaxWorkingSetSize > 0 ?
                              $"{(procgov.MaxWorkingSetSize / 1048576):0,0}" : "(not set)");
            Console.WriteLine("Preferred NUMA node:                    {0}", procgov.NumaNode != 0xffff ?
                              $"{procgov.NumaNode}" : "(not set)");
            Console.WriteLine("Process user-time execution limit (ms): {0}", procgov.ProcessUserTimeLimitInMilliseconds > 0 ?
                              $"{procgov.ProcessUserTimeLimitInMilliseconds:0,0}" : "(not set)");
            Console.WriteLine("Job user-time execution limit (ms):     {0}", procgov.JobUserTimeLimitInMilliseconds > 0 ?
                              $"{procgov.JobUserTimeLimitInMilliseconds:0,0}" : "(not set)");
            Console.WriteLine("Clock-time execution limit (ms):        {0}", procgov.ClockTimeLimitInMilliseconds > 0 ?
                              $"{procgov.ClockTimeLimitInMilliseconds:0,0}" : "(not set)");

            if (procgov.PropagateOnChildProcesses)
            {
                Console.WriteLine();
                Console.WriteLine("All configured limits will also apply to the child processes.");
            }
            Console.WriteLine();
            Console.WriteLine("Press Ctrl-C to end execution without terminating the process.");
            Console.WriteLine();
        }
Esempio n. 7
0
        public static int Main(string[] args)
        {
            ShowHeader();

            using (var procgov = new ProcessGovernor()) {
                List <string>     procargs = null;
                bool              showhelp = false, nogui = false, debug = false;
                int               pid               = 0;
                RegistryOperation registryOperation = RegistryOperation.NONE;

                var p = new OptionSet()
                {
                    { "m|maxmem=", "Max committed memory usage in bytes (accepted suffixes: K, M or G).",
                      v => { procgov.MaxProcessMemory = ParseMemoryString(v); } },
                    { "env=", "A text file with environment variables (each line in form: VAR=VAL). Applies only to newly created processes.",
                      v => LoadCustomEnvironmentVariables(procgov, v) },
                    { "c|cpu=", "If in hex (starts with 0x) it is treated as an affinity mask, otherwise it is a number of CPU cores assigned to your app.",
                      v => {
                          if (v.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
                          {
                              procgov.CpuAffinityMask = long.Parse(v.Substring(2), NumberStyles.HexNumber);
                          }
                          else
                          {
                              procgov.CpuAffinityMask = CalculateAffinityMaskFromCpuCount(int.Parse(v));
                          }
                      } },
                    { "r|recursive", "Apply limits to child processes too (will wait for all processes to finish).", v => { procgov.PropagateOnChildProcesses = v != null; } },
                    { "newconsole", "Start the process in a new console window.", v => { procgov.SpawnNewConsoleWindow = v != null; } },
                    { "nogui", "Hide Process Governor console window (set always when installed as debugger).",
                      v => { nogui = v != null; } },
                    { "p|pid=", "Attach to an already running process", (int v) => pid = v },
                    { "install", "Install procgov as a debugger for a specific process using Image File Executions. " +
                      "DO NOT USE this option if the process you want to control starts child instances of itself (for example, Chrome).",
                      v => { registryOperation = RegistryOperation.INSTALL; } },
                    { "t|timeout=", "Kill the process (with -r, also all its children) if it does not finish within the specified time. " +
                      "Add suffix to define the time unit. Valid suffixes are: ms, s, m, h.",
                      (string v) => procgov.ClockTimeLimitInMilliseconds = ParseTimeStringToMilliseconds(v) },
                    { "process-utime=", "Kill the process (with -r, also applies to its children) if it exceeds the given " +
                      "user-mode execution time. Add suffix to define the time unit. Valid suffixes are: ms, s, m, h.",
                      (string v) => procgov.ProcessUserTimeLimitInMilliseconds = ParseTimeStringToMilliseconds(v) },
                    { "job-utime=", "Kill the process (with -r, also all its children) if the total user-mode execution " +
                      "time exceed the specified value. Add suffix to define the time unit. Valid suffixes are: ms, s, m, h.",
                      (string v) => procgov.JobUserTimeLimitInMilliseconds = ParseTimeStringToMilliseconds(v) },
                    { "uninstall", "Uninstall procgov for a specific process.", v => { registryOperation = RegistryOperation.UNINSTALL; } },
                    { "debugger", "Internal - do not use.",
                      v => debug = v != null },
                    { "v|verbose", "Show verbose messages in the console.", v => procgov.ShowTraceMessages = v != null },
                    { "h|help", "Show this message and exit", v => showhelp = v != null },
                    { "?", "Show this message and exit", v => showhelp = v != null }
                };

                try {
                    procargs = p.Parse(args);
                } catch (OptionException ex) {
                    Console.Error.Write("ERROR: invalid argument");
                    Console.Error.WriteLine(ex.Message);
                    Console.WriteLine();
                    showhelp = true;
                } catch (FormatException) {
                    Console.Error.WriteLine("ERROR: invalid number in one of the constraints");
                    Console.WriteLine();
                    showhelp = true;
                } catch (ArgumentException ex) {
                    Console.Error.WriteLine("ERROR: {0}", ex.Message);
                    Console.WriteLine();
                    showhelp = true;
                }

                if (!showhelp && registryOperation != RegistryOperation.NONE)
                {
                    if (procargs.Count == 0)
                    {
                        Console.Error.WriteLine("ERROR: please provide an image name for a process you would like to intercept.");
                        return(1);
                    }
                    SetupRegistryForProcessGovernor(procgov, procargs[0], registryOperation);
                    return(0);
                }

                if (!showhelp && (procargs.Count == 0 && pid == 0) || (pid > 0 && procargs.Count > 0))
                {
                    Console.Error.WriteLine("ERROR: please provide either process name or PID of the already running process");
                    Console.WriteLine();
                    showhelp = true;
                }

                if (showhelp)
                {
                    ShowHelp(p);
                    return(0);
                }

                if (nogui)
                {
                    WinWindows.NativeMethods.ShowWindow(WinWindows.NativeMethods.GetConsoleWindow(),
                                                        WinWindows.NativeMethods.SW_HIDE);
                }

                try {
                    ShowLimits(procgov);

                    if (debug)
                    {
                        return(procgov.StartProcessUnderDebuggerAndDetach(procargs));
                    }
                    if (pid > 0)
                    {
                        return(procgov.AttachToProcess(pid));
                    }
                    return(procgov.StartProcess(procargs));
                } catch (Win32Exception ex) {
                    Console.Error.WriteLine("ERROR: {0} (0x{1:X})", ex.Message, ex.ErrorCode);
                    return(1);
                } catch (Exception ex) {
                    Console.Error.WriteLine("ERROR: {0}", ex.Message);
                    return(1);
                }
            }
        }
Esempio n. 8
0
        public static void Main(string[] args)
        {
            using (var procgov = new ProcessGovernor()) {
                List <string>     procargs = null;
                bool              showhelp = false, nogui = false, debug = false;
                int               pid               = 0;
                RegistryOperation registryOperation = RegistryOperation.NONE;

                var p = new OptionSet()
                {
                    { "m|maxmem=", "Max committed memory usage in bytes (accepted suffixes: K, M or G).",
                      v => { procgov.MaxProcessMemory = ParseMemoryString(v); } },
                    { "env=", "A text file with environment variables (each line in form: VAR=VAL). Applies only to newly created processes.",
                      v => LoadCustomEnvironmentVariables(procgov, v) },
                    { "c|cpu=", "If in hex (starts with 0x) it is treated as an affinity mask, otherwise it is a number of CPU cores assigned to your app.",
                      v => {
                          if (v.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
                          {
                              procgov.CpuAffinityMask = long.Parse(v.Substring(2), NumberStyles.HexNumber);
                          }
                          else
                          {
                              procgov.CpuAffinityMask = CalculateAffinityMaskFromCpuCount(int.Parse(v));
                          }
                      } },
                    { "newconsole", "Start the process in a new console window.", v => { procgov.SpawnNewConsoleWindow = v != null; } },
                    { "nogui", "Hide Process Governor console window (set always when installed as debugger).",
                      v => { nogui = v != null; } },
                    { "p|pid=", "Attach to an already running process", (int v) => pid = v },
                    { "install", "Installs procgov as a debugger for a specific process using Image File Executions.",
                      v => { registryOperation = RegistryOperation.INSTALL; } },
                    { "uninstall", "Uninstalls procgov for a specific process.",
                      v => { registryOperation = RegistryOperation.UNINSTALL; } },
                    { "debugger", "Internal - do not use.",
                      v => { debug = v != null; } },
                    { "h|help", "Show this message and exit", v => showhelp = v != null },
                    { "?", "Show this message and exit", v => showhelp = v != null }
                };

                try {
                    procargs = p.Parse(args);
                } catch (OptionException ex) {
                    Console.Write("ERROR: invalid argument");
                    Console.WriteLine(ex.Message);
                    Console.WriteLine();
                    showhelp = true;
                } catch (FormatException) {
                    Console.WriteLine("ERROR: invalid number in one of the constraints");
                    Console.WriteLine();
                    showhelp = true;
                } catch (ArgumentException ex) {
                    Console.WriteLine("ERROR: {0}", ex.Message);
                    Console.WriteLine();
                    showhelp = true;
                }

                if (!showhelp && registryOperation != RegistryOperation.NONE)
                {
                    if (procargs.Count == 0)
                    {
                        Console.WriteLine("ERROR: please provide an image name for a process you would like to intercept.");
                        return;
                    }
                    SetupRegistryForProcessGovernor(procgov, procargs[0], registryOperation);
                    return;
                }

                if (!showhelp && (procargs.Count == 0 && pid == 0) || (pid > 0 && procargs.Count > 0))
                {
                    Console.WriteLine("ERROR: please provide either process name or PID of the already running process");
                    Console.WriteLine();
                    showhelp = true;
                }

                if (showhelp)
                {
                    ShowHelp(p);
                    return;
                }

                if (nogui)
                {
                    WinWindows.NativeMethods.ShowWindow(WinWindows.NativeMethods.GetConsoleWindow(),
                                                        WinWindows.NativeMethods.SW_HIDE);
                }

                try {
                    if (debug)
                    {
                        procgov.StartProcessUnderDebuggerAndDetach(procargs);
                    }
                    else if (pid > 0)
                    {
                        procgov.AttachToProcess(pid);
                    }
                    else
                    {
                        procgov.StartProcess(procargs);
                    }
                } catch (Win32Exception ex) {
                    Console.WriteLine("ERROR: {0} (0x{1:X})", ex.Message, ex.ErrorCode);
                } catch (Exception ex) {
                    Console.WriteLine("ERROR: {0}", ex.Message);
                }
            }
        }