~ubuntu-branches/ubuntu/hardy/ruby1.8/hardy-updates

« back to all changes in this revision

Viewing changes to ext/etc/etc.c

  • Committer: Bazaar Package Importer
  • Author(s): akira yamada
  • Date: 2007-03-13 22:11:58 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070313221158-h3oql37brlaf2go2
Tags: 1.8.6-1
* new upstream version, 1.8.6.
* libruby1.8 conflicts with libopenssl-ruby1.8 (< 1.8.6) (closes: #410018)
* changed packaging style to cdbs from dbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************
 
2
 
 
3
  etc.c -
 
4
 
 
5
  $Author: shyouhei $
 
6
  $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
 
7
  created at: Tue Mar 22 18:39:19 JST 1994
 
8
 
 
9
************************************************/
 
10
 
 
11
#include "ruby.h"
 
12
 
 
13
#include <sys/types.h>
 
14
#ifdef HAVE_UNISTD_H
 
15
#include <unistd.h>
 
16
#endif
 
17
 
 
18
#ifdef HAVE_GETPWENT
 
19
#include <pwd.h>
 
20
#endif
 
21
 
 
22
#ifdef HAVE_GETGRENT
 
23
#include <grp.h>
 
24
#endif
 
25
 
 
26
#ifndef HAVE_TYPE_UID_T
 
27
#define uid_t int
 
28
#endif
 
29
 
 
30
static VALUE sPasswd, sGroup;
 
31
 
 
32
#ifndef _WIN32
 
33
char *getenv();
 
34
#endif
 
35
char *getlogin();
 
36
 
 
37
/* Returns the short user name of the currently logged in user.
 
38
 *
 
39
 * e.g.
 
40
 *   Etc.getlogin -> 'guest'
 
41
 */
 
42
static VALUE
 
43
etc_getlogin(obj)
 
44
    VALUE obj;
 
45
{
 
46
    char *login;
 
47
 
 
48
    rb_secure(4);
 
49
#ifdef HAVE_GETLOGIN
 
50
    login = getlogin();
 
51
    if (!login) login = getenv("USER");
 
52
#else
 
53
    login = getenv("USER");
 
54
#endif
 
55
 
 
56
    if (login)
 
57
        return rb_tainted_str_new2(login);
 
58
    return Qnil;
 
59
}
 
60
 
 
61
#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
 
62
static VALUE
 
63
safe_setup_str(str)
 
64
    const char *str;
 
65
{
 
66
    if (str == 0) str = "";
 
67
    return rb_tainted_str_new2(str);
 
68
}
 
69
#endif
 
70
 
 
71
#ifdef HAVE_GETPWENT
 
72
static VALUE
 
73
setup_passwd(pwd)
 
74
    struct passwd *pwd;
 
75
{
 
76
    if (pwd == 0) rb_sys_fail("/etc/passwd");
 
77
    return rb_struct_new(sPasswd,
 
78
                         safe_setup_str(pwd->pw_name),
 
79
#ifdef HAVE_ST_PW_PASSWD
 
80
                         safe_setup_str(pwd->pw_passwd),
 
81
#endif
 
82
                         PW_UID2VAL(pwd->pw_uid),
 
83
                         PW_GID2VAL(pwd->pw_gid),
 
84
#ifdef HAVE_ST_PW_GECOS
 
85
                         safe_setup_str(pwd->pw_gecos),
 
86
#endif
 
87
                         safe_setup_str(pwd->pw_dir),
 
88
                         safe_setup_str(pwd->pw_shell),
 
89
#ifdef HAVE_ST_PW_CHANGE
 
90
                         INT2NUM(pwd->pw_change),
 
91
#endif
 
92
#ifdef HAVE_ST_PW_QUOTA
 
93
                         INT2NUM(pwd->pw_quota),
 
94
#endif
 
95
#ifdef HAVE_ST_PW_AGE
 
96
                         PW_AGE2VAL(pwd->pw_age),
 
97
#endif
 
98
#ifdef HAVE_ST_PW_CLASS
 
99
                         safe_setup_str(pwd->pw_class),
 
100
#endif
 
101
#ifdef HAVE_ST_PW_COMMENT
 
102
                         safe_setup_str(pwd->pw_comment),
 
103
#endif
 
104
#ifdef HAVE_ST_PW_EXPIRE
 
105
                         INT2NUM(pwd->pw_expire),
 
106
#endif
 
107
                         0              /*dummy*/
 
108
        );
 
109
}
 
110
#endif
 
111
 
 
112
/* Returns the /etc/passwd information for the user with specified integer
 
113
 * user id (uid).
 
114
 *
 
115
 * The information is returned as a Struct::Passwd; see getpwent above for
 
116
 * details.
 
117
 *
 
118
 * e.g.  * Etc.getpwuid(0) -> #<struct Struct::Passwd name="root",
 
119
 * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
 
120
 */
 
121
static VALUE
 
122
etc_getpwuid(argc, argv, obj)
 
123
    int argc;
 
124
    VALUE *argv;
 
125
    VALUE obj;
 
126
{
 
127
#if defined(HAVE_GETPWENT)
 
128
    VALUE id;
 
129
    uid_t uid;
 
130
    struct passwd *pwd;
 
131
 
 
132
    rb_secure(4);
 
133
    if (rb_scan_args(argc, argv, "01", &id) == 1) {
 
134
        uid = PW_VAL2UID(id);
 
135
    }
 
136
    else {
 
137
        uid = getuid();
 
138
    }
 
139
    pwd = getpwuid(uid);
 
140
    if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", uid);
 
141
    return setup_passwd(pwd);
 
142
#else 
 
143
    return Qnil;
 
144
#endif
 
145
}
 
146
 
 
147
/* Returns the /etc/passwd information for the user with specified login name.
 
148
 *
 
149
 * The information is returned as a Struct::Passwd; see getpwent above for
 
150
 * details.
 
151
 *
 
152
 * e.g.  * Etc.getpwnam('root') -> #<struct Struct::Passwd name="root",
 
153
 * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
 
154
 */
 
155
static VALUE
 
156
etc_getpwnam(obj, nam)
 
157
    VALUE obj, nam;
 
158
{
 
159
#ifdef HAVE_GETPWENT
 
160
    struct passwd *pwd;
 
161
 
 
162
    SafeStringValue(nam);
 
163
    pwd = getpwnam(RSTRING(nam)->ptr);
 
164
    if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING(nam)->ptr);
 
165
    return setup_passwd(pwd);
 
166
#else 
 
167
    return Qnil;
 
168
#endif
 
169
}
 
