Section 9.4. Name and Bootstrap Servers


9.4. Name and Bootstrap Servers

Consider two programs communicating via Mach IPCsay, using the familiar client-server model. The server will have receive rights to a port, which is how it will receive request messages from a client. A client must possess send rights to such a port to send messages to the server. How does the client acquire these rights? A rather contrived and impractical way is that the server task creates the client task. As the client task's creator, the server task can manipulate the client task's port space. Specifically, the server task can insert send rights to the server port into the client's port space. A more reasonable alternativeone used in practiceis that every task is created with send rights to a system-wide server that acts as a trusted intermediary. Mach-based systems have such an intermediary: the Network Message Server (netmsgserver).

9.4.1. The Network Message Server

A Mach program desiring to receive messages on a port can publish the port through the netmsgserver. The publication process involves the server task registering the server port, along with an associated ASCII string name, with the netmsgserver. Since a client task will have send rights to a port that netmsgserver is listening on, it can send a lookup message containing the ASCII string associated with the desired service.

// ipc_common.h (shared between the client and the server) #define SERVICE_NAME "com.osxbook.SomeService" // ipc_server.c #include "ipc_common.h" ... kern_return_t kr; port_t server_port; server_port = mach_port_allocate(...); ... kr = netname_check_in(name_server_port,                       (netname_name_t)SERVICE_NAME,                       mach_task_self(),                       server_port); ...


The first argument to the netname_check_in call is the task's port to the Network Name Server. The global variable name_server_port represents send rights to the default system-wide name server. The second argument is the ASCII name of the service to be checked in. The third argument is a signaturetypically a port to which the calling task has send rights. The signature is required later, when checking out (i.e., removing the port from the name server's namespace) the server port, which is the fourth argument.

... kr = netname_check_out(name_server_port,                        (netname_name_t)SERVICE_NAME,                        mach_task_self()); ...


Once a server task checks in a port successfully, a client can look it up using the ASCII name that the server used for it.

// ipc_client.c #include "ipc_common.h" ... kern_return_t kr; port_t server_port; ... kr = netname_look_up(name_server_port,                      (netname_name_t)"*",                      (netname_name_t)SERVICE_NAME,                      &server_port); ...


The second argument is the host name whose Network Name Server is to be queried. An empty string represents the local host, whereas the "*" string specifies all hosts on the local network, resulting in a broadcast lookup.

We noted earlier that the design of Mach's IPC allows for transparent extension to a distributed environment, even though the kernel does not have any explicit support for distributed IPC. Two programs residing on different machines can communicate using Mach IPC if both machines are running an intermediary user-level program that extends Mach IPC across a network. The netmsgserver transparently handles servers and clients residing on different machines. Whereas it communicates with tasks on the local machine using regular, local Mach IPC, it can communicate with other netmsgserver tasks on the network using arbitrary networking protocols, forwarding messages sent to local proxy ports to the appropriate remote netmsgserver tasks. Thus, the netmsgserver works both as a name server (allowing a network-wide name registration of ports) and a proxy server for distributed IPC (performing network-transparent message transfers). Mac OS X provides a conceptually similar facility called Distributed Objects (see Section 9.14) for use by Cocoa programs.


9.4.2. The Bootstrap Server

Mac OS X does not provide a netmsgserver, or rather, it doesn't provide a network-capable netmsgserver. It does provide a local name serverthe Bootstrap Serverwhich allows tasks to publish ports that other tasks on the same machine can send messages to. The Bootstrap Server's functionality is provided by the bootstrap task, whose program encapsulation is the launchd program. Besides managing name-port bindings in its role as the Mach name server, the Bootstrap Server also initiates certain (typically on-demand) system daemonsspecifically those that have not been migrated to the higher-level server interface exported by launchd.

Why Use a Local Name Server?

The need for a local name server arises from the fact that Mach port namespaces are local to tasks. Even though the kernel manages port structures, there is no kernel-wide global port namespace. Exporting services to clients through Mach ports would involve sharing of ports that provide access to these services. To achieve this, an external entity must act as the port name server, allowing service names and associated ports to be registered and looked up.

