-
Notifications
You must be signed in to change notification settings - Fork 654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
expose getpwent and getgrent #1820
base: master
Are you sure you want to change the base?
expose getpwent and getgrent #1820
Conversation
Haven't added the changes to Will add it, maybe after #1817 is merged, or there will be a merge conflict. |
The CI for fuchsia failed because PR filed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This setpwent
business sucks. Very un-Rusty. I wonder if it would better just to use the raceless fgetpwent_r
function instead. I think that's only available on GNU/Linux, but at least it's thread-safe.
/// | ||
/// # Safety | ||
/// | ||
/// This function is marked as `unsafe` cause `setpwent()` and `endpwent()` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This function is marked as `unsafe` cause `setpwent()` and `endpwent()` | |
/// This function is marked as `unsafe` because `setpwent()` and `endpwent()` |
|
||
#[cfg(any( | ||
target_os = "freebsd", | ||
target_os = "netbsd", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about OpenBSD?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenBSD does not have getpwent_r
and getgrent_r
so I am using getpwent/getgrent
on it.
/// # Safety | ||
/// | ||
/// This function is marked as `unsafe` cause `setpwent()` and `endpwent()` | ||
/// will modify a global state, which will result in a data race if we have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What kind of data race? Skipping over some users, or duplicating some, is not considered unsafe
. Only something like reading a struct with some entries from one source and some from another would be considered unsafe
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two issues here I think:
- The pointer returned by
getpwent()
points to static memory, and thus can be overwritten by subsequent calls likegetpwent
,getpwuid
, andgetpwnam
. So in the implementation usinggetpwent()
, when executingSome(Ok(User::from(unsafe{&*pwd})))
in a thread (say thread A), there happens to be another thread (thread B) callinggetpwent/getpwuid/getpwnam
, then the static memory will be overwritten due to the call in thread B, making thread A get a wrong result. This is the data race. setpwent/endpwent
will modify a global state, if two instances are running at the same time, the state set by the first instance can be reset by the second one, then the first instance will get duplicate entries.
Sorry for the unclarity in my documentation, will update it stating both issues.
/// ``` | ||
// RedoxFS does not support passwd and android does not have /etc/passwd. | ||
#[cfg(not(any(target_os = "redox", target_os = "android")))] | ||
pub unsafe fn all_users() -> AllUsers { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest that a more natural API would be to call this function AllUsers::new()
// no more entries | ||
if res.is_null() { | ||
None | ||
}else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}else { | |
} else { |
Yes, this API sucks. What are we going to do about this pr? Change the implementation for GNU/Linux to |
This PR is for issue #1811.
On OSes where
getpwent_r/getgrent_r
is available, it is used. On other OSes, usegetpwent/getgrent
. However,illumos
andsolaris
, they do havegetpwent_r/getgrent_r
, but the definitions exposed bylibc
are wrong, so I currently usegetpwent/getgrent
on them.The implementations of
AllUsers::next
andAllGroups::next
on platforms wheregetpwent_r/getgrent_r
is available are kind of ugly, this is because the return values of these functions are so different:freebsd: getpwent_r man page
result
will be non-NULLresult
will be NULLresult
will be NULL.dragonfly: getpwent_r man page
result
will be non-NULLresult
will be NULLresult
will be NULLnetbsd: getpwent_r man page
result
will be non-NULL,result
will be NULLresult
will be NULLLinux: getpwent_r man page
result
will be non-NULLresult
will be NULLresult
will be NULL.Another thing I am not sure about is the return value of
AllUsers::next()/AllGroups::next()
. In my implementation, it is:The inner
Result
is used to expose theerrno
value, the drawback of such a design is that the user has to stop iterating when an error occurs.