Utility functions for accessing system functionality.

Methods
Classes and Modules
Class PhusionPassenger::NativeSupport::FileSystemWatcher
Constants
UNIX_PATH_MAX = INT2NUM(sizeof(addr.sun_path))
  The maximum length of a Unix socket path, including terminating null.
SSIZE_MAX = LL2NUM(SSIZE_MAX)
  The maximum size of the data that may be passed to #writev.
Public Class methods
close_all_file_descriptors(exceptions)

Close all file descriptors, except those given in the exceptions array. For example, the following would close all file descriptors except standard input (0) and standard output (1).

 close_all_file_descriptors([0, 1])
/*
 * call-seq: close_all_file_descriptors(exceptions)
 *
 * Close all file descriptors, except those given in the +exceptions+ array.
 * For example, the following would close all file descriptors except standard
 * input (0) and standard output (1).
 *
 *  close_all_file_descriptors([0, 1])
 */
static VALUE
close_all_file_descriptors(VALUE self, VALUE exceptions) {

create_unix_socket(filename, backlog)

Create a SOCK_STREAM server Unix socket. Unlike Ruby‘s UNIXServer class, this function is also able to create Unix sockets on the abstract namespace by prepending the filename with a null byte.

  • filename (string): The filename of the Unix socket to create.
  • backlog (integer): The backlog to use for listening on the socket.
  • Returns: The file descriptor of the created Unix socket, as an integer.
  • Raises SystemCallError if something went wrong.
/*
 * call-seq: create_unix_socket(filename, backlog)
 *
 * Create a SOCK_STREAM server Unix socket. Unlike Ruby's UNIXServer class,
 * this function is also able to create Unix sockets on the abstract namespace
 * by prepending the filename with a null byte.
 *
 * - +filename+ (string): The filename of the Unix socket to create.
 * - +backlog+ (integer): The backlog to use for listening on the socket.
 * - Returns: The file descriptor of the created Unix socket, as an integer.
 * - Raises +SystemCallError+ if something went wrong.
 */
static VALUE
create_unix_socket(VALUE self, VALUE filename, VALUE backlog) {

disable_stdio_buffering

Disables any kind of buffering on the C stdout and stderr variables, so that +fprintf()+ on stdout and stderr have immediate effect.

/*
 * call-seq: disable_stdio_buffering
 *
 * Disables any kind of buffering on the C +stdout+ and +stderr+ variables,
 * so that +fprintf()+ on +stdout+ and +stderr+ have immediate effect.
 */
static VALUE
disable_stdio_buffering(VALUE self) {

recv_fd(socket_fd)

Receive a file descriptor from the given Unix socket. Returns the received file descriptor as an integer. Raises SystemCallError if something went wrong.

You do not have call this method directly. A convenience wrapper is provided by IO#recv_io.

/*
 * call-seq: recv_fd(socket_fd)
 *
 * Receive a file descriptor from the given Unix socket. Returns the received
 * file descriptor as an integer. Raises +SystemCallError+ if something went
 * wrong.
 *
 * You do not have call this method directly. A convenience wrapper is
 * provided by IO#recv_io.
 */
static VALUE
recv_fd(VALUE self, VALUE socket_fd) {

send_fd(socket_fd, fd_to_send)

Send a file descriptor over the given Unix socket. You do not have to call this function directly. A convenience wrapper is provided by IO#send_io.

  • socket_fd (integer): The file descriptor of the socket.
  • fd_to_send (integer): The file descriptor to send.
  • Raises SystemCallError if something went wrong.
/*
 * call-seq: send_fd(socket_fd, fd_to_send)
 *
 * Send a file descriptor over the given Unix socket. You do not have to call
 * this function directly. A convenience wrapper is provided by IO#send_io.
 *
 * - +socket_fd+ (integer): The file descriptor of the socket.
 * - +fd_to_send+ (integer): The file descriptor to send.
 * - Raises +SystemCallError+ if something went wrong.
 */
static VALUE
send_fd(VALUE self, VALUE socket_fd, VALUE fd_to_send) {

split_by_null_into_hash(p1)

Split the given string into an hash. Keys and values are obtained by splitting the string using the null character as the delimitor.

/**
 * Split the given string into an hash. Keys and values are obtained by splitting the
 * string using the null character as the delimitor.
 */
static VALUE
split_by_null_into_hash(VALUE self, VALUE data) {

switch_user(p1, p2, p3)

Ruby‘s implementations of initgroups, setgid and setuid are broken various ways, sigh… Ruby‘s setgid and setuid can‘t handle negative UIDs and initgroups is just broken. Work around it by using our own implementation.

/**
 * Ruby's implementations of initgroups, setgid and setuid are broken various ways,
 * sigh...
 * Ruby's setgid and setuid can't handle negative UIDs and initgroups is just broken.
 * Work around it by using our own implementation.
 */
static VALUE
switch_user(VALUE self, VALUE username, VALUE uid, VALUE gid) {

writev(p1, p2)

Writes all of the strings in the components array into the given file descriptor using the +writev()+ system call. Unlike IO#write, this method does not require one to concatenate all those strings into a single buffer in order to send the data in a single system call. Thus, #writev is a great way to perform zero-copy I/O.

Unlike the raw writev() system call, this method ensures that all given data is written before returning, by performing multiple writev() calls and whatever else is necessary.

  writev(@socket.fileno, ["hello ", "world", "\n"])
/**
 * Writes all of the strings in the +components+ array into the given file
 * descriptor using the +writev()+ system call. Unlike IO#write, this method
 * does not require one to concatenate all those strings into a single buffer
 * in order to send the data in a single system call. Thus, #writev is a great
 * way to perform zero-copy I/O.
 *
 * Unlike the raw writev() system call, this method ensures that all given
 * data is written before returning, by performing multiple writev() calls
 * and whatever else is necessary.
 *
 *   writev(@socket.fileno, ["hello ", "world", "\n"])
 */
static VALUE
f_writev(VALUE self, VALUE fd, VALUE components) {

writev2(p1, p2, p3)

Like #writev, but accepts two arrays. The data is written in the given order.

  writev2(@socket.fileno, ["hello ", "world", "\n"], ["another ", "message\n"])
/**
 * Like #writev, but accepts two arrays. The data is written in the given order.
 *
 *   writev2(@socket.fileno, ["hello ", "world", "\n"], ["another ", "message\n"])
 */
static VALUE
f_writev2(VALUE self, VALUE fd, VALUE components1, VALUE components2) {

writev3(p1, p2, p3, p4)

Like #writev, but accepts three arrays. The data is written in the given order.

  writev3(@socket.fileno,
    ["hello ", "world", "\n"],
    ["another ", "message\n"],
    ["yet ", "another ", "one", "\n"])
/**
 * Like #writev, but accepts three arrays. The data is written in the given order.
 *
 *   writev3(@socket.fileno,
 *     ["hello ", "world", "\n"],
 *     ["another ", "message\n"],
 *     ["yet ", "another ", "one", "\n"])
 */
static VALUE
f_writev3(VALUE self, VALUE fd, VALUE components1, VALUE components2, VALUE components3) {