The Bootstrap Server was originally created by NeXT for its NEXTSTEP operating system.


9.4.2.1. The Bootstrap Port

Each task has a bootstrap port that it inherits from its parent task. The bootstrap port allows a task to access various system services. The Bootstrap Server provides its own service port to its descendant tasks via their bootstrap ports. Therefore, all direct descendants of the Bootstrap Server receive privileged bootstrap ports. It is possible for a parent task to change its bootstrap port while creating a tasksay, to limit the set of services available to the child task. System services that execute untrusted tasks replace the Mach bootstrap task special port with a subset port. A task can retrieve its default bootstrap port by using task_get_bootstrap_port().

9.4.2.2. The Bootstrap Context

The scope of the bootstrap task's lookup mechanism available to a subsequent task, as determined by the latter task's bootstrap port, is referred to as the task's bootstrap context. In other words, a task's bootstrap context determines which services (the corresponding ports, that is) the task can look up. There is a single top-level bootstrap context when Mac OS X boots: the startup context. launchd executes in this context, and so do early system services that rely on being able to look up various Mach ports. Subsequent, less privileged bootstrap contexts can be created by the system for running programs that may be untrusted. For example, when a user logs in, the bootstrap task creates a login context, which is a subset of the startup context. All of a user's processes are in the login context.

More Context on Contexts

In general, if a process was started in a user's login context, its children are automatically in the login context. Similarly, a process running in the startup context will spawn children that run in the startup context as well, unless the parent explicitly calls the Bootstrap Server to create a subset context. Recall from Chapter 5 the example of a user logging in both graphically (through loginwindow.app, at the console) and through SSH. When a user logs in by providing a username and password to loginwindow.app's GUI (or automatically, if configured), a new login context is created for the user. Several user-specific services are present in the login context but not in the startup context. If the same user logs in at the console, by first providing >console as the username to loginwindow.app (which will cause it to exit, leading to launchd running a getty process on the console) and then typing his or her username and password, the user will be in the startup context. All programs in the chain of processes involved in the console loginlaunchd, getty, login, and the user's shellremain in the startup context because launchd runs in the startup context, and the others do not create any subset context.

Similarly, the SSH daemon is launched at system boot time in the startup context. Therefore, logging in via SSH will put the user in the startup context. We will see an example in Section 9.4.3.1 of using the bootstrap_info() call to retrieve information about all known services in a context. This call does not return information on services that are defined only in subset contexts, unless the subset port is an ancestor of the bootstrap port (bootstrap_port). Consequently, running our service-listing program will show different results depending on how you are logged in.


9.4.2.3. Debugging the Bootstrap Server

When experimenting with the Bootstrap Server or launchd in general, you may find it worthwhile to configure launchd to log debugging messages. You can arrange for log messages from launchd to be written to a file by adjusting launchd's log level and configuring the system log daemon (syslogd) not to ignore these messages. There are multiple ways to adjust launchd's log level.

If you wish to debug launchd from the point where it starts, you should create a system-wide launchd configuration file (/etc/launchd.conf) with the following contents:

# /etc/launchd.conf log level debug


When launchd starts, the contents of launchd.conf are run as subcommands through the launchctl program.

Setting a log-level value of debug will cause launchd to generate a substantial amount of debugging output.


Alternatively, you can create a per-user launchd configuration file (~/.launchd.conf), which will apply the log-level change only to the per-user local scope.

Moreover, if you only wish to change launchd's log level temporarily, you can run the launchctl program yourself.

launchd generates its log messages using the syslog(3) API. syslogd selects which messages to log based on rules specified in its configuration file (/etc/syslog.conf). The default rules do not include debugging or informational messages from launchd. You can temporarily log all launchd messages to a specific file by adding a rule such as the following to /etc/syslog.conf:

# /etc/syslog.conf ... launchd.*    /var/log/launchd_debug.log


Thereafter, you must either send syslogd a hangup signal (SIGHUP) or restart it. In particular, you can examine /var/log/launchd_debug.log after system startup to see subset bootstrap contexts being created and disabled as users log in and log out.

