etc 0.2.1
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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +18 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/etc.gemspec +41 -0
- data/ext/etc/etc.c +1205 -0
- data/ext/etc/extconf.rb +44 -0
- data/ext/etc/mkconstants.rb +332 -0
- data/test/etc/test_etc.rb +172 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8ae337119cdf0d4de924a5ead10fef45273f280a
|
4
|
+
data.tar.gz: 48d0f0864f628b37f55eb2e5cb49ab13564c9631
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a23eb4e20bd188cae18155adcbcd391310b74f623ec70ea4b92a0d79e4833f3a3c01495ce1d5a294e349a867c5440cfb789aae21850094a66aeb936cc63b341c
|
7
|
+
data.tar.gz: da3a5cee8c1f22a1c780d1d3a9fb83baa076f6a9bbb3fdb9d0adb9840004e251ea2593033ec9e94ba96d946410de26b6ca64130d02996ce3dc7a0a063b73a998
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
1. Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
15
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
16
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
17
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
18
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
19
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
20
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
21
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
22
|
+
SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Etc
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/etc`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'etc'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install etc
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/etc.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList['test/**/test_*.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
file("constdefs.h") do
|
11
|
+
`ruby ext/etc/mkconstants.rb -o ext/etc/constdefs.h`
|
12
|
+
end
|
13
|
+
|
14
|
+
require "rake/extensiontask"
|
15
|
+
Rake::ExtensionTask.new("etc")
|
16
|
+
task :compile => "constdefs.h".to_sym
|
17
|
+
|
18
|
+
task :default => :test
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "etc"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/etc.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "etc"
|
5
|
+
spec.version = "0.2.1"
|
6
|
+
spec.date = '2017-02-27'
|
7
|
+
spec.authors = ["Yukihiro Matsumoto"]
|
8
|
+
spec.email = ["matz@ruby-lang.org"]
|
9
|
+
|
10
|
+
spec.summary = %q{Provides access to information typically stored in UNIX /etc directory.}
|
11
|
+
spec.description = %q{Provides access to information typically stored in UNIX /etc directory.}
|
12
|
+
spec.homepage = "https://github.com/ruby/etc"
|
13
|
+
spec.license = "BSD-2-Clause"
|
14
|
+
|
15
|
+
spec.files = %w[
|
16
|
+
.gitignore
|
17
|
+
.travis.yml
|
18
|
+
Gemfile
|
19
|
+
LICENSE.txt
|
20
|
+
README.md
|
21
|
+
Rakefile
|
22
|
+
bin/console
|
23
|
+
bin/setup
|
24
|
+
etc.gemspec
|
25
|
+
ext/etc/etc.c
|
26
|
+
ext/etc/extconf.rb
|
27
|
+
ext/etc/mkconstants.rb
|
28
|
+
test/etc/test_etc.rb
|
29
|
+
]
|
30
|
+
spec.bindir = "exe"
|
31
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
+
spec.require_paths = ["lib"]
|
33
|
+
spec.extensions = %w{ext/etc/extconf.rb}
|
34
|
+
|
35
|
+
spec.required_ruby_version = ">= 2.5.0dev"
|
36
|
+
|
37
|
+
spec.add_development_dependency "bundler"
|
38
|
+
spec.add_development_dependency "rake"
|
39
|
+
spec.add_development_dependency "rake-compiler"
|
40
|
+
spec.add_development_dependency "test-unit"
|
41
|
+
end
|
data/ext/etc/etc.c
ADDED
@@ -0,0 +1,1205 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
etc.c -
|
4
|
+
|
5
|
+
$Author$
|
6
|
+
created at: Tue Mar 22 18:39:19 JST 1994
|
7
|
+
|
8
|
+
************************************************/
|
9
|
+
|
10
|
+
#include "ruby.h"
|
11
|
+
#include "ruby/encoding.h"
|
12
|
+
#include "ruby/io.h"
|
13
|
+
|
14
|
+
#include <sys/types.h>
|
15
|
+
#ifdef HAVE_UNISTD_H
|
16
|
+
#include <unistd.h>
|
17
|
+
#endif
|
18
|
+
|
19
|
+
#ifdef HAVE_GETPWENT
|
20
|
+
#include <pwd.h>
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#ifdef HAVE_GETGRENT
|
24
|
+
#include <grp.h>
|
25
|
+
#endif
|
26
|
+
|
27
|
+
#include <errno.h>
|
28
|
+
|
29
|
+
#ifdef HAVE_SYS_UTSNAME_H
|
30
|
+
#include <sys/utsname.h>
|
31
|
+
#endif
|
32
|
+
|
33
|
+
#ifdef HAVE_SCHED_GETAFFINITY
|
34
|
+
#include <sched.h>
|
35
|
+
#endif
|
36
|
+
|
37
|
+
static VALUE sPasswd;
|
38
|
+
#ifdef HAVE_GETGRENT
|
39
|
+
static VALUE sGroup;
|
40
|
+
#endif
|
41
|
+
|
42
|
+
#ifdef _WIN32
|
43
|
+
#include <shlobj.h>
|
44
|
+
#ifndef CSIDL_COMMON_APPDATA
|
45
|
+
#define CSIDL_COMMON_APPDATA 35
|
46
|
+
#endif
|
47
|
+
#define HAVE_UNAME 1
|
48
|
+
#endif
|
49
|
+
|
50
|
+
#ifndef _WIN32
|
51
|
+
char *getenv();
|
52
|
+
#endif
|
53
|
+
char *getlogin();
|
54
|
+
|
55
|
+
#include "constdefs.h"
|
56
|
+
|
57
|
+
/* call-seq:
|
58
|
+
* getlogin -> String
|
59
|
+
*
|
60
|
+
* Returns the short user name of the currently logged in user.
|
61
|
+
* Unfortunately, it is often rather easy to fool ::getlogin.
|
62
|
+
*
|
63
|
+
* Avoid ::getlogin for security-related purposes.
|
64
|
+
*
|
65
|
+
* If ::getlogin fails, try ::getpwuid.
|
66
|
+
*
|
67
|
+
* See the unix manpage for <code>getpwuid(3)</code> for more detail.
|
68
|
+
*
|
69
|
+
* e.g.
|
70
|
+
* Etc.getlogin -> 'guest'
|
71
|
+
*/
|
72
|
+
static VALUE
|
73
|
+
etc_getlogin(VALUE obj)
|
74
|
+
{
|
75
|
+
char *login;
|
76
|
+
|
77
|
+
#ifdef HAVE_GETLOGIN
|
78
|
+
login = getlogin();
|
79
|
+
if (!login) login = getenv("USER");
|
80
|
+
#else
|
81
|
+
login = getenv("USER");
|
82
|
+
#endif
|
83
|
+
|
84
|
+
if (login) {
|
85
|
+
#ifdef _WIN32
|
86
|
+
rb_encoding *extenc = rb_utf8_encoding();
|
87
|
+
#else
|
88
|
+
rb_encoding *extenc = rb_locale_encoding();
|
89
|
+
#endif
|
90
|
+
return rb_external_str_new_with_enc(login, strlen(login), extenc);
|
91
|
+
}
|
92
|
+
|
93
|
+
return Qnil;
|
94
|
+
}
|
95
|
+
|
96
|
+
#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
|
97
|
+
static VALUE
|
98
|
+
safe_setup_str(const char *str)
|
99
|
+
{
|
100
|
+
if (str == 0) str = "";
|
101
|
+
return rb_tainted_str_new2(str);
|
102
|
+
}
|
103
|
+
|
104
|
+
static VALUE
|
105
|
+
safe_setup_locale_str(const char *str)
|
106
|
+
{
|
107
|
+
if (str == 0) str = "";
|
108
|
+
return rb_locale_str_new_cstr(str);
|
109
|
+
}
|
110
|
+
|
111
|
+
static VALUE
|
112
|
+
safe_setup_filesystem_str(const char *str)
|
113
|
+
{
|
114
|
+
if (str == 0) str = "";
|
115
|
+
return rb_filesystem_str_new_cstr(str);
|
116
|
+
}
|
117
|
+
#endif
|
118
|
+
|
119
|
+
#ifdef HAVE_GETPWENT
|
120
|
+
static VALUE
|
121
|
+
setup_passwd(struct passwd *pwd)
|
122
|
+
{
|
123
|
+
if (pwd == 0) rb_sys_fail("/etc/passwd");
|
124
|
+
return rb_struct_new(sPasswd,
|
125
|
+
safe_setup_locale_str(pwd->pw_name),
|
126
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
|
127
|
+
safe_setup_str(pwd->pw_passwd),
|
128
|
+
#endif
|
129
|
+
UIDT2NUM(pwd->pw_uid),
|
130
|
+
GIDT2NUM(pwd->pw_gid),
|
131
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
|
132
|
+
safe_setup_locale_str(pwd->pw_gecos),
|
133
|
+
#endif
|
134
|
+
safe_setup_filesystem_str(pwd->pw_dir),
|
135
|
+
safe_setup_filesystem_str(pwd->pw_shell),
|
136
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
|
137
|
+
INT2NUM(pwd->pw_change),
|
138
|
+
#endif
|
139
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
|
140
|
+
INT2NUM(pwd->pw_quota),
|
141
|
+
#endif
|
142
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_AGE
|
143
|
+
PW_AGE2VAL(pwd->pw_age),
|
144
|
+
#endif
|
145
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
|
146
|
+
safe_setup_locale_str(pwd->pw_class),
|
147
|
+
#endif
|
148
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
|
149
|
+
safe_setup_locale_str(pwd->pw_comment),
|
150
|
+
#endif
|
151
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
|
152
|
+
INT2NUM(pwd->pw_expire),
|
153
|
+
#endif
|
154
|
+
0 /*dummy*/
|
155
|
+
);
|
156
|
+
}
|
157
|
+
#endif
|
158
|
+
|
159
|
+
/* call-seq:
|
160
|
+
* getpwuid(uid) -> Passwd
|
161
|
+
*
|
162
|
+
* Returns the /etc/passwd information for the user with the given integer +uid+.
|
163
|
+
*
|
164
|
+
* The information is returned as a Passwd struct.
|
165
|
+
*
|
166
|
+
* If +uid+ is omitted, the value from <code>Passwd[:uid]</code> is returned
|
167
|
+
* instead.
|
168
|
+
*
|
169
|
+
* See the unix manpage for <code>getpwuid(3)</code> for more detail.
|
170
|
+
*
|
171
|
+
* === Example:
|
172
|
+
*
|
173
|
+
* Etc.getpwuid(0)
|
174
|
+
* #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
|
175
|
+
*/
|
176
|
+
static VALUE
|
177
|
+
etc_getpwuid(int argc, VALUE *argv, VALUE obj)
|
178
|
+
{
|
179
|
+
#if defined(HAVE_GETPWENT)
|
180
|
+
VALUE id;
|
181
|
+
rb_uid_t uid;
|
182
|
+
struct passwd *pwd;
|
183
|
+
|
184
|
+
if (rb_scan_args(argc, argv, "01", &id) == 1) {
|
185
|
+
uid = NUM2UIDT(id);
|
186
|
+
}
|
187
|
+
else {
|
188
|
+
uid = getuid();
|
189
|
+
}
|
190
|
+
pwd = getpwuid(uid);
|
191
|
+
if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", (int)uid);
|
192
|
+
return setup_passwd(pwd);
|
193
|
+
#else
|
194
|
+
return Qnil;
|
195
|
+
#endif
|
196
|
+
}
|
197
|
+
|
198
|
+
/* call-seq:
|
199
|
+
* getpwnam(name) -> Passwd
|
200
|
+
*
|
201
|
+
* Returns the /etc/passwd information for the user with specified login
|
202
|
+
* +name+.
|
203
|
+
*
|
204
|
+
* The information is returned as a Passwd struct.
|
205
|
+
*
|
206
|
+
* See the unix manpage for <code>getpwnam(3)</code> for more detail.
|
207
|
+
*
|
208
|
+
* === Example:
|
209
|
+
*
|
210
|
+
* Etc.getpwnam('root')
|
211
|
+
* #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
|
212
|
+
*/
|
213
|
+
static VALUE
|
214
|
+
etc_getpwnam(VALUE obj, VALUE nam)
|
215
|
+
{
|
216
|
+
#ifdef HAVE_GETPWENT
|
217
|
+
struct passwd *pwd;
|
218
|
+
|
219
|
+
SafeStringValue(nam);
|
220
|
+
pwd = getpwnam(RSTRING_PTR(nam));
|
221
|
+
if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
|
222
|
+
return setup_passwd(pwd);
|
223
|
+
#else
|
224
|
+
return Qnil;
|
225
|
+
#endif
|
226
|
+
}
|
227
|
+
|
228
|
+
#ifdef HAVE_GETPWENT
|
229
|
+
static int passwd_blocking = 0;
|
230
|
+
static VALUE
|
231
|
+
passwd_ensure(void)
|
232
|
+
{
|
233
|
+
endpwent();
|
234
|
+
passwd_blocking = (int)Qfalse;
|
235
|
+
return Qnil;
|
236
|
+
}
|
237
|
+
|
238
|
+
static VALUE
|
239
|
+
passwd_iterate(void)
|
240
|
+
{
|
241
|
+
struct passwd *pw;
|
242
|
+
|
243
|
+
setpwent();
|
244
|
+
while ((pw = getpwent()) != 0) {
|
245
|
+
rb_yield(setup_passwd(pw));
|
246
|
+
}
|
247
|
+
return Qnil;
|
248
|
+
}
|
249
|
+
|
250
|
+
static void
|
251
|
+
each_passwd(void)
|
252
|
+
{
|
253
|
+
if (passwd_blocking) {
|
254
|
+
rb_raise(rb_eRuntimeError, "parallel passwd iteration");
|
255
|
+
}
|
256
|
+
passwd_blocking = (int)Qtrue;
|
257
|
+
rb_ensure(passwd_iterate, 0, passwd_ensure, 0);
|
258
|
+
}
|
259
|
+
#endif
|
260
|
+
|
261
|
+
/* call-seq:
|
262
|
+
* Etc.passwd { |struct| block } -> Passwd
|
263
|
+
* Etc.passwd -> Passwd
|
264
|
+
*
|
265
|
+
* Provides a convenient Ruby iterator which executes a block for each entry
|
266
|
+
* in the /etc/passwd file.
|
267
|
+
*
|
268
|
+
* The code block is passed an Passwd struct.
|
269
|
+
*
|
270
|
+
* See ::getpwent above for details.
|
271
|
+
*
|
272
|
+
* Example:
|
273
|
+
*
|
274
|
+
* require 'etc'
|
275
|
+
*
|
276
|
+
* Etc.passwd {|u|
|
277
|
+
* puts u.name + " = " + u.gecos
|
278
|
+
* }
|
279
|
+
*
|
280
|
+
*/
|
281
|
+
static VALUE
|
282
|
+
etc_passwd(VALUE obj)
|
283
|
+
{
|
284
|
+
#ifdef HAVE_GETPWENT
|
285
|
+
struct passwd *pw;
|
286
|
+
|
287
|
+
if (rb_block_given_p()) {
|
288
|
+
each_passwd();
|
289
|
+
}
|
290
|
+
else if ((pw = getpwent()) != 0) {
|
291
|
+
return setup_passwd(pw);
|
292
|
+
}
|
293
|
+
#endif
|
294
|
+
return Qnil;
|
295
|
+
}
|
296
|
+
|
297
|
+
/* call-seq:
|
298
|
+
* Etc::Passwd.each { |struct| block } -> Passwd
|
299
|
+
* Etc::Passwd.each -> Enumerator
|
300
|
+
*
|
301
|
+
* Iterates for each entry in the /etc/passwd file if a block is given.
|
302
|
+
*
|
303
|
+
* If no block is given, returns the Enumerator.
|
304
|
+
*
|
305
|
+
* The code block is passed an Passwd struct.
|
306
|
+
*
|
307
|
+
* See ::getpwent above for details.
|
308
|
+
*
|
309
|
+
* Example:
|
310
|
+
*
|
311
|
+
* require 'etc'
|
312
|
+
*
|
313
|
+
* Etc::Passwd.each {|u|
|
314
|
+
* puts u.name + " = " + u.gecos
|
315
|
+
* }
|
316
|
+
*
|
317
|
+
* Etc::Passwd.collect {|u| u.gecos}
|
318
|
+
* Etc::Passwd.collect {|u| u.gecos}
|
319
|
+
*
|
320
|
+
*/
|
321
|
+
static VALUE
|
322
|
+
etc_each_passwd(VALUE obj)
|
323
|
+
{
|
324
|
+
#ifdef HAVE_GETPWENT
|
325
|
+
RETURN_ENUMERATOR(obj, 0, 0);
|
326
|
+
each_passwd();
|
327
|
+
#endif
|
328
|
+
return obj;
|
329
|
+
}
|
330
|
+
|
331
|
+
/* Resets the process of reading the /etc/passwd file, so that the next call
|
332
|
+
* to ::getpwent will return the first entry again.
|
333
|
+
*/
|
334
|
+
static VALUE
|
335
|
+
etc_setpwent(VALUE obj)
|
336
|
+
{
|
337
|
+
#ifdef HAVE_GETPWENT
|
338
|
+
setpwent();
|
339
|
+
#endif
|
340
|
+
return Qnil;
|
341
|
+
}
|
342
|
+
|
343
|
+
/* Ends the process of scanning through the /etc/passwd file begun with
|
344
|
+
* ::getpwent, and closes the file.
|
345
|
+
*/
|
346
|
+
static VALUE
|
347
|
+
etc_endpwent(VALUE obj)
|
348
|
+
{
|
349
|
+
#ifdef HAVE_GETPWENT
|
350
|
+
endpwent();
|
351
|
+
#endif
|
352
|
+
return Qnil;
|
353
|
+
}
|
354
|
+
|
355
|
+
/* Returns an entry from the /etc/passwd file.
|
356
|
+
*
|
357
|
+
* The first time it is called it opens the file and returns the first entry;
|
358
|
+
* each successive call returns the next entry, or +nil+ if the end of the file
|
359
|
+
* has been reached.
|
360
|
+
*
|
361
|
+
* To close the file when processing is complete, call ::endpwent.
|
362
|
+
*
|
363
|
+
* Each entry is returned as a Passwd struct.
|
364
|
+
*
|
365
|
+
*/
|
366
|
+
static VALUE
|
367
|
+
etc_getpwent(VALUE obj)
|
368
|
+
{
|
369
|
+
#ifdef HAVE_GETPWENT
|
370
|
+
struct passwd *pw;
|
371
|
+
|
372
|
+
if ((pw = getpwent()) != 0) {
|
373
|
+
return setup_passwd(pw);
|
374
|
+
}
|
375
|
+
#endif
|
376
|
+
return Qnil;
|
377
|
+
}
|
378
|
+
|
379
|
+
#ifdef HAVE_GETGRENT
|
380
|
+
static VALUE
|
381
|
+
setup_group(struct group *grp)
|
382
|
+
{
|
383
|
+
VALUE mem;
|
384
|
+
char **tbl;
|
385
|
+
|
386
|
+
mem = rb_ary_new();
|
387
|
+
tbl = grp->gr_mem;
|
388
|
+
while (*tbl) {
|
389
|
+
rb_ary_push(mem, safe_setup_locale_str(*tbl));
|
390
|
+
tbl++;
|
391
|
+
}
|
392
|
+
return rb_struct_new(sGroup,
|
393
|
+
safe_setup_locale_str(grp->gr_name),
|
394
|
+
#ifdef HAVE_STRUCT_GROUP_GR_PASSWD
|
395
|
+
safe_setup_str(grp->gr_passwd),
|
396
|
+
#endif
|
397
|
+
GIDT2NUM(grp->gr_gid),
|
398
|
+
mem);
|
399
|
+
}
|
400
|
+
#endif
|
401
|
+
|
402
|
+
/* call-seq:
|
403
|
+
* getgrgid(group_id) -> Group
|
404
|
+
*
|
405
|
+
* Returns information about the group with specified integer +group_id+,
|
406
|
+
* as found in /etc/group.
|
407
|
+
*
|
408
|
+
* The information is returned as a Group struct.
|
409
|
+
*
|
410
|
+
* See the unix manpage for <code>getgrgid(3)</code> for more detail.
|
411
|
+
*
|
412
|
+
* === Example:
|
413
|
+
*
|
414
|
+
* Etc.getgrgid(100)
|
415
|
+
* #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
|
416
|
+
*
|
417
|
+
*/
|
418
|
+
static VALUE
|
419
|
+
etc_getgrgid(int argc, VALUE *argv, VALUE obj)
|
420
|
+
{
|
421
|
+
#ifdef HAVE_GETGRENT
|
422
|
+
VALUE id;
|
423
|
+
gid_t gid;
|
424
|
+
struct group *grp;
|
425
|
+
|
426
|
+
if (rb_scan_args(argc, argv, "01", &id) == 1) {
|
427
|
+
gid = NUM2GIDT(id);
|
428
|
+
}
|
429
|
+
else {
|
430
|
+
gid = getgid();
|
431
|
+
}
|
432
|
+
grp = getgrgid(gid);
|
433
|
+
if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", (int)gid);
|
434
|
+
return setup_group(grp);
|
435
|
+
#else
|
436
|
+
return Qnil;
|
437
|
+
#endif
|
438
|
+
}
|
439
|
+
|
440
|
+
/* call-seq:
|
441
|
+
* getgrnam(name) -> Group
|
442
|
+
*
|
443
|
+
* Returns information about the group with specified +name+, as found in
|
444
|
+
* /etc/group.
|
445
|
+
*
|
446
|
+
* The information is returned as a Group struct.
|
447
|
+
*
|
448
|
+
* See the unix manpage for <code>getgrnam(3)</code> for more detail.
|
449
|
+
*
|
450
|
+
* === Example:
|
451
|
+
*
|
452
|
+
* Etc.getgrnam('users')
|
453
|
+
* #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
|
454
|
+
*
|
455
|
+
*/
|
456
|
+
static VALUE
|
457
|
+
etc_getgrnam(VALUE obj, VALUE nam)
|
458
|
+
{
|
459
|
+
#ifdef HAVE_GETGRENT
|
460
|
+
struct group *grp;
|
461
|
+
|
462
|
+
SafeStringValue(nam);
|
463
|
+
grp = getgrnam(RSTRING_PTR(nam));
|
464
|
+
if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
|
465
|
+
return setup_group(grp);
|
466
|
+
#else
|
467
|
+
return Qnil;
|
468
|
+
#endif
|
469
|
+
}
|
470
|
+
|
471
|
+
#ifdef HAVE_GETGRENT
|
472
|
+
static int group_blocking = 0;
|
473
|
+
static VALUE
|
474
|
+
group_ensure(void)
|
475
|
+
{
|
476
|
+
endgrent();
|
477
|
+
group_blocking = (int)Qfalse;
|
478
|
+
return Qnil;
|
479
|
+
}
|
480
|
+
|
481
|
+
|
482
|
+
static VALUE
|
483
|
+
group_iterate(void)
|
484
|
+
{
|
485
|
+
struct group *pw;
|
486
|
+
|
487
|
+
setgrent();
|
488
|
+
while ((pw = getgrent()) != 0) {
|
489
|
+
rb_yield(setup_group(pw));
|
490
|
+
}
|
491
|
+
return Qnil;
|
492
|
+
}
|
493
|
+
|
494
|
+
static void
|
495
|
+
each_group(void)
|
496
|
+
{
|
497
|
+
if (group_blocking) {
|
498
|
+
rb_raise(rb_eRuntimeError, "parallel group iteration");
|
499
|
+
}
|
500
|
+
group_blocking = (int)Qtrue;
|
501
|
+
rb_ensure(group_iterate, 0, group_ensure, 0);
|
502
|
+
}
|
503
|
+
#endif
|
504
|
+
|
505
|
+
/* Provides a convenient Ruby iterator which executes a block for each entry
|
506
|
+
* in the /etc/group file.
|
507
|
+
*
|
508
|
+
* The code block is passed an Group struct.
|
509
|
+
*
|
510
|
+
* See ::getgrent above for details.
|
511
|
+
*
|
512
|
+
* Example:
|
513
|
+
*
|
514
|
+
* require 'etc'
|
515
|
+
*
|
516
|
+
* Etc.group {|g|
|
517
|
+
* puts g.name + ": " + g.mem.join(', ')
|
518
|
+
* }
|
519
|
+
*
|
520
|
+
*/
|
521
|
+
static VALUE
|
522
|
+
etc_group(VALUE obj)
|
523
|
+
{
|
524
|
+
#ifdef HAVE_GETGRENT
|
525
|
+
struct group *grp;
|
526
|
+
|
527
|
+
if (rb_block_given_p()) {
|
528
|
+
each_group();
|
529
|
+
}
|
530
|
+
else if ((grp = getgrent()) != 0) {
|
531
|
+
return setup_group(grp);
|
532
|
+
}
|
533
|
+
#endif
|
534
|
+
return Qnil;
|
535
|
+
}
|
536
|
+
|
537
|
+
#ifdef HAVE_GETGRENT
|
538
|
+
/* call-seq:
|
539
|
+
* Etc::Group.each { |group| block } -> obj
|
540
|
+
* Etc::Group.each -> Enumerator
|
541
|
+
*
|
542
|
+
* Iterates for each entry in the /etc/group file if a block is given.
|
543
|
+
*
|
544
|
+
* If no block is given, returns the Enumerator.
|
545
|
+
*
|
546
|
+
* The code block is passed a Group struct.
|
547
|
+
*
|
548
|
+
* Example:
|
549
|
+
*
|
550
|
+
* require 'etc'
|
551
|
+
*
|
552
|
+
* Etc::Group.each {|g|
|
553
|
+
* puts g.name + ": " + g.mem.join(', ')
|
554
|
+
* }
|
555
|
+
*
|
556
|
+
* Etc::Group.collect {|g| g.name}
|
557
|
+
* Etc::Group.select {|g| !g.mem.empty?}
|
558
|
+
*
|
559
|
+
*/
|
560
|
+
static VALUE
|
561
|
+
etc_each_group(VALUE obj)
|
562
|
+
{
|
563
|
+
RETURN_ENUMERATOR(obj, 0, 0);
|
564
|
+
each_group();
|
565
|
+
return obj;
|
566
|
+
}
|
567
|
+
#endif
|
568
|
+
|
569
|
+
/* Resets the process of reading the /etc/group file, so that the next call
|
570
|
+
* to ::getgrent will return the first entry again.
|
571
|
+
*/
|
572
|
+
static VALUE
|
573
|
+
etc_setgrent(VALUE obj)
|
574
|
+
{
|
575
|
+
#ifdef HAVE_GETGRENT
|
576
|
+
setgrent();
|
577
|
+
#endif
|
578
|
+
return Qnil;
|
579
|
+
}
|
580
|
+
|
581
|
+
/* Ends the process of scanning through the /etc/group file begun by
|
582
|
+
* ::getgrent, and closes the file.
|
583
|
+
*/
|
584
|
+
static VALUE
|
585
|
+
etc_endgrent(VALUE obj)
|
586
|
+
{
|
587
|
+
#ifdef HAVE_GETGRENT
|
588
|
+
endgrent();
|
589
|
+
#endif
|
590
|
+
return Qnil;
|
591
|
+
}
|
592
|
+
|
593
|
+
/* Returns an entry from the /etc/group file.
|
594
|
+
*
|
595
|
+
* The first time it is called it opens the file and returns the first entry;
|
596
|
+
* each successive call returns the next entry, or +nil+ if the end of the file
|
597
|
+
* has been reached.
|
598
|
+
*
|
599
|
+
* To close the file when processing is complete, call ::endgrent.
|
600
|
+
*
|
601
|
+
* Each entry is returned as a Group struct
|
602
|
+
*/
|
603
|
+
static VALUE
|
604
|
+
etc_getgrent(VALUE obj)
|
605
|
+
{
|
606
|
+
#ifdef HAVE_GETGRENT
|
607
|
+
struct group *gr;
|
608
|
+
|
609
|
+
if ((gr = getgrent()) != 0) {
|
610
|
+
return setup_group(gr);
|
611
|
+
}
|
612
|
+
#endif
|
613
|
+
return Qnil;
|
614
|
+
}
|
615
|
+
|
616
|
+
#define numberof(array) (sizeof(array) / sizeof(*(array)))
|
617
|
+
|
618
|
+
#ifdef _WIN32
|
619
|
+
VALUE rb_w32_special_folder(int type);
|
620
|
+
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
|
621
|
+
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
|
622
|
+
#endif
|
623
|
+
|
624
|
+
/*
|
625
|
+
* Returns system configuration directory.
|
626
|
+
*
|
627
|
+
* This is typically "/etc", but is modified by the prefix used when Ruby was
|
628
|
+
* compiled. For example, if Ruby is built and installed in /usr/local, returns
|
629
|
+
* "/usr/local/etc".
|
630
|
+
*/
|
631
|
+
static VALUE
|
632
|
+
etc_sysconfdir(VALUE obj)
|
633
|
+
{
|
634
|
+
#ifdef _WIN32
|
635
|
+
return rb_w32_special_folder(CSIDL_COMMON_APPDATA);
|
636
|
+
#else
|
637
|
+
return rb_filesystem_str_new_cstr(SYSCONFDIR);
|
638
|
+
#endif
|
639
|
+
}
|
640
|
+
|
641
|
+
/*
|
642
|
+
* Returns system temporary directory; typically "/tmp".
|
643
|
+
*/
|
644
|
+
static VALUE
|
645
|
+
etc_systmpdir(void)
|
646
|
+
{
|
647
|
+
VALUE tmpdir;
|
648
|
+
#ifdef _WIN32
|
649
|
+
WCHAR path[_MAX_PATH];
|
650
|
+
UINT len = rb_w32_system_tmpdir(path, numberof(path));
|
651
|
+
if (!len) return Qnil;
|
652
|
+
tmpdir = rb_w32_conv_from_wchar(path, rb_filesystem_encoding());
|
653
|
+
#else
|
654
|
+
const char default_tmp[] = "/tmp";
|
655
|
+
const char *tmpstr = default_tmp;
|
656
|
+
size_t tmplen = strlen(default_tmp);
|
657
|
+
# if defined _CS_DARWIN_USER_TEMP_DIR
|
658
|
+
#ifndef MAXPATHLEN
|
659
|
+
#define MAXPATHLEN 1024
|
660
|
+
#endif
|
661
|
+
char path[MAXPATHLEN];
|
662
|
+
size_t len;
|
663
|
+
len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
|
664
|
+
if (len > 0) {
|
665
|
+
tmpstr = path;
|
666
|
+
tmplen = len - 1;
|
667
|
+
if (len > sizeof(path)) tmpstr = 0;
|
668
|
+
}
|
669
|
+
# endif
|
670
|
+
tmpdir = rb_filesystem_str_new(tmpstr, tmplen);
|
671
|
+
# if defined _CS_DARWIN_USER_TEMP_DIR
|
672
|
+
if (!tmpstr) {
|
673
|
+
confstr(_CS_DARWIN_USER_TEMP_DIR, RSTRING_PTR(tmpdir), len);
|
674
|
+
}
|
675
|
+
# endif
|
676
|
+
#endif
|
677
|
+
FL_UNSET(tmpdir, FL_TAINT);
|
678
|
+
return tmpdir;
|
679
|
+
}
|
680
|
+
|
681
|
+
#ifdef HAVE_UNAME
|
682
|
+
/*
|
683
|
+
* Returns the system information obtained by uname system call.
|
684
|
+
*
|
685
|
+
* The return value is a hash which has 5 keys at least:
|
686
|
+
* :sysname, :nodename, :release, :version, :machine
|
687
|
+
*
|
688
|
+
* Example:
|
689
|
+
*
|
690
|
+
* require 'etc'
|
691
|
+
* require 'pp'
|
692
|
+
*
|
693
|
+
* pp Etc.uname
|
694
|
+
* #=> {:sysname=>"Linux",
|
695
|
+
* # :nodename=>"boron",
|
696
|
+
* # :release=>"2.6.18-6-xen-686",
|
697
|
+
* # :version=>"#1 SMP Thu Nov 5 19:54:42 UTC 2009",
|
698
|
+
* # :machine=>"i686"}
|
699
|
+
*
|
700
|
+
*/
|
701
|
+
static VALUE
|
702
|
+
etc_uname(VALUE obj)
|
703
|
+
{
|
704
|
+
#ifdef _WIN32
|
705
|
+
OSVERSIONINFOW v;
|
706
|
+
SYSTEM_INFO s;
|
707
|
+
const char *sysname, *mach;
|
708
|
+
VALUE result, release, version;
|
709
|
+
VALUE vbuf, nodename = Qnil;
|
710
|
+
DWORD len = 0;
|
711
|
+
WCHAR *buf;
|
712
|
+
|
713
|
+
v.dwOSVersionInfoSize = sizeof(v);
|
714
|
+
if (!GetVersionExW(&v))
|
715
|
+
rb_sys_fail("GetVersionEx");
|
716
|
+
|
717
|
+
result = rb_hash_new();
|
718
|
+
switch (v.dwPlatformId) {
|
719
|
+
case VER_PLATFORM_WIN32s:
|
720
|
+
sysname = "Win32s";
|
721
|
+
break;
|
722
|
+
case VER_PLATFORM_WIN32_NT:
|
723
|
+
sysname = "Windows_NT";
|
724
|
+
break;
|
725
|
+
case VER_PLATFORM_WIN32_WINDOWS:
|
726
|
+
default:
|
727
|
+
sysname = "Windows";
|
728
|
+
break;
|
729
|
+
}
|
730
|
+
rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(sysname));
|
731
|
+
release = rb_sprintf("%lu.%lu.%lu", v.dwMajorVersion, v.dwMinorVersion, v.dwBuildNumber);
|
732
|
+
rb_hash_aset(result, ID2SYM(rb_intern("release")), release);
|
733
|
+
version = rb_sprintf("%s Version %"PRIsVALUE": %"PRIsVALUE, sysname, release,
|
734
|
+
rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding()));
|
735
|
+
rb_hash_aset(result, ID2SYM(rb_intern("version")), version);
|
736
|
+
|
737
|
+
# if defined _MSC_VER && _MSC_VER < 1300
|
738
|
+
# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen)
|
739
|
+
# else
|
740
|
+
# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen)
|
741
|
+
# endif
|
742
|
+
GET_COMPUTER_NAME(NULL, &len);
|
743
|
+
buf = ALLOCV_N(WCHAR, vbuf, len);
|
744
|
+
if (GET_COMPUTER_NAME(buf, &len)) {
|
745
|
+
nodename = rb_w32_conv_from_wchar(buf, rb_utf8_encoding());
|
746
|
+
}
|
747
|
+
ALLOCV_END(vbuf);
|
748
|
+
if (NIL_P(nodename)) nodename = rb_str_new(0, 0);
|
749
|
+
rb_hash_aset(result, ID2SYM(rb_intern("nodename")), nodename);
|
750
|
+
|
751
|
+
# ifndef PROCESSOR_ARCHITECTURE_AMD64
|
752
|
+
# define PROCESSOR_ARCHITECTURE_AMD64 9
|
753
|
+
# endif
|
754
|
+
# ifndef PROCESSOR_ARCHITECTURE_IA64
|
755
|
+
# define PROCESSOR_ARCHITECTURE_IA64 6
|
756
|
+
# endif
|
757
|
+
# ifndef PROCESSOR_ARCHITECTURE_INTEL
|
758
|
+
# define PROCESSOR_ARCHITECTURE_INTEL 0
|
759
|
+
# endif
|
760
|
+
GetSystemInfo(&s);
|
761
|
+
switch (s.wProcessorArchitecture) {
|
762
|
+
case PROCESSOR_ARCHITECTURE_AMD64:
|
763
|
+
mach = "x64";
|
764
|
+
break;
|
765
|
+
case PROCESSOR_ARCHITECTURE_ARM:
|
766
|
+
mach = "ARM";
|
767
|
+
break;
|
768
|
+
case PROCESSOR_ARCHITECTURE_IA64:
|
769
|
+
mach = "IA64";
|
770
|
+
break;
|
771
|
+
case PROCESSOR_ARCHITECTURE_INTEL:
|
772
|
+
mach = "x86";
|
773
|
+
break;
|
774
|
+
default:
|
775
|
+
mach = "unknown";
|
776
|
+
break;
|
777
|
+
}
|
778
|
+
|
779
|
+
rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(mach));
|
780
|
+
#else
|
781
|
+
struct utsname u;
|
782
|
+
int ret;
|
783
|
+
VALUE result;
|
784
|
+
|
785
|
+
ret = uname(&u);
|
786
|
+
if (ret == -1)
|
787
|
+
rb_sys_fail("uname");
|
788
|
+
|
789
|
+
result = rb_hash_new();
|
790
|
+
rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(u.sysname));
|
791
|
+
rb_hash_aset(result, ID2SYM(rb_intern("nodename")), rb_str_new_cstr(u.nodename));
|
792
|
+
rb_hash_aset(result, ID2SYM(rb_intern("release")), rb_str_new_cstr(u.release));
|
793
|
+
rb_hash_aset(result, ID2SYM(rb_intern("version")), rb_str_new_cstr(u.version));
|
794
|
+
rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(u.machine));
|
795
|
+
#endif
|
796
|
+
|
797
|
+
return result;
|
798
|
+
}
|
799
|
+
#else
|
800
|
+
#define etc_uname rb_f_notimplement
|
801
|
+
#endif
|
802
|
+
|
803
|
+
#ifdef HAVE_SYSCONF
|
804
|
+
/*
|
805
|
+
* Returns system configuration variable using sysconf().
|
806
|
+
*
|
807
|
+
* _name_ should be a constant under <code>Etc</code> which begins with <code>SC_</code>.
|
808
|
+
*
|
809
|
+
* The return value is an integer or nil.
|
810
|
+
* nil means indefinite limit. (sysconf() returns -1 but errno is not set.)
|
811
|
+
*
|
812
|
+
* Etc.sysconf(Etc::SC_ARG_MAX) #=> 2097152
|
813
|
+
* Etc.sysconf(Etc::SC_LOGIN_NAME_MAX) #=> 256
|
814
|
+
*
|
815
|
+
*/
|
816
|
+
static VALUE
|
817
|
+
etc_sysconf(VALUE obj, VALUE arg)
|
818
|
+
{
|
819
|
+
int name;
|
820
|
+
long ret;
|
821
|
+
|
822
|
+
name = NUM2INT(arg);
|
823
|
+
|
824
|
+
errno = 0;
|
825
|
+
ret = sysconf(name);
|
826
|
+
if (ret == -1) {
|
827
|
+
if (errno == 0) /* no limit */
|
828
|
+
return Qnil;
|
829
|
+
rb_sys_fail("sysconf");
|
830
|
+
}
|
831
|
+
return LONG2NUM(ret);
|
832
|
+
}
|
833
|
+
#else
|
834
|
+
#define etc_sysconf rb_f_notimplement
|
835
|
+
#endif
|
836
|
+
|
837
|
+
#ifdef HAVE_CONFSTR
|
838
|
+
/*
|
839
|
+
* Returns system configuration variable using confstr().
|
840
|
+
*
|
841
|
+
* _name_ should be a constant under <code>Etc</code> which begins with <code>CS_</code>.
|
842
|
+
*
|
843
|
+
* The return value is a string or nil.
|
844
|
+
* nil means no configuration-defined value. (confstr() returns 0 but errno is not set.)
|
845
|
+
*
|
846
|
+
* Etc.confstr(Etc::CS_PATH) #=> "/bin:/usr/bin"
|
847
|
+
*
|
848
|
+
* # GNU/Linux
|
849
|
+
* Etc.confstr(Etc::CS_GNU_LIBC_VERSION) #=> "glibc 2.18"
|
850
|
+
* Etc.confstr(Etc::CS_GNU_LIBPTHREAD_VERSION) #=> "NPTL 2.18"
|
851
|
+
*
|
852
|
+
*/
|
853
|
+
static VALUE
|
854
|
+
etc_confstr(VALUE obj, VALUE arg)
|
855
|
+
{
|
856
|
+
int name;
|
857
|
+
char localbuf[128], *buf = localbuf;
|
858
|
+
size_t bufsize = sizeof(localbuf), ret;
|
859
|
+
VALUE tmp;
|
860
|
+
|
861
|
+
name = NUM2INT(arg);
|
862
|
+
|
863
|
+
errno = 0;
|
864
|
+
ret = confstr(name, buf, bufsize);
|
865
|
+
if (bufsize < ret) {
|
866
|
+
bufsize = ret;
|
867
|
+
buf = ALLOCV_N(char, tmp, bufsize);
|
868
|
+
errno = 0;
|
869
|
+
ret = confstr(name, buf, bufsize);
|
870
|
+
}
|
871
|
+
if (bufsize < ret)
|
872
|
+
rb_bug("required buffer size for confstr() changed dynamically.");
|
873
|
+
if (ret == 0) {
|
874
|
+
if (errno == 0) /* no configuration-defined value */
|
875
|
+
return Qnil;
|
876
|
+
rb_sys_fail("confstr");
|
877
|
+
}
|
878
|
+
return rb_str_new_cstr(buf);
|
879
|
+
}
|
880
|
+
#else
|
881
|
+
#define etc_confstr rb_f_notimplement
|
882
|
+
#endif
|
883
|
+
|
884
|
+
#ifdef HAVE_FPATHCONF
|
885
|
+
/*
|
886
|
+
* Returns pathname configuration variable using fpathconf().
|
887
|
+
*
|
888
|
+
* _name_ should be a constant under <code>Etc</code> which begins with <code>PC_</code>.
|
889
|
+
*
|
890
|
+
* The return value is an integer or nil.
|
891
|
+
* nil means indefinite limit. (fpathconf() returns -1 but errno is not set.)
|
892
|
+
*
|
893
|
+
* require 'etc'
|
894
|
+
* IO.pipe {|r, w|
|
895
|
+
* p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
|
896
|
+
* }
|
897
|
+
*
|
898
|
+
*/
|
899
|
+
static VALUE
|
900
|
+
io_pathconf(VALUE io, VALUE arg)
|
901
|
+
{
|
902
|
+
int name;
|
903
|
+
long ret;
|
904
|
+
rb_io_t *fptr;
|
905
|
+
|
906
|
+
name = NUM2INT(arg);
|
907
|
+
|
908
|
+
GetOpenFile(io, fptr);
|
909
|
+
|
910
|
+
errno = 0;
|
911
|
+
ret = fpathconf(fptr->fd, name);
|
912
|
+
if (ret == -1) {
|
913
|
+
if (errno == 0) /* no limit */
|
914
|
+
return Qnil;
|
915
|
+
rb_sys_fail("fpathconf");
|
916
|
+
}
|
917
|
+
return LONG2NUM(ret);
|
918
|
+
}
|
919
|
+
#else
|
920
|
+
#define io_pathconf rb_f_notimplement
|
921
|
+
#endif
|
922
|
+
|
923
|
+
#if (defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)) || defined(_WIN32)
|
924
|
+
|
925
|
+
#if defined(HAVE_SCHED_GETAFFINITY) && defined(CPU_ALLOC)
|
926
|
+
static int
|
927
|
+
etc_nprocessors_affin(void)
|
928
|
+
{
|
929
|
+
cpu_set_t *cpuset;
|
930
|
+
size_t size;
|
931
|
+
int ret;
|
932
|
+
int n;
|
933
|
+
|
934
|
+
/*
|
935
|
+
* XXX:
|
936
|
+
* man page says CPU_ALLOC takes number of cpus. But it is not accurate
|
937
|
+
* explanation. sched_getaffinity() returns EINVAL if cpuset bitmap is
|
938
|
+
* smaller than kernel internal bitmap.
|
939
|
+
* That said, sched_getaffinity() can fail when a kernel have sparse bitmap
|
940
|
+
* even if cpuset bitmap is larger than number of cpus.
|
941
|
+
* The precious way is to use /sys/devices/system/cpu/online. But there are
|
942
|
+
* two problems,
|
943
|
+
* - Costly calculation
|
944
|
+
* It is a minor issue, but possibly kill a benefit of a parallel processing.
|
945
|
+
* - No guarantee to exist /sys/devices/system/cpu/online
|
946
|
+
* This is an issue especially when using Linux containers.
|
947
|
+
* So, we use hardcode number for a workaround. Current linux kernel
|
948
|
+
* (Linux 3.17) support 8192 cpus at maximum. Then 16384 must be enough.
|
949
|
+
*/
|
950
|
+
for (n=64; n <= 16384; n *= 2) {
|
951
|
+
size = CPU_ALLOC_SIZE(n);
|
952
|
+
if (size >= 1024) {
|
953
|
+
cpuset = xcalloc(1, size);
|
954
|
+
if (!cpuset)
|
955
|
+
return -1;
|
956
|
+
} else {
|
957
|
+
cpuset = alloca(size);
|
958
|
+
CPU_ZERO_S(size, cpuset);
|
959
|
+
}
|
960
|
+
|
961
|
+
ret = sched_getaffinity(0, size, cpuset);
|
962
|
+
if (ret == 0) {
|
963
|
+
/* On success, count number of cpus. */
|
964
|
+
ret = CPU_COUNT_S(size, cpuset);
|
965
|
+
}
|
966
|
+
|
967
|
+
if (size >= 1024) {
|
968
|
+
xfree(cpuset);
|
969
|
+
}
|
970
|
+
if (ret > 0) {
|
971
|
+
return ret;
|
972
|
+
}
|
973
|
+
}
|
974
|
+
|
975
|
+
return ret;
|
976
|
+
}
|
977
|
+
#endif
|
978
|
+
|
979
|
+
/*
|
980
|
+
* Returns the number of online processors.
|
981
|
+
*
|
982
|
+
* The result is intended as the number of processes to
|
983
|
+
* use all available processors.
|
984
|
+
*
|
985
|
+
* This method is implemented using:
|
986
|
+
* - sched_getaffinity(): Linux
|
987
|
+
* - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX
|
988
|
+
*
|
989
|
+
* Example:
|
990
|
+
*
|
991
|
+
* require 'etc'
|
992
|
+
* p Etc.nprocessors #=> 4
|
993
|
+
*
|
994
|
+
* The result might be smaller number than physical cpus especially when ruby
|
995
|
+
* process is bound to specific cpus. This is intended for getting better
|
996
|
+
* parallel processing.
|
997
|
+
*
|
998
|
+
* Example: (Linux)
|
999
|
+
*
|
1000
|
+
* linux$ taskset 0x3 ./ruby -retc -e "p Etc.nprocessors" #=> 2
|
1001
|
+
*
|
1002
|
+
*/
|
1003
|
+
static VALUE
|
1004
|
+
etc_nprocessors(VALUE obj)
|
1005
|
+
{
|
1006
|
+
long ret;
|
1007
|
+
|
1008
|
+
#if !defined(_WIN32)
|
1009
|
+
|
1010
|
+
#if defined(HAVE_SCHED_GETAFFINITY) && defined(CPU_ALLOC)
|
1011
|
+
int ncpus;
|
1012
|
+
|
1013
|
+
ncpus = etc_nprocessors_affin();
|
1014
|
+
if (ncpus != -1) {
|
1015
|
+
return INT2NUM(ncpus);
|
1016
|
+
}
|
1017
|
+
/* fallback to _SC_NPROCESSORS_ONLN */
|
1018
|
+
#endif
|
1019
|
+
|
1020
|
+
errno = 0;
|
1021
|
+
ret = sysconf(_SC_NPROCESSORS_ONLN);
|
1022
|
+
if (ret == -1) {
|
1023
|
+
rb_sys_fail("sysconf(_SC_NPROCESSORS_ONLN)");
|
1024
|
+
}
|
1025
|
+
#else
|
1026
|
+
SYSTEM_INFO si;
|
1027
|
+
GetSystemInfo(&si);
|
1028
|
+
ret = (long)si.dwNumberOfProcessors;
|
1029
|
+
#endif
|
1030
|
+
return LONG2NUM(ret);
|
1031
|
+
}
|
1032
|
+
#else
|
1033
|
+
#define etc_nprocessors rb_f_notimplement
|
1034
|
+
#endif
|
1035
|
+
|
1036
|
+
/*
|
1037
|
+
* The Etc module provides access to information typically stored in
|
1038
|
+
* files in the /etc directory on Unix systems.
|
1039
|
+
*
|
1040
|
+
* The information accessible consists of the information found in the
|
1041
|
+
* /etc/passwd and /etc/group files, plus information about the system's
|
1042
|
+
* temporary directory (/tmp) and configuration directory (/etc).
|
1043
|
+
*
|
1044
|
+
* The Etc module provides a more reliable way to access information about
|
1045
|
+
* the logged in user than environment variables such as +$USER+.
|
1046
|
+
*
|
1047
|
+
* == Example:
|
1048
|
+
*
|
1049
|
+
* require 'etc'
|
1050
|
+
*
|
1051
|
+
* login = Etc.getlogin
|
1052
|
+
* info = Etc.getpwnam(login)
|
1053
|
+
* username = info.gecos.split(/,/).first
|
1054
|
+
* puts "Hello #{username}, I see your login name is #{login}"
|
1055
|
+
*
|
1056
|
+
* Note that the methods provided by this module are not always secure.
|
1057
|
+
* It should be used for informational purposes, and not for security.
|
1058
|
+
*
|
1059
|
+
* All operations defined in this module are class methods, so that you can
|
1060
|
+
* include the Etc module into your class.
|
1061
|
+
*/
|
1062
|
+
void
|
1063
|
+
Init_etc(void)
|
1064
|
+
{
|
1065
|
+
VALUE mEtc;
|
1066
|
+
|
1067
|
+
mEtc = rb_define_module("Etc");
|
1068
|
+
init_constants(mEtc);
|
1069
|
+
|
1070
|
+
rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
|
1071
|
+
|
1072
|
+
rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
|
1073
|
+
rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
|
1074
|
+
rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
|
1075
|
+
rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
|
1076
|
+
rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
|
1077
|
+
rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
|
1078
|
+
|
1079
|
+
rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, -1);
|
1080
|
+
rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
|
1081
|
+
rb_define_module_function(mEtc, "group", etc_group, 0);
|
1082
|
+
rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
|
1083
|
+
rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
|
1084
|
+
rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
|
1085
|
+
rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
|
1086
|
+
rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
|
1087
|
+
rb_define_module_function(mEtc, "uname", etc_uname, 0);
|
1088
|
+
rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1);
|
1089
|
+
rb_define_module_function(mEtc, "confstr", etc_confstr, 1);
|
1090
|
+
rb_define_method(rb_cIO, "pathconf", io_pathconf, 1);
|
1091
|
+
rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0);
|
1092
|
+
|
1093
|
+
sPasswd = rb_struct_define_under(mEtc, "Passwd",
|
1094
|
+
"name",
|
1095
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
|
1096
|
+
"passwd",
|
1097
|
+
#endif
|
1098
|
+
"uid",
|
1099
|
+
"gid",
|
1100
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
|
1101
|
+
"gecos",
|
1102
|
+
#endif
|
1103
|
+
"dir",
|
1104
|
+
"shell",
|
1105
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
|
1106
|
+
"change",
|
1107
|
+
#endif
|
1108
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
|
1109
|
+
"quota",
|
1110
|
+
#endif
|
1111
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_AGE
|
1112
|
+
"age",
|
1113
|
+
#endif
|
1114
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
|
1115
|
+
"uclass",
|
1116
|
+
#endif
|
1117
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
|
1118
|
+
"comment",
|
1119
|
+
#endif
|
1120
|
+
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
|
1121
|
+
"expire",
|
1122
|
+
#endif
|
1123
|
+
NULL);
|
1124
|
+
#if 0
|
1125
|
+
/* Define-const: Passwd
|
1126
|
+
*
|
1127
|
+
* Passwd is a Struct that contains the following members:
|
1128
|
+
*
|
1129
|
+
* name::
|
1130
|
+
* contains the short login name of the user as a String.
|
1131
|
+
* passwd::
|
1132
|
+
* contains the encrypted password of the user as a String.
|
1133
|
+
* an 'x' is returned if shadow passwords are in use. An '*' is returned
|
1134
|
+
* if the user cannot log in using a password.
|
1135
|
+
* uid::
|
1136
|
+
* contains the integer user ID (uid) of the user.
|
1137
|
+
* gid::
|
1138
|
+
* contains the integer group ID (gid) of the user's primary group.
|
1139
|
+
* dir::
|
1140
|
+
* contains the path to the home directory of the user as a String.
|
1141
|
+
* shell::
|
1142
|
+
* contains the path to the login shell of the user as a String.
|
1143
|
+
*
|
1144
|
+
* === The following members below are optional, and must be compiled with special flags:
|
1145
|
+
*
|
1146
|
+
* gecos::
|
1147
|
+
* contains a longer String description of the user, such as
|
1148
|
+
* a full name. Some Unix systems provide structured information in the
|
1149
|
+
* gecos field, but this is system-dependent.
|
1150
|
+
* must be compiled with +HAVE_STRUCT_PASSWD_PW_GECOS+
|
1151
|
+
* change::
|
1152
|
+
* password change time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_CHANGE+
|
1153
|
+
* quota::
|
1154
|
+
* quota value(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_QUOTA+
|
1155
|
+
* age::
|
1156
|
+
* password age(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_AGE+
|
1157
|
+
* class::
|
1158
|
+
* user access class(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_CLASS+
|
1159
|
+
* comment::
|
1160
|
+
* comment(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_COMMENT+
|
1161
|
+
* expire::
|
1162
|
+
* account expiration time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_EXPIRE+
|
1163
|
+
*/
|
1164
|
+
rb_define_const(mEtc, "Passwd", sPasswd);
|
1165
|
+
#endif
|
1166
|
+
rb_define_const(rb_cStruct, "Passwd", sPasswd); /* deprecated name */
|
1167
|
+
rb_extend_object(sPasswd, rb_mEnumerable);
|
1168
|
+
rb_define_singleton_method(sPasswd, "each", etc_each_passwd, 0);
|
1169
|
+
|
1170
|
+
#ifdef HAVE_GETGRENT
|
1171
|
+
sGroup = rb_struct_define_under(mEtc, "Group", "name",
|
1172
|
+
#ifdef HAVE_STRUCT_GROUP_GR_PASSWD
|
1173
|
+
"passwd",
|
1174
|
+
#endif
|
1175
|
+
"gid", "mem", NULL);
|
1176
|
+
|
1177
|
+
#if 0
|
1178
|
+
/* Define-const: Group
|
1179
|
+
*
|
1180
|
+
* Group is a Struct that is only available when compiled with +HAVE_GETGRENT+.
|
1181
|
+
*
|
1182
|
+
* The struct contains the following members:
|
1183
|
+
*
|
1184
|
+
* name::
|
1185
|
+
* contains the name of the group as a String.
|
1186
|
+
* passwd::
|
1187
|
+
* contains the encrypted password as a String. An 'x' is
|
1188
|
+
* returned if password access to the group is not available; an empty
|
1189
|
+
* string is returned if no password is needed to obtain membership of
|
1190
|
+
* the group.
|
1191
|
+
*
|
1192
|
+
* Must be compiled with +HAVE_STRUCT_GROUP_GR_PASSWD+.
|
1193
|
+
* gid::
|
1194
|
+
* contains the group's numeric ID as an integer.
|
1195
|
+
* mem::
|
1196
|
+
* is an Array of Strings containing the short login names of the
|
1197
|
+
* members of the group.
|
1198
|
+
*/
|
1199
|
+
rb_define_const(mEtc, "Group", sGroup);
|
1200
|
+
#endif
|
1201
|
+
rb_define_const(rb_cStruct, "Group", sGroup); /* deprecated name */
|
1202
|
+
rb_extend_object(sGroup, rb_mEnumerable);
|
1203
|
+
rb_define_singleton_method(sGroup, "each", etc_each_group, 0);
|
1204
|
+
#endif
|
1205
|
+
}
|