Module: Mixlib::ShellOut::Unix

Included in:
Mixlib::ShellOut
Defined in:
lib/mixlib/shellout/unix.rb

Instance Method Summary collapse

Instance Method Details

#all_seconderiesObject

Helper method for sgids



36
37
38
39
40
41
42
43
44
# File 'lib/mixlib/shellout/unix.rb', line 36

def all_seconderies
  ret = []
  Etc.endgrent
  while ( g = Etc.getgrent )
    ret << g
  end
  Etc.endgrent
  ret
end

#logon_environmentObject

The environment variables that are deduced from simulating logon Only valid if login is used



58
59
60
61
62
63
64
65
66
# File 'lib/mixlib/shellout/unix.rb', line 58

def logon_environment
  return {} unless using_login?

  entry = Etc.getpwuid(uid)
  # According to `man su`, the set fields are:
  #  $HOME, $SHELL, $USER, $LOGNAME, $PATH, and $IFS
  # Values are copied from "shadow" package in Ubuntu 14.10
  { "HOME" => entry.dir, "SHELL" => entry.shell, "USER" => entry.name, "LOGNAME" => entry.name, "PATH" => "/sbin:/bin:/usr/sbin:/usr/bin", "IFS" => "\t\n" }
end

#process_environmentObject

Merges the two environments for the process



69
70
71
# File 'lib/mixlib/shellout/unix.rb', line 69

def process_environment
  logon_environment.merge(environment)
end

#run_commandObject

Run the command, writing the command’s standard out and standard error to stdout and stderr, and saving its exit status object to status

Returns

returns self; stdout, stderr, status, and exitstatus will be populated with results of the command.

Raises

  • Errno::EACCES when you are not privileged to execute the command

  • Errno::ENOENT when the command is not available on the system (or not in the current $PATH)

  • Chef::Exceptions::CommandTimeout when the command does not complete within timeout seconds (default: 600s). When this happens, ShellOut will send a TERM and then KILL to the entire process group to ensure that any grandchild processes are terminated. If the invocation of the child process spawned multiple child processes (which commonly happens if the command is passed as a single string to be interpreted by bin/sh, and bin/sh is not bash), the exit status object may not contain the correct exit code of the process (of course there is no exit code if the command is killed by SIGKILL, also).



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/mixlib/shellout/unix.rb', line 91

def run_command
  @child_pid = fork_subprocess
  @reaped = false

  configure_parent_process_file_descriptors

  # CHEF-3390: Marshall.load on Ruby < 1.8.7p369 also has a GC bug related
  # to Marshall.load, so try disabling GC first.
  propagate_pre_exec_failure

  @status = nil
  @result = nil
  @execution_time = 0

  write_to_child_stdin

  until @status
    ready_buffers = attempt_buffer_read
    unless ready_buffers
      @execution_time += READ_WAIT_TIME
      if @execution_time >= timeout && !@result
        # kill the bad proccess
        reap_errant_child
        # read anything it wrote when we killed it
        attempt_buffer_read
        # raise
        raise CommandTimeout, "Command timed out after #{@execution_time.to_i}s:\n#{format_for_exception}"
      end
    end

    attempt_reap
  end

  self
rescue Errno::ENOENT
  # When ENOENT happens, we can be reasonably sure that the child process
  # is going to exit quickly, so we use the blocking variant of waitpid2
  reap
  raise
ensure
  reap_errant_child if should_reap?
  # make one more pass to get the last of the output after the
  # child process dies
  attempt_buffer_read
  # no matter what happens, turn the GC back on, and hope whatever busted
  # version of ruby we're on doesn't allocate some objects during the next
  # GC run.
  GC.enable
  close_all_pipes
end

#sgidsObject

The secondary groups that the subprocess will switch to. Currently valid only if login is used, and is set to the user’s secondary groups



49
50
51
52
53
54
# File 'lib/mixlib/shellout/unix.rb', line 49

def sgids
  return nil unless using_login?

  user_name = Etc.getpwuid(uid).name
  all_seconderies.select { |g| g.mem.include?(user_name) }.map(&:gid)
end

#using_login?Boolean

Whether we’re simulating a login shell

Returns:

  • (Boolean)


31
32
33
# File 'lib/mixlib/shellout/unix.rb', line 31

def using_login?
   && user
end

#validate_options(opts) ⇒ Object

Option validation that is unix specific



24
25
26
27
28
# File 'lib/mixlib/shellout/unix.rb', line 24

def validate_options(opts)
  if opts[:elevated]
    raise InvalidCommandOption, "Option `elevated` is supported for Powershell commands only"
  end
end