Registered service 2307 bootstrap 1103: com.apple.SecurityServer ... Service checkin attempt for service /usr/sbin/cupsd bootstrap 1103 bootstrap_check_in service /usr/sbin/cupsd unknown received message on port 1103 Handled request. Server create attempt: "/usr/sbin/cupsd -f" bootstrap 1103 adding new server "/usr/sbin/cupsd -f" with uid 0 Allocating port b503 for server /usr/sbin/cupsd -f New server b503 in bootstrap 1103: "/usr/sbin/cupsd -f" received message on port b503 Handled request. Service creation attempt for service /usr/sbin/cupsd bootstrap b503 Created new service b603 in bootstrap 1103: /usr/sbin/cupsd received message on port b503 Handled request. Service checkin attempt for service /usr/sbin/cups ... Subset create attempt: bootstrap 1103, requestor: ad07 Created bootstrap subset ac07 parent 1103 requestor ad07 ... Received dead name notification for bootstrap subset ac07 requestor port ad07 ...


9.4.3. The Bootstrap Server API

Let us first look at examples of functions supported by the Mac OS X Bootstrap Server, after which we will see examples of communicating with the server using these functions.

bootstrap_create_server() defines a server that can be launched and relaunched by the Bootstrap Server in the context corresponding to bootstrap_port.

kern_return_t bootstrap_create_server(mach_port_t  bootstrap_port,                         cmd_t        server_command,                         integer_t    server_uid,                         boolean_t    on_demand,                         mach_port_t *server_port);


The on_demand argument determines the relaunching behavior as managed by launchd. If on_demand is true, launchd will relaunch a nonrunning server when any of the registered service ports is used for the first time. If on_demand is false, launchd will relaunch the server as soon as the server exits, regardless of whether any of its service ports are in use. The server task created because of relaunching has server_port as its bootstrap port. The server abstraction created by this call is automatically deleted when all of its associated services are deleted and the server program has exited.

Services associated with the server can be declared by calling bootstrap_create_service(), with server_port (obtained by calling bootstrap_create_server()) specified as the bootstrap port in that call.

kern_return_t bootstrap_create_service(mach_port_t  bootstrap_port,                          name_t       service_name,                          mach_port_t *service_port);


bootstrap_create_service() creates a port and binds service_name to it. Send rights to the newly created port are returned in service_port. Later on, a service may call bootstrap_check_in() to check in the binding: In doing so, the caller will acquire receive rights for the bound port and the service will be made active. Thus, bootstrap_create_service() allows establishment of a name port binding before the backing service is even available. Lookups performed on bindings created by this mechanism return send rights to service_port, even if no service has checked in yet. If a caller uses such rights to send requests to the port, the messages will be queued until a server checks in.

kern_return_t bootstrap_check_in(mach_port_t  bootstrap_port,                    name_t       service_name,                    mach_port_t *service_port);


bootstrap_check_in() returns the receive rights for the service named by service_name, thus making the service active. The service must already be defined in the bootstrap context by an earlier call to bootstrap_create_service(). When used in conjunction with bootstrap_subset(), bootstrap_check_in() can be used to create services that are available only to a subset of tasks. It is an error to attempt to check in an already active service.

bootstrap_register() registers a send right for the service port specified by service_port, with service_name specifying the service.

kern_return_t bootstrap_register(mach_port_t bootstrap_port,                    name_t      service_name,                    mach_port_t service_port);


After a successful service registration, if a client looks up the service, the Bootstrap Server will provide send rights for the bound port to the client. Although you cannot register a service if an active binding already exists, you can register a service if an inactive binding exists. In the latter case, the existing service port, which the Bootstrap Server would have receive rights to, will be deallocated. In particular, if service_port is MACH_PORT_NULL, this can be used to undeclare (shut down) a declared service.

Each service created by the Bootstrap Server has an associated backup port, which the Bootstrap Server uses to detect when a service is no longer being served. When this happens, the Bootstrap Server regains all rights to the named port. Clients can continue to perform successful lookups on the port while the Bootstrap Server has receive rights to the port. If a client wishes to determine whether the service is active or not, it must call bootstrap_status(). A restarting service that wishes to resume serving existing clients must first attempt to call bootstrap_check_in() to prevent the original port from being destroyed.


