lib/wright/util/user.rb
require 'etc'
module Wright
module Util
# Various user utility functions.
module User
# Returns a user's uid.
#
# @param user [String, Integer] the user's name or uid
#
# @example
# Wright::Util::User.user_to_uid('root')
# # => 0
#
# Wright::Util::User.user_to_uid(0)
# # => 0
#
# @return [Integer] the integer uid of the given user or nil if
# user was nil
def self.user_to_uid(user)
to_id(user, :user)
end
# Returns a group's gid.
#
# @param group [String, Integer] the group's name or gid
#
# @example
# Wright::Util::User.group_to_gid('root')
# # => 0
#
# Wright::Util::User.group_to_gid(0)
# # => 0
#
# @return [Integer] the integer gid of the given group or nil if
# group was nil
def self.group_to_gid(group)
to_id(group, :group)
end
def self.to_id(object, type)
raise ArgumentError unless [:group, :user].include?(type)
return nil if object.nil?
return object.to_i unless object.is_a?(String)
type == :user ? Etc.getpwnam(object).uid : Etc.getgrnam(object).gid
end
private_class_method :to_id
# Returns the next free uid in a range.
#
# @param uid_range [Range] the uid range
#
# @example
# Wright::Util::User.next_free_uid(1...500)
# # => 2
#
# @return [Integer] the next free uid
# @raise [RuntimeError] if there are no free uids in the range
def self.next_free_uid(uid_range)
next_free_id(uid_range, :uid)
end
# Returns the next free gid in a range.
#
# @param gid_range [Range] the gid range
#
# @example
# Wright::Util::User.next_free_gid(1...500)
# # => 11
#
# @return [Integer] the next free gid
# @raise [RuntimeError] if there are no free gids in the range
def self.next_free_gid(gid_range)
next_free_id(gid_range, :gid)
end
def self.next_free_id(id_range, id_type)
iterator = id_iterator(id_type)
used_ids = []
iterator.call do |o|
id = o.method(id_type).call
used_ids << id if id_range.include?(id)
end
free_ids = id_range.to_a - used_ids
raise "No free #{id_type} in range #{id_range}" if free_ids.empty?
free_ids.min
end
private_class_method(:next_free_id)
def self.id_iterator(id_type)
raise ArgumentError unless [:uid, :gid].include?(id_type)
id_type == :uid ? Etc.method(:passwd) : Etc.method(:group)
end
private_class_method :id_iterator
# Returns a user entry.
#
# @param username [String] the name of the user
#
# @example
# Wright::Util::User.safe_getpwnam('this_user_does_not_exist')
# # => nil
#
# @return [Struct::Passwd, nil] the user entry or nil if the
# user does not exist
def self.safe_getpwnam(username)
Etc.getpwnam(username)
rescue ArgumentError
nil
end
# Returns a group entry.
#
# @param groupname [String] the name of the group
#
# @example
# Wright::Util::User.safe_getgrnam('this_group_does_not_exist')
# # => nil
#
# @return [Struct::Group, nil] the group entry or nil if the
# group does not exist
def self.safe_getgrnam(groupname)
Etc.getgrnam(groupname)
rescue ArgumentError
nil
end
end
end
end