170
 
 
171
#ifdef HAVE_GETPWENT
 
172
static int passwd_blocking = 0;
 
173
static VALUE
 
174
passwd_ensure()
 
175
{
 
176
    passwd_blocking = Qfalse;
 
177
    return Qnil;
 
178
}
 
179
 
 
180
static VALUE
 
181
passwd_iterate()
 
182
{
 
183
    struct passwd *pw;
 
184
 
 
185
    setpwent();
 
186
    while (pw = getpwent()) {
 
187
        rb_yield(setup_passwd(pw));
 
188
    }
 
189
    endpwent();
 
190
    return Qnil;
 
191
}
 
192
#endif
 
193
 
 
194
/* Provides a convenient Ruby iterator which executes a block for each entry 
 
195
 * in the /etc/passwd file.
 
196
 *
 
197
 * The code block is passed an Etc::Passwd struct; see getpwent above for 
 
198
 * details.
 
199
 *
 
200
 * Example:
 
201
 *
 
202
 *     require 'etc'
 
203
 *
 
204
 *     Etc.passwd {|u|
 
205
 *       puts u.name + " = " + u.gecos
 
206
 *     }
 
207
 *
 
208
 */
 
209
static VALUE
 
210
etc_passwd(obj)
 
211
    VALUE obj;
 
