realuser 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +125 -0
  4. data/lib/realuser.rb +134 -0
  5. metadata +152 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e03f1f6f13c2a98474e2f4fc75b7ff0966730ce3706137dbd7f7bd3fc895cb8f
4
+ data.tar.gz: b4b2048130f57d58ee35ecfe1f4762afae8eb63d80949e5ef90a290bcefba4f2
5
+ SHA512:
6
+ metadata.gz: bdee82a998f28f1a8f9ec72147ab8cbc5caeeac9b348c58e304df98cb0ad541fad430990ba602fbb04f7605fe88b94b9736c4af952eada7016fad8b7a9391e02
7
+ data.tar.gz: 6ed3268db94fbc18ba4a9b34013aefc48bd4eb664700878524212716299fab81601cfe65fde9b330d3642e1b1bb2dc5157c55e9e5962bcf6040aa62a62fc8325
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Julian Kahlert
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # RealUser
2
+
3
+ [![Build Status](https://github.com/juliankahlert/realuser/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/juliankahlert/realuser)
4
+ [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/juliankahlert/realuser)](https://github.com/juliankahlert/realuser/commits/)
5
+ [![GitHub Tag](https://img.shields.io/github/v/tag/juliankahlert/realuser)](https://github.com/juliankahlert/realuser)
6
+ [![Gem Version](https://img.shields.io/gem/v/realuser)](https://rubygems.org/gems/realuser)
7
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/20103f24ebc747cda2ebe2d2029365f6)](https://app.codacy.com/gh/juliankahlert/realuser/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
8
+ [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/20103f24ebc747cda2ebe2d2029365f6)](https://app.codacy.com/gh/juliankahlert/realuser/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)
9
+
10
+ ## Introduction
11
+
12
+ The `RealUser` gem provides a simple Ruby interface for retrieving the real user ID (RUID) of a process and its parent processes on Linux systems. It interacts with the `/proc` filesystem to fetch detailed process information and supports both deep and shallow resolution of the RUID.
13
+
14
+ ## Features
15
+
16
+ - **Retrieve RUID**: Obtain the real user ID of a specific process.
17
+ - **Parent Process Lookup**: Access the RUID of a process’s parent and ancestor processes.
18
+ - **Deep and Shallow Resolution**: Choose between deep resolution (finding the root process) or shallow resolution (finding the nearest ancestor with a different RUID).
19
+ - **Caching**: Efficiently caches results to improve performance.
20
+
21
+ ## Install
22
+
23
+ The supported installation methods are:
24
+
25
+ ### Using `gitpack`
26
+
27
+ To install the gem from RubyGems:
28
+
29
+ ```sh
30
+ gitpack add juliankahlert/realuser
31
+ ```
32
+
33
+ ### Using `gem`
34
+
35
+ To install the gem from RubyGems:
36
+
37
+ ```sh
38
+ gem install realuser
39
+ ```
40
+
41
+ ### From Source
42
+
43
+ You can also install the gem from the source repository:
44
+
45
+ ```sh
46
+ git clone https://github.com/juliankahlert/realuser.git
47
+ cd realuser
48
+ gem build realuser.gemspec
49
+ sudo gem install --local realuser-0.1.0.gem
50
+ ```
51
+
52
+ ## API Documentation
53
+
54
+ ### `RealUser#ruid(cfg = Process.pid)`
55
+
56
+ - **Description**: Determines the RUID of a process based on the provided configuration. Can perform deep or shallow resolution based on the options given.
57
+ - **Parameters**:
58
+ - `cfg` (Integer, Hash):
59
+ - If an Integer, it performs a deep resolution for the given `pid`.
60
+ - If a Hash, it can contain:
61
+ - `:pid` (Integer): The process ID to resolve. Defaults to the current process.
62
+ - `:deep` (Boolean): If `true`, performs a deep resolution; if `false` or omitted, performs a shallow resolution.
63
+ - **Returns**: Integer representing the RUID of the process, or `nil` if it cannot be determined.
64
+
65
+ ### `RealUser::Resolver`
66
+
67
+ - **`.deep(pid)`**
68
+ - **Description**: Recursively resolves and returns the RUID of the root process ancestor of the specified `pid`.
69
+ - **Parameters**:
70
+ - `pid` (Integer): The process ID to start the resolution from.
71
+ - **Returns**: Integer representing the RUID of the root ancestor, or `nil` if the RUID cannot be determined.
72
+
73
+ - **`.shallow(pid, pruid = nil)`**
74
+ - **Description**: Resolves and returns the RUID of the given `pid` or the nearest ancestor where the RUID differs from `pruid`. Recursively checks parent processes if needed.
75
+ - **Parameters**:
76
+ - `pid` (Integer): The process ID to start the resolution from.
77
+ - `pruid` (Integer, optional): The RUID of the parent process to compare against. If provided, will return the RUID of the process if it differs from `pruid`.
78
+ - **Returns**: Integer representing the RUID of the nearest ancestor with a different RUID, or the RUID of the specified process.
79
+
80
+ ### `RealUser::ProcFs`
81
+
82
+ - **`.ruid(pid = Process.pid)`**
83
+ - **Description**: Retrieves the real user ID (RUID) of the process with the specified `pid`. Defaults to the current process ID if `pid` is not provided.
84
+ - **Parameters**:
85
+ - `pid` (Integer): The process ID to retrieve the RUID for. Defaults to `Process.pid`.
86
+ - **Returns**: Integer representing the RUID, or `nil` if the RUID cannot be determined.
87
+
88
+ - **`.ppid(pid = Process.pid)`**
89
+ - **Description**: Retrieves the parent process ID (PPID) of the process with the specified `pid`. Defaults to the current process ID if `pid` is not provided.
90
+ - **Parameters**:
91
+ - `pid` (Integer): The process ID to retrieve the PPID for. Defaults to `Process.pid`.
92
+ - **Returns**: Integer representing the PPID, or `nil` if the PPID cannot be determined.
93
+
94
+ For detailed API documentation, please refer to the [YARD documentation](https://rubydoc.info/github/juliankahlert/realuser).
95
+
96
+ ## Example Usage
97
+
98
+ Here is an example of how to use the `RealUser` gem to find the RUID of a process and its parent processes:
99
+
100
+ ```ruby
101
+ require 'realuser'
102
+
103
+ # Create an instance of the RealUser module
104
+ real_user = RealUser.new
105
+
106
+ # Get the RUID of the current process
107
+ puts "Current process RUID: #{real_user.ruid}"
108
+
109
+ # Get the RUID of a specific process (PID 1234)
110
+ puts "Process 1234 RUID: #{real_user.ruid(1234)}"
111
+
112
+ # Perform a deep resolution to find the root RUID of a specific process (PID 1234)
113
+ puts "Root RUID of process 1234: #{real_user.ruid(pid: 1234, deep: true)}"
114
+
115
+ # Perform a shallow resolution to find the nearest ancestor with a different RUID
116
+ puts "Shallow RUID of process 1234: #{real_user.ruid(pid: 1234, deep: false)}"
117
+ ```
118
+
119
+ ## Encouragement for Contribution
120
+
121
+ Contributions from the community are welcome! If you find any issues, have suggestions for improvements, or want to add new features, please feel free to submit a pull request or open an issue on [GitHub](https://github.com/juliankahlert/realuser).
122
+
123
+ ## License
124
+
125
+ `RealUser` is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
data/lib/realuser.rb ADDED
@@ -0,0 +1,134 @@
1
+ # lib/realuser.rb
2
+ #
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2024 Julian Kahlert
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ module RealUser
26
+
27
+ # The `ProcFs` class interacts with the `/proc` filesystem to fetch
28
+ # information about the real user ID (RUID) and parent process ID (PPID) of a given process.
29
+ class ProcFs
30
+
31
+ # Retrieves the real user ID (RUID) of the process specified by `pid`.
32
+ # Defaults to the current process ID if none is provided.
33
+ #
34
+ # @param pid [Integer] the process ID for which to retrieve the RUID. Defaults to `Process.pid`.
35
+ # @return [Integer, nil] the real user ID of the process, or `nil` if it cannot be determined.
36
+ def self.ruid(pid = Process.pid)
37
+ @ruid_cache ||= {}
38
+ key = pid.to_s.to_sym
39
+
40
+ result = @ruid_cache[key]
41
+ return result if result
42
+
43
+ result = File.stat("/proc/#{pid}").uid
44
+ @ruid_cache[key] = result
45
+ result
46
+ rescue
47
+ @ruid_cache[key] = nil
48
+ nil
49
+ end
50
+
51
+ # Retrieves the parent process ID (PPID) of the process specified by `pid`.
52
+ # Defaults to the current process ID if none is provided.
53
+ #
54
+ # @param pid [Integer] the process ID for which to retrieve the PPID. Defaults to `Process.pid`.
55
+ # @return [Integer, nil] the parent process ID of the process, or `nil` if it cannot be determined.
56
+ def self.ppid(pid = Process.pid)
57
+ @ppid_cache ||= {}
58
+ key = pid.to_s.to_sym
59
+
60
+ result = @ppid_cache[key]
61
+ return result if result
62
+
63
+ result = File.read("/proc/#{pid}/status").match(/^PPid:\s+(\d+)/)[1].to_i
64
+ @ppid_cache[key] = result
65
+ result
66
+ rescue
67
+ @ppid_cache[key] = nil
68
+ nil
69
+ end
70
+ end
71
+
72
+ # The `Resolver` class provides methods to resolve the real user ID (RUID) of a process
73
+ # and its parent processes, either through a deep search (resolving the root RUID) or a shallow search.
74
+ class Resolver
75
+
76
+ # Resolves the real user ID (RUID) of the root process ancestor of the given `pid`.
77
+ # It recursively traverses the parent processes until it finds the root process.
78
+ #
79
+ # @param pid [Integer] the process ID for which to resolve the root RUID.
80
+ # @return [Integer, nil] the root RUID of the process, or `nil` if it cannot be determined.
81
+ def self.deep(pid)
82
+ ppid = ProcFs.ppid(pid)
83
+
84
+ # has parent and parent is not init
85
+ if ppid && ppid > 1
86
+ deep(ppid)
87
+ else
88
+ ProcFs.ruid(pid)
89
+ end
90
+ end
91
+
92
+ # Resolves the real user ID (RUID) of the given `pid` or its nearest ancestor where
93
+ # the RUID differs from the process's parent RUID.
94
+ #
95
+ # @param pid [Integer] the process ID for which to resolve the shallow RUID.
96
+ # @param pruid [Integer, nil] the parent process's RUID. Used to compare and stop if a difference is found.
97
+ # @return [Integer, nil] the RUID of the process or the nearest ancestor with a different RUID.
98
+ def self.shallow(pid, pruid = nil)
99
+ ruid = ProcFs.ruid(pid)
100
+ return ruid if pruid && (ruid != pruid || ruid.nil?)
101
+
102
+ ppid = ProcFs.ppid(pid)
103
+
104
+ # has parent and parent is not init
105
+ if ppid && ppid > 1
106
+ shallow(ppid, ruid)
107
+ else
108
+ ruid
109
+ end
110
+ end
111
+ end
112
+
113
+ # Determines the real user ID (RUID) of a process, either using a deep or shallow search.
114
+ # If a `Hash` is provided, the configuration specifies whether to perform a deep search.
115
+ #
116
+ # @param cfg [Integer, Hash] the process ID (Integer) or configuration Hash.
117
+ # - If an Integer is provided, a deep search is performed.
118
+ # - If a Hash is provided, it can contain:
119
+ # - `:pid` (Integer): the process ID to resolve. Defaults to the current process.
120
+ # - `:deep` (Boolean): whether to perform a deep search. Defaults to shallow.
121
+ # @return [Integer, nil] the real user ID of the process, or `nil` if it cannot be determined.
122
+ def self.ruid(cfg = Process.pid)
123
+ case cfg
124
+ when Integer
125
+ Resolver.deep(cfg)
126
+ when Hash
127
+ pid = cfg[:pid] || Process.pid
128
+ deep = cfg[:deep]
129
+ return Resolver.deep(pid) if deep
130
+
131
+ Resolver.shallow(pid)
132
+ end
133
+ end
134
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: realuser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Julian Kahlert
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: simplecov-cobertura
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '2.1'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.1'
33
+ - !ruby/object:Gem::Dependency
34
+ name: simplecov-console
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.9'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.9.1
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.9'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.9.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: simplecov
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.22'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.22.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.22'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.22.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: yard
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.9'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.9.37
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 0.9.37
93
+ - !ruby/object:Gem::Dependency
94
+ name: rspec
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '3'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '3.4'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '3.4'
113
+ description: The realuser gem provides a simple API for obtaining the real user ID
114
+ (RUID) of a process and its parent processes on Linux systems. It leverages the
115
+ `/proc` filesystem to perform deep and shallow resolution of RUIDs, making it useful
116
+ for process management and monitoring in Linux environments.
117
+ email:
118
+ - 90937526+juliankahlert@users.noreply.github.com
119
+ executables: []
120
+ extensions: []
121
+ extra_rdoc_files: []
122
+ files:
123
+ - LICENSE
124
+ - README.md
125
+ - lib/realuser.rb
126
+ homepage: https://github.com/juliankahlert/realuser
127
+ licenses:
128
+ - MIT
129
+ metadata:
130
+ homepage_uri: https://juliankahlert.github.io/realuser/
131
+ documentation_uri: https://www.rubydoc.info/gems/realuser/0.1.0
132
+ source_code_uri: https://github.com/juliankahlert/realuser
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: 3.0.0
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubygems_version: 3.2.33
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: Retrieve the real user ID (RUID) of a process and its parent processes.
152
+ test_files: []