bootstrap_look_up() returns send rights for the service port of the service specified by service_name. A successful return means that the service must have been either declared or registered under this name, although it is not guaranteed to be active. bootstrap_status() can be used to check whether the service is active.

kern_return_t bootstrap_look_up(mach_port_t     bootstrap_port,                   name_service_t  service_name,                   mach_port_t    *service_port);


bootstrap_look_up_array() returns send rights for the service ports of multiple services. The service_names array specifies the service names to look up, whereas the service_ports array contains the corresponding looked-up service ports. The Boolean out parameter all_services_known is true on return if all specified service names are known; it is false otherwise.

kern_return_t bootstrap_look_up_array(mach_port_t   bootstrap_port,                         name_array_t  service_names,                         int           service_names_cnt,                         port_array_t *service_port,                         int          *service_ports_cnt,                         boolean_t    *all_services_known);


bootstrap_status() returns whether a service is known to users of the specified bootstrap port and whether a server is able to receive messages on an associated service portthat is, whether the service is active. Note that if a service is known but not active, then the Bootstrap Server has receive rights for the service port.

kern_return_t bootstrap_status(mach_port_t         bootstrap_port,                  name_t              service_name,                  bootstrap_status_t *service_active);


bootstrap_info() returns information about all services that are known, except those that are defined only in subset contextsunless the subset port is an ancestor of bootstrap_port. The service_names array contains the names of all known services. The server_names array contains the namesif knownof the corresponding servers that provide the services. The service_active array contains a Boolean value for each name in the service_names array. This value is true for services that are receiving messages sent to their ports and false for the rest.

kern_return_t bootstrap_info(port_t        bootstrap_port,                name_array_t *service_names,                int          *service_names_cnt,                name_array_t *server_names,                int          *server_names_cnt,                bool_array_t *service_active,                int          *service_active_cnt);


bootstrap_subset() returns a new port to be used as a subset bootstrap port. The new port is similar to bootstrap_port, but any ports dynamically registered by calling bootstrap_register() are available only to tasks using subset_port or its descendants.

kern_return_t bootstrap_subset(mach_port_t  bootstrap_port,                  mach_port_t  requestor_port,                  mach_port_t *subset_port);


A lookup operation on subset_port will return not only ports registered with only subset_port but also ports registered with ancestors of subset_port. If the same service is registered with both subset_port and an ancestor port, a lookup for that service by a user of subset_port will fetch the subset_port version of the service. This way, services can be transparently customized for certain tasks without affecting the rest of the system, which can continue to use the default versions of the services in question. The lifespan of subset_port is determined by requestor_port; subset_port, its descendants, and any services advertised by these ports are all destroyed when requestor_port is destroyed.

bootstrap_parent() returns the parent bootstrap port of bootstrap_port, which is typically a bootstrap subset port. The calling task must have superuser privileges. For example, when called from a user login context, this function will return the bootstrap port corresponding to the startup context. When called from the startup context, the parent port returned is the same as the bootstrap port.

kern_return_t bootstrap_parent(mach_port_t  bootstrap_port,                  mach_port_t *parent_port);


The /usr/libexec/StartupItemContext program can be used to run an executable in the startup contextthat is, the context in which the Mac OS X startup items run. It works by calling bootstrap_parent() repeatedly until it has reached the startup (root) context. It then sets the port as its own bootstrap port, after which it can execute the requested program.


The automatic relaunching of servers by the Bootstrap Server is useful for creating crash-resistant servers. However, it is neither necessary nor advisable to create production servers by directly using the Bootstrap Server interface. Beginning with Mac OS X 10.4, the launch API,[8] as exported through <launch.h>, should be used. With this caveat, let us look at two examples of using the Bootstrap Server interface.

[8] Section 5.10.1.2 provides an example of using the launch API.

9.4.3.1. Displaying Information about All Known Services

In this example, we will use bootstrap_info() to retrieve a list of all known services that can be looked up in the bootstrap context associated with the given bootstrap port. Figure 915 shows the program.

Figure 915. Displaying information about all known services in a bootstrap context