212
{
 
213
#ifdef HAVE_GETPWENT
 
214
    struct passwd *pw;
 
215
 
 
216
    rb_secure(4);
 
217
    if (rb_block_given_p()) {
 
218
        if (passwd_blocking) {
 
219
            rb_raise(rb_eRuntimeError, "parallel passwd iteration");
 
220
        }
 
221
        passwd_blocking = Qtrue;
 
222
        rb_ensure(passwd_iterate, 0, passwd_ensure, 0);
 
223
    }
 
224
    if (pw = getpwent()) {
 
225
        return setup_passwd(pw);
 
226
    }
 
227
#endif
 
228
    return Qnil;
 
229
}
 
230
 
 
231
/* Resets the process of reading the /etc/passwd file, so that the next call
 
232
 * to getpwent will return the first entry again.
 
233
 */
 
234
static VALUE
 
235
etc_setpwent(obj)
 
236
    VALUE obj;
 
237
{
 
238
#ifdef HAVE_GETPWENT
 
239
    setpwent();
 
240
#endif
 
241
    return Qnil;
 
242
}
 
243
 
 
244
/* Ends the process of scanning through the /etc/passwd file begun with
 
245
 * getpwent, and closes the file.
 
246
 */
 
247
static VALUE
 
248
etc_endpwent(obj)
 
249
    VALUE obj;
 
250
{
 
251
#ifdef HAVE_GETPWENT
 
252
    endpwent();
 
253
#endif
 
254
    return Qnil;
 
255
}
 
256
 
 
257
/* Returns an entry from the /etc/passwd file. The first time it is called it
 
258
 * opens the file and returns the first entry; each successive call returns 
 
259
 * the next entry, or nil if the end of the file has been reached.
 
260
 *
 
261
 * To close the file when processing is complete, call endpwent.
 
262
 *
 
263
 * Each entry is returned as a Struct::Passwd:
 
264
 *
 
265
 * - Passwd#name contains the short login name of the user as a String.
 
266
 *
 
267
 * - Passwd#passwd contains the encrypted password of the user as a String.
 
268
 *   an 'x' is returned if shadow passwords are in use. An '*' is returned
 
269
 *   if the user cannot log in using a password.
 
270
 *
 
271
 * - Passwd#uid contains the integer user ID (uid) of the user.
 
272
 *
 
273
 * - Passwd#gid contains the integer group ID (gid) of the user's primary group.
 
274
 *
 
275
 * - Passwd#gecos contains a longer String description of the user, such as 
 
276
 *   a full name. Some Unix systems provide structured information in the 
 
277
 *   gecos field, but this is system-dependent.
 
278
 *
 
279
 * - Passwd#dir contains the path to the home directory of the user as a String.
 
280
 *
 
281
 * - Passwd#shell contains the path to the login shell of the user as a String.
 
282
 */
 
283
static VALUE
 
284
etc_getpwent(obj)
 
285
    VALUE obj;
 
286
{
 
287
#ifdef HAVE_GETPWENT
 
288
    struct passwd *pw;
 
289
 
 
290
    if (pw = getpwent()) {
 
291
        return setup_passwd(pw);
 
292
    }
 
293
#endif
 
294
    return Qnil;
 
295
}
 
296
 
 
297
#ifdef HAVE_GETGRENT
 
298
static VALUE
 
299
setup_group(grp)
 
300
    struct group *grp;
 
301
{
 
302
    VALUE mem;
 
303
    char **tbl;
 
304
 
 
305
    mem = rb_ary_new();
 
306
    tbl = grp->gr_mem;
 
307
    while (*tbl) {
 
308
        rb_ary_push(mem, safe_setup_str(*tbl));
 
309
        tbl++;
 
310
    }
 
311
    return rb_struct_new(sGroup,
 
312
                         safe_setup_str(grp->gr_name),
 
313
#ifdef HAVE_ST_GR_PASSWD
 
314
                         safe_setup_str(grp->gr_passwd),
 
315
#endif
 
316
                         PW_GID2VAL(grp->gr_gid),
 
317
                         mem);
 
318
}
 
319
#endif
 
320
 
 
321
/* Returns information about the group with specified integer group id (gid), 
 
322
 * as found in /etc/group.
 
323
 *
 
324
 * The information is returned as a Struct::Group; see getgrent above for
 
325
 * details.
 
326
 *
 
327
 * e.g.  Etc.getgrgid(100) -> #<struct Struct::Group name="users", passwd="x",
 
328
 * gid=100, mem=["meta", "root"]>
 
329
 *
 
330
 */
 
331
static VALUE
 
332
etc_getgrgid(obj, id)
 
333
    VALUE obj, id;
 
334
{
 
335
#ifdef HAVE_GETGRENT
 
336
    gid_t gid;
 
337
    struct group *grp;
 
338
 
 
339
    rb_secure(4);
 
340
    gid = getgid();
 
341
    grp = getgrgid(gid);
 
342
    if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", gid);
 
343
    return setup_group(grp);
 
344
#else
 
345
    return Qnil;
 
346
#endif
 
347
}
 
348
 
 
349
/* Returns information about the group with specified String name, as found 
 
350
 * in /etc/group.
 
351
 *
 
352
 * The information is returned as a Struct::Group; see getgrent above for
 
353
 * details.
 
354
 *
 
355
 * e.g.  Etc.getgrnam('users') -> #<struct Struct::Group name="users",
 
356
 * passwd="x", gid=100, mem=["meta", "root"]>
 
357
 *
 
358
 */
 
359
static VALUE
 
360
etc_getgrnam(obj, nam)
 
361
    VALUE obj, nam;
 
362
{
 
363
#ifdef HAVE_GETGRENT
 
364
    struct group *grp;
 
365
 
 
366
    rb_secure(4);
 
367
    SafeStringValue(nam);
 
368
    grp = getgrnam(RSTRING(nam)->ptr);
 
369
    if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING(nam)->ptr);
 
370
    return setup_group(grp);
 
371
#else
 
372
    return Qnil;
 
373
#endif
 
374
}
 
375
 
 
376
#ifdef HAVE_GETGRENT
 
377
static int group_blocking = 0;
 
378
static VALUE
 
379
group_ensure()
 
380
{
 
381
    group_blocking = Qfalse;
 
382
    return Qnil;
 
383
}
 
384
 
 
385
static VALUE
 
386
group_iterate()
 
387
{
 
388
    struct group *pw;
 
389
 
 
390
    setgrent();
 
391
    while (pw = getgrent()) {
 
392
        rb_yield(setup_group(pw));
 
393
    }
 
394
    endgrent();
 
395
    return Qnil;
 
396
}
 
397
#endif
 
398
 
 
399
/* Provides a convenient Ruby iterator which executes a block for each entry 
 
400
 * in the /etc/group file.
 
401
 *
 
402
 * The code block is passed an Etc::Group struct; see getgrent above for 
 
403
 * details.
 
404
 *
 
405
 * Example:
 
406
 *
 
407
 *     require 'etc'
 
408
 *
 
409
 *     Etc.group {|g|
 
410
 *       puts g.name + ": " + g.mem.join(', ')
 
411
 *     }
 
412
 *
 
413
 */
 
414
static VALUE
 
415
etc_group(obj)
 
416
    VALUE obj;
 
417
{
 
418
#ifdef HAVE_GETGRENT
 
419
    struct group *grp;
 
420
 
 
421
    rb_secure(4);
 
422
    if (rb_block_given_p()) {
 
423
        if (group_blocking) {
 
424
            rb_raise(rb_eRuntimeError, "parallel group iteration");
 
425
        }
 
426
        group_blocking = Qtrue;
 
427
        rb_ensure(group_iterate, 0, group_ensure, 0);
 
428
    }
 
429
    if (grp = getgrent()) {
 
430
        return setup_group(grp);
 
431
    }
 
432
#endif
 
433
    return Qnil;
 
434
}
 
435
 
 
436
/* Resets the process of reading the /etc/group file, so that the next call
 
437
 * to getgrent will return the first entry again.
 
438
 */
 
439
static VALUE
 
440
etc_setgrent(obj)
 
441
    VALUE obj;
 
