summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-06-23 08:32:49 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-06-23 08:32:49 +0000
commitc339f208c4b304199ebed24cf9963e8d13eefa1f (patch)
treed91946e1927ef4615cde44e7472fda698fa8bc6b /process.c
parent0fcc2cdb99264e196846155617f14e503ac951fc (diff)
merge revision(s) 45287:45290: [Backport #9600]
* process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r() may need larger buffers than sysconf values, so retry with expanding the buffer when ERANGE is returned. [ruby-core:61325] [Bug #9600] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@46511 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'process.c')
-rw-r--r--process.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/process.c b/process.c
index d351a398d3..6c9cc7c153 100644
--- a/process.c
+++ b/process.c
@@ -147,6 +147,9 @@ static void check_gid_switch(void);
#if defined(HAVE_PWD_H)
# if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
# define USE_GETPWNAM_R 1
+# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
+# define GETPW_R_SIZE_DEFAULT 0x1000
+# define GETPW_R_SIZE_LIMIT 0x10000
# endif
# ifdef USE_GETPWNAM_R
# define PREPARE_GETPWNAM \
@@ -171,6 +174,9 @@ static rb_uid_t obj2uid(VALUE id);
#if defined(HAVE_GRP_H)
# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
# define USE_GETGRNAM_R
+# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
+# define GETGR_R_SIZE_DEFAULT 0x1000
+# define GETGR_R_SIZE_LIMIT 0x10000
# endif
# ifdef USE_GETGRNAM_R
# define PREPARE_GETGRNAM \
@@ -4744,8 +4750,28 @@ obj2uid(VALUE id
struct passwd *pwptr;
#ifdef USE_GETPWNAM_R
struct passwd pwbuf;
- if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr))
- rb_sys_fail("getpwnam_r");
+ char *getpw_buf;
+ long getpw_buf_len;
+ if (!*getpw_tmp) {
+ getpw_buf_len = GETPW_R_SIZE_INIT;
+ if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
+ getpw_buf = rb_alloc_tmp_buffer(getpw_tmp, getpw_buf_len);
+ }
+ else {
+ getpw_buf = RSTRING_PTR(*getpw_tmp);
+ getpw_buf_len = rb_str_capacity(*getpw_tmp);
+ }
+ errno = ERANGE;
+ /* gepwnam_r() on MacOS X doesn't set errno if buffer size is insufficient */
+ while (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) {
+ if (errno != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
+ rb_free_tmp_buffer(getpw_tmp);
+ rb_sys_fail("getpwnam_r");
+ }
+ rb_str_modify_expand(*getpw_tmp, getpw_buf_len);
+ getpw_buf = RSTRING_PTR(*getpw_tmp);
+ getpw_buf_len = rb_str_capacity(*getpw_tmp);
+ }
#else
pwptr = getpwnam(usrname);
#endif
@@ -4792,8 +4818,28 @@ obj2gid(VALUE id
struct group *grptr;
#ifdef USE_GETGRNAM_R
struct group grbuf;
- if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr))
- rb_sys_fail("getgrnam_r");
+ char *getgr_buf;
+ long getgr_buf_len;
+ if (!*getgr_tmp) {
+ getgr_buf_len = GETGR_R_SIZE_INIT;
+ if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
+ getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len);
+ }
+ else {
+ getgr_buf = RSTRING_PTR(*getgr_tmp);
+ getgr_buf_len = rb_str_capacity(*getgr_tmp);
+ }
+ errno = ERANGE;
+ /* gegrnam_r() on MacOS X doesn't set errno if buffer size is insufficient */
+ while (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) {
+ if (errno != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
+ rb_free_tmp_buffer(getgr_tmp);
+ rb_sys_fail("getgrnam_r");
+ }
+ rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
+ getgr_buf = RSTRING_PTR(*getgr_tmp);
+ getgr_buf_len = rb_str_capacity(*getgr_tmp);
+ }
#else
grptr = getgrnam(grpname);
#endif