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.
@@ -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
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /ext/etc/constdefs.h
11
+ *.bundle
12
+ *.so
13
+ *.dll
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - ruby-head
5
+ before_install: gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in etc.gemspec
4
+ gemspec
@@ -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.
@@ -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).
@@ -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
@@ -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__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -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
+ }