442
{
 
443
#ifdef HAVE_GETGRENT
 
444
    setgrent();
 
445
#endif
 
446
    return Qnil;
 
447
}
 
448
 
 
449
/* Ends the process of scanning through the /etc/group file begun by 
 
450
 * getgrent, and closes the file.
 
451
 */
 
452
static VALUE
 
453
etc_endgrent(obj)
 
454
    VALUE obj;
 
455
{
 
456
#ifdef HAVE_GETGRENT
 
457
    endgrent();
 
458
#endif
 
459
    return Qnil;
 
460
}
 
461
 
 
462
/* Returns an entry from the /etc/group file. The first time it is called it
 
463
 * opens the file and returns the first entry; each successive call returns 
 
464
 * the next entry, or nil if the end of the file has been reached.
 
465
 *
 
466
 * To close the file when processing is complete, call endgrent.
 
467
 *
 
468
 * Each entry is returned as a Struct::Group:
 
469
 *
 
470
 * - Group#name contains the name of the group as a String.
 
471
 *
 
472
 * - Group#passwd contains the encrypted password as a String. An 'x' is
 
473
 *   returned if password access to the group is not available; an empty 
 
474
 *   string is returned if no password is needed to obtain membership of 
 
475
 *   the group.
 
476
 *
 
477
 * - Group#gid contains the group's numeric ID as an integer.
 
478
 *
 
479
 * - Group#mem is an Array of Strings containing the short login names of the 
 
480
 *   members of the group.
 
481
 */
 
482
static VALUE
 
483
etc_getgrent(obj)
 
484
    VALUE obj;
 
485
{
 
486
#ifdef HAVE_GETGRENT
 
487
    struct group *gr;
 
488
 
 
489
    if (gr = getgrent()) {
 
490
        return setup_group(gr);
 
491
    }
 
492
#endif
 
493
    return Qnil;
 
494
}
 
495
 
 
496
static VALUE mEtc;
 
497
 
 
498
/* The etc module provides access to information from the /etc/passwd and
 
499
 * /etc/group files on Linux and Unix systems.
 
500
 *
 
501
 * Documented by mathew <meta@pobox.com>.
 
502
 */
 
503
void
 
504
Init_etc()
 
505
{
 
506
    mEtc = rb_define_module("Etc");
 
507
 
 
508
    rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
 
509
 
 
510
    rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
 
511
    rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
 
512
    rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
 
513
    rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
 
514
    rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
 
515
    rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
 
516
 
 
517
    rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, 1);
 
518
    rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
 
519
    rb_define_module_function(mEtc, "group", etc_group, 0);
 
520
    rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
 
521
    rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
 
522
    rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
 
523
 
 
524
    rb_global_variable(&sPasswd);
 
525
    sPasswd =  rb_struct_define("Passwd",
 
526
                                "name", "passwd", "uid", "gid",
 
527
#ifdef HAVE_ST_PW_GECOS
 
528
                                "gecos",
 
529
#endif
 
530
                                "dir", "shell",
 
531
#ifdef HAVE_ST_PW_CHANGE
 
532
                                "change",
 
533
#endif
 
534
#ifdef HAVE_ST_PW_QUOTA
 
535
                                "quota",
 
536
#endif
 
537
#ifdef HAVE_ST_PW_AGE
 
538
                                "age",
 
539
#endif
 
540
#ifdef HAVE_ST_PW_CLASS
 
541
                                "uclass",
 
542
#endif
 
543
#ifdef HAVE_ST_PW_COMMENT
 
544
                                "comment",
 
545
#endif
 
546
#ifdef HAVE_ST_PW_EXPIRE
 
547
                                "expire",
 
548
#endif
 
549
                                NULL);
 
550
 
 
551
#ifdef HAVE_GETGRENT
 
552
    rb_global_variable(&sGroup);
 
553
    sGroup = rb_struct_define("Group", "name",
 
554
#ifdef HAVE_ST_GR_PASSWD
 
555
                              "passwd",
 
556
#endif
 
557
                              "gid", "mem", NULL);
 
558
#endif
 
559
}