// bootstrap_info.c #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <servers/bootstrap.h> int main(int argc, char **argv) {     kern_return_t            kr;     name_array_t             service_names, server_names;     bootstrap_status_array_t service_active;     unsigned int             service_names_count, server_names_count;     unsigned int             service_active_count, i;     // We can use bootstrap_port, a global variable declared in a Mach header,     // for the current task's bootstrap port. Alternatively, we can explicitly     // retrieve the same send right by calling task_get_bootstrap_port(),     // specifying mach_task_self() as the target task. This is how the system     // library initializes the global variable.     // launchd implements this routine     kr = bootstrap_info(bootstrap_port,                         &service_names,                         &service_names_count,                         &server_names,                         &server_names_count,                         &service_active,                         &service_active_count);     if (kr != BOOTSTRAP_SUCCESS) {         mach_error("bootstrap_info:", kr);         exit(1);     }     printf("%s %-48s %s\n%s %-48s %s\n", "up?", "service name", "server cmd",            "___", "____________", "__________");     for (i = 0; i < service_names_count; i++)         printf("%s %-48s %s\n",                (service_active[i]) ? "1  " : "0  ", service_names[i],                (server_names[i][0] == '\0') ? "-" : server_names[i]);     // The service_names, server_names, and service_active arrays have been     // vm_allocate()'d in our address space. Both "names" arrays are of type     // name_array_t, which is an array of name_t elements. A name_t in turn     // is a character string of length 128.     //     // As good programming practice, we should call vm_deallocate() to free up     // such virtual memory when it is not needed anymore.     (void)vm_deallocate(mach_task_self(), (vm_address_t)service_active,                         service_active_count * sizeof(service_active[0]));     (void)vm_deallocate(mach_task_self(), (vm_address_t)service_names,                         service_names_count * sizeof(service_names[0]));     (void)vm_deallocate(mach_task_self(), (vm_address_t)server_names,                         server_names_count * sizeof(server_names[0]));     exit(0); } $ gcc -Wall -o bootstrap_info bootstrap_info.c $ ./bootstrap_info up? service name                            server cmd ___ ____________                            __________ 1   com.apple.KernelExtensionServer         - ... 1   com.apple.SystemConfiguration.configd   /usr/sbin/configd ... 1   com.apple.iChatAgent                    - 1   com.apple.audio.SystemSoundClient-561   - 1   com.apple.FontObjectsServer_258         -

You can run the bootstrap_info program in different bootstrap contexts to see the differences in the services that are accessible from those contexts. For example, the program's output will be different when run from a shell in an SSH login compared with running it from a normal, graphical login. Similarly, using /usr/libexec/StartupItemContext to run bootstrap_info will list services in the startup context.

9.4.3.2. Creating a Crash-Resistant Server

In this example, we will create a dummy server that will be crash resistant in that if it exits unexpectedly, it will be relaunched by the Bootstrap Server. We will also provide a way for our server to explicitly arrange for its shutdown if it really wishes to exit. The server will provide a service named com.osxbook.DummySleeper (the server does nothing but sleep). The server executable will reside as /tmp/sleeperd. The server will check for the existence of a flag file, /tmp/sleeperd.off; if it exists, the server will turn itself off by calling bootstrap_register() with a null port as the service port. Figure 916 shows the program.

Figure 916. A crash-resistant server

