etc 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }