diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c82b07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-cache +zig-out diff --git a/README.md b/README.md new file mode 100644 index 0000000..39524c7 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# IsRunning + +IsRunning is a very simple and lightweight Windows command-line utility to check if some processes are running or not. + +It expects a list of process's names as argument and simply exits with code `0` if they were found, or `1` otherwise. +No output or message is printed. + +Usage: + +```CMD +IsRunning.exe PROCESS_1 [PROCESS_2] [PROCESS_N] +``` + +_Examples_ +```CMD +C:\> IsRunning.exe traefik.exe +C:\> echo %errorlevel% +0 +``` + +```CMD +C:\> IsRunning.exe traefik.exe node.exe +C:\> echo %errorlevel% +0 +``` + +```CMD +C:\> IsRunning.exe dead.exe +C:\> echo %errorlevel% +1 +``` + +### Motivation +Its main purpose is to serve as readiness probe for containers that spawn multiple processes. + +For example, a [Pod readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) to detect if `traefik` is running: +```yaml + readinessProbe: + exec: + command: + - C:/IsRunning.exe + - traefik.exe + failureThreshold: 3 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 +``` + +> It's not advisable to run multiple processes on a single container, but for many reasons, it's not uncommon, especially for legacy applications in Microsoft Windows containers. + +### Why not use batch script? +I used to use a batch script combining `tasklist` and `find` together: + +```CMD +C:\> tasklist | find "traefik.exe" +C:\> echo %errorlevel% +0 +``` + +It works, but it's not the most efficient solution, particularly when you call it every 5 seconds for hundreds of containers. + +This utility saves a little bit of CPU and memory by removing the overhead of `CMD` interpreter and all the string processing between `tasklist` and `find`. + +This utility is implemented in [Zig](https://ziglang.org/), just because we needed a native, small, fast, and secure binary to perform such task. + +### Further improvements + +- Windows only application + +- It is optimized for low memory consumption, and only works with ASCII processes names. + +Please, feel free to open an issue or send a PR if you might improve this implementation in some sense. + diff --git a/UNLICENSE.txt b/UNLICENSE.txt new file mode 100644 index 0000000..3c577b0 --- /dev/null +++ b/UNLICENSE.txt @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/src/main.zig b/src/main.zig index a7d92d5..51cc8c0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -23,7 +23,7 @@ pub fn main() u8 { var name = getProcessName(allocator, process_id) orelse continue; defer allocator.free(name); - if (args.contains(name)) { + if (args.contains(toUpper(name))) { return FOUND; } } @@ -41,7 +41,7 @@ fn getArgs(allocator: *Allocator) ?StringHashMap { while (iterator.next(allocator)) |arg| { var key = arg catch unreachable; - var entry = args.getOrPut(key) catch unreachable; + var entry = args.getOrPut(toUpper(key)) catch unreachable; if (entry.found_existing) { allocator.free(key); } @@ -64,6 +64,13 @@ fn deinitArgs(args: *StringHashMap) void { args.deinit(); } +fn toUpper(str: []u8) []u8 { + for (str) |*char| { + char.* = std.ascii.toUpper(char.*); + } + return str; +} + fn getProcesses(allocator: *Allocator) ?[]win32.DWORD { // It's likely to have few processes inside a container @@ -103,7 +110,7 @@ fn getProcessName(allocator: *Allocator, process_id: win32.DWORD) ?[]u8 { } else { // Starting with a small buffer and grow as needed - var max_process_name: usize = 64; + var max_process_name: usize = 32; var name_buffer = allocator.allocSentinel(win32.CHAR, max_process_name, 0) catch unreachable; errdefer allocator.free(name_buffer);