// bootstrap_server.c #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> #include <asl.h> #include <mach/mach.h> #include <servers/bootstrap.h> #define SERVICE_NAME          "com.osxbook.DummySleeper" #define SERVICE_CMD           "/tmp/sleeperd" #define SERVICE_SHUTDOWN_FILE SERVICE_CMD ".off" static mach_port_t server_priv_port; static aslmsg      logmsg; // Note that asl_log() accepts the %m formatting character, which is // replaced by the ASL facility with the error string corresponding to // the errno variable's current value. #define MY_ASL_LOG(fmt, ...) \     asl_log(NULL, logmsg, ASL_LEVEL_ERR, fmt, ## __VA_ARGS__) static kern_return_t register_bootstrap_service(void) {     kern_return_t kr;     mach_port_t   service_send_port, service_rcv_port;     // Let us attempt to check in.... This routine will look up the service     // by name and attempt to return receive rights to the service port.     kr = bootstrap_check_in(bootstrap_port, (char *)SERVICE_NAME,                             &service_rcv_port);     if (kr == KERN_SUCCESS)         server_priv_port = bootstrap_port;     else if (kr == BOOTSTRAP_UNKNOWN_SERVICE) {         // The service does not exist, so let us create it....         kr = bootstrap_create_server(bootstrap_port,                                      SERVICE_CMD,                                      getuid(),       // server uid                                      FALSE,          // not on-demand                                      &server_priv_port);        if (kr != KERN_SUCCESS)            return kr;        // We can now use server_priv_port to declare services associated        // with this server by calling bootstrap_create_service() and passing        // server_priv_port as the bootstrap port.        // Create a service called SERVICE_NAME, and return send rights to        // that port in service_send_port.        kr = bootstrap_create_service(server_priv_port, (char *)SERVICE_NAME,                                      &service_send_port);        if (kr != KERN_SUCCESS) {            mach_port_deallocate(mach_task_self(), server_priv_port);            return kr;        }        // Check in and get receive rights to the service port of the service.        kr = bootstrap_check_in(server_priv_port, (char *)SERVICE_NAME,                                &service_rcv_port);        if (kr != KERN_SUCCESS) {            mach_port_deallocate(mach_task_self(), server_priv_port);            mach_port_deallocate(mach_task_self(), service_send_port);            return kr;        }     }     // We are not a Mach port server, so we do not need this port. However,     // we still will have a service with the Bootstrap Server, and so we     // will be relaunched if we exit.     mach_port_destroy(mach_task_self(), service_rcv_port);     return kr; } static kern_return_t unregister_bootstrap_service(void) {     return bootstrap_register(server_priv_port, (char *)SERVICE_NAME,                               MACH_PORT_NULL); } int main(void) {     kern_return_t kr;     struct stat   statbuf;     // Initialize a message for use with the Apple System Log (asl) facility.     logmsg = asl_new(ASL_TYPE_MSG);     asl_set(logmsg, "Facility", "Sleeper Daemon");     // If the shutdown flag file exists, we are destroying the service;     // otherwise, we are trying to be a server.     if (stat(SERVICE_SHUTDOWN_FILE, &statbuf) == 0) {         kr = unregister_bootstrap_service();         MY_ASL_LOG("destroying service %s\n", SERVICE_NAME);     } else {         kr = register_bootstrap_service();         MY_ASL_LOG("starting up service %s\n", SERVICE_NAME);     }     if (kr != KERN_SUCCESS) {         // NB: When unregistering, we will get here if the unregister succeeded.         mach_error("bootstrap_register", kr);         exit(kr);     }     MY_ASL_LOG("server loop ready\n");     while (1) // Dummy server loop.         sleep(60);     exit(0); }

Note that the program also shows an example of using the Apple System Logger (ASL) facility. Beginning with Mac OS X 10.4, the asl(3) interface is available as a replacement for the syslog(3) logging interface. Besides logging, the ASL facility provides functions for querying logged messages. Section 10.8.3 contains an overview of logging in Mac OS X. Our server logs a few messages at the ASL_LEVEL_ERR log level. These messages will be written to both /var/log/system.log and /var/log/asl.log. Moreover, if launchd's debugging output is enabled (as described in Section 9.4.2.3), you will see detailed log messages corresponding to the Bootstrap Server calls made by our program.

$ gcc -Wall -o /tmp/sleeperd bootstrap_server.c $ /tmp/sleeperd


Apple System Logger (ASL)

The ASL facility allows structured log messages that consist of string-based key-value dictionaries. The facility provides several predefined keys, such as for priority level, process ID, time, and message sender. An application can extend the message dictionary by defining its own keys. Moreover, applications need not be concerned about the whereabouts of log filesASL stores messages in a single data store. The ASL interface includes functions for constructing queries and searching for log messages based on those queries.

Beginning with Mac OS X 10.4, the syslogd program is the ASL daemon, although it provides backward compatibility with previous syslogd implementations. ASL also supports message filtering both in the client library and in syslogd.


Since our server does not fork and performs no operation other than sleeping, it will hang on running. We can examine the launchd log at this point to see the relevant messages, which are shown annotated, with prefixes removed, in Figure 917.

Figure 917. launchd debug messages corresponding to a Mach server's initialization

# server -> bootstrap_check_in() Service checkin attempt for service com.osxbook.DummySleeper bootstrap 5103 bootstrap_check_in service com.osxbook.DummySleeper unknown received message on port 5103 ... # server -> bootstrap_create_server() Server create attempt: "/tmp/sleeperd" bootstrap 5103 adding new server "/tmp/sleeperd" with uid 501 Allocating port f70f for server /tmp/sleeperd New server f70f in bootstrap 5103: "/tmp/sleeperd" ... # server -> bootstrap_create_service() Service creation attempt for service com.osxbook.DummySleeper bootstrap f70f Created new service c19f in bootstrap 5103: com.osxbook.DummySleeper ... # server -> bootstrap_check_in() Service checkin attempt for service com.osxbook.DummySleeper bootstrap f70f Checkin service com.osxbook.DummySleeper for bootstrap 5103 Check-in service c19f in bootstrap 5103: com.osxbook.DummySleeper ... # server -> mach_port_destroy() received destroyed notification for service com.osxbook.DummySleeper Service f797 bootstrap 5103 backed up: com.osxbook.DummySleeper ...

Let us kill the server by sending it the interrupt signalthat is, by typing ctrl-c in the shell from which we executed /tmp/sleeperd. We can then verify that the server was indeed relaunched.

^C $ ps -ax | grep sleeperd 2364  ?? Ss    0:00.01 /tmp/sleeperd


Let us examine launchd's log again (Figure 918).

Figure 918. launchd debug messages corresponding to a Mach server's relaunch

... # server died; will be relaunched server /tmp/sleeperd dropped server port Allocating port f627 for server /tmp/sleeperd Launched server f627 in bootstrap 5103 uid 501: "/tmp/sleeperd": [pid 2364] received message on port f627 # server-> bootstrap_check_in() Service checkin attempt for service com.osxbook.DummySleeper bootstrap f627 Checkin service com.osxbook.DummySleeper for bootstrap 5103 Check-in service f797 in bootstrap 5103: com.osxbook.DummySleeper ... # server -> mach_port_destroy() Received destroyed notification for service com.osxbook.DummySleeper Service f797 bootstrap 5103 backed up: com.osxbook.DummySleeper ...

We can see that certain log messages are different from when we executed /tmp/sleeperd for the first time. In the first case, both a new server and a new service were created. In this case, when launchd respawns the server, the server's first attempt to call bootstrap_check_in() succeeds because the service already exists.

Now, even if we kill the server process by sending it SIGKILL, launchd will relaunch it. We can cause the server to terminate permanently by creating the /tmp/sleeperd.off file.

$ touch /tmp/sleeperd.off $ kill -TERM 2344 $ ps -ax | grep sleeperd $


The log messages will show that launchd relaunched our server even this time. However, instead of calling bootstrap_check_in(), the server calls bootstrap_register() with MACH_PORT_NULL specified as the service port, which makes the service unavailable.

... # server died received message on port f627 server /tmp/sleeperd dropped server port received message on port f03 Notified dead name c1ab Received task death notification for server /tmp/sleeperd waitpid: cmd = /tmp/sleeperd: No child processes # launchd is attempting to relaunch Allocating port f62b for server /tmp/sleeperd Launched server f62b in bootstrap 5103 uid 501: "/tmp/sleeperd": [pid 2380] ... # server -> bootstrap_register(..., MACH_PORT_NULL) server /tmp/sleeperd dropped server port received message on port f03 Notified dead name f84f # server -> exit() Received task death notification for server /tmp/sleeperd waitpid: cmd = /tmp/sleeperd: No child processes Deleting server /tmp/sleeperd Declared service com.osxbook.DummySleeper now unavailable ...





Mac OS X Internals. A Systems Approach
Mac OS X Internals: A Systems Approach
ISBN: 0321278542
EAN: 2147483647
Year: 2006
Pages: 161
Authors: Amit Singh

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net