2  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  23 #include <CoreFoundation/CoreFoundation.h> 
  24 #include <sys/types.h> 
  27 #include <sys/socket.h> 
  29 #include <sys/fcntl.h> 
  30 #include <sys/event.h> 
  31 #include <sys/resource.h> 
  32 #include <sys/param.h> 
  33 #include <netinet/in.h> 
  44 #include <readline/readline.h> 
  45 #include <readline/history.h> 
  49 #include "launch_priv.h" 
  51 #define LAUNCH_SECDIR "/tmp/launch-XXXXXX" 
  53 static bool launch_data_array_append(launch_data_t a
, launch_data_t o
); 
  54 static void distill_config_file(launch_data_t
); 
  55 static void sock_dict_cb(launch_data_t what
, const char *key
, void *context
); 
  56 static void sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
); 
  57 static launch_data_t 
CF2launch_data(CFTypeRef
); 
  58 static launch_data_t 
read_plist_file(const char *file
, bool editondisk
, bool load
); 
  59 static CFPropertyListRef 
CreateMyPropertyListFromFile(const char *); 
  60 static void WriteMyPropertyListToFile(CFPropertyListRef
, const char *); 
  61 static void readpath(const char *, launch_data_t
, launch_data_t
, bool editondisk
, bool load
); 
  63 static int demux_cmd(int argc
, char *const argv
[]); 
  64 static launch_data_t 
do_rendezvous_magic(const struct addrinfo 
*res
, const char *serv
); 
  65 static void submit_job_pass(launch_data_t jobs
); 
  67 static int load_and_unload_cmd(int argc
, char *const argv
[]); 
  68 //static int reload_cmd(int argc, char *const argv[]); 
  69 static int start_and_stop_cmd(int argc
, char *const argv
[]); 
  70 static int list_cmd(int argc
, char *const argv
[]); 
  72 static int setenv_cmd(int argc
, char *const argv
[]); 
  73 static int unsetenv_cmd(int argc
, char *const argv
[]); 
  74 static int getenv_and_export_cmd(int argc
, char *const argv
[]); 
  76 static int limit_cmd(int argc
, char *const argv
[]); 
  77 static int stdio_cmd(int argc
, char *const argv
[]); 
  78 static int fyi_cmd(int argc
, char *const argv
[]); 
  79 static int logupdate_cmd(int argc
, char *const argv
[]); 
  80 static int umask_cmd(int argc
, char *const argv
[]); 
  81 static int getrusage_cmd(int argc
, char *const argv
[]); 
  83 static int help_cmd(int argc
, char *const argv
[]); 
  87         int (*func
)(int argc
, char *const argv
[]); 
  90         { "load",       load_and_unload_cmd
,    "Load configuration files and/or directories" }, 
  91         { "unload",     load_and_unload_cmd
,    "Unload configuration files and/or directories" }, 
  92 //      { "reload",     reload_cmd,             "Reload configuration files and/or directories" }, 
  93         { "start",      start_and_stop_cmd
,     "Start specified jobs" }, 
  94         { "stop",       start_and_stop_cmd
,     "Stop specified jobs" }, 
  95         { "list",       list_cmd
,               "List jobs and information about jobs" }, 
  96         { "setenv",     setenv_cmd
,             "Set an environmental variable in launchd" }, 
  97         { "unsetenv",   unsetenv_cmd
,           "Unset an environmental variable in launchd" }, 
  98         { "getenv",     getenv_and_export_cmd
,  "Get an environmental variable from launchd" }, 
  99         { "export",     getenv_and_export_cmd
,  "Export shell settings from launchd" }, 
 100         { "limit",      limit_cmd
,              "View and adjust launchd resource limits" }, 
 101         { "stdout",     stdio_cmd
,              "Redirect launchd's standard out to the given path" }, 
 102         { "stderr",     stdio_cmd
,              "Redirect launchd's standard error to the given path" }, 
 103         { "shutdown",   fyi_cmd
,                "Prepare for system shutdown" }, 
 104         { "reloadttys", fyi_cmd
,                "Reload /etc/ttys" }, 
 105         { "getrusage",  getrusage_cmd
,          "Get resource usage statistics from launchd" }, 
 106         { "log",        logupdate_cmd
,          "Adjust the logging level or mask of launchd" }, 
 107         { "umask",      umask_cmd
,              "Change launchd's umask" }, 
 108         { "help",       help_cmd
,               "This help output" }, 
 111 int main(int argc
, char *const argv
[]) 
 113         bool istty 
= isatty(STDIN_FILENO
); 
 117                 exit(demux_cmd(argc 
- 1, argv 
+ 1)); 
 119         if (NULL 
== readline
) { 
 120                 fprintf(stderr
, "missing library: readline\n"); 
 124         while ((l 
= readline(istty 
? "launchd% " : NULL
))) { 
 125                 char *inputstring 
= l
, *argv2
[100], **ap 
= argv2
; 
 128                 while ((*ap 
= strsep(&inputstring
, " \t"))) { 
 147 static int demux_cmd(int argc
, char *const argv
[]) 
 154         for (i 
= 0; i 
< (sizeof cmds 
/ sizeof cmds
[0]); i
++) { 
 155                 if (!strcmp(cmds
[i
].name
, argv
[0])) 
 156                         return cmds
[i
].func(argc
, argv
); 
 159         fprintf(stderr
, "%s: unknown subcommand \"%s\"\n", getprogname(), argv
[0]); 
 163 static int unsetenv_cmd(int argc
, char *const argv
[]) 
 165         launch_data_t resp
, tmp
, msg
; 
 168                 fprintf(stderr
, "%s usage: unsetenv <key>\n", getprogname()); 
 172         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 174         tmp 
= launch_data_new_string(argv
[1]); 
 175         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_UNSETUSERENVIRONMENT
); 
 177         resp 
= launch_msg(msg
); 
 179         launch_data_free(msg
); 
 182                 launch_data_free(resp
); 
 184                 fprintf(stderr
, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_UNSETUSERENVIRONMENT
, strerror(errno
)); 
 190 static int setenv_cmd(int argc
, char *const argv
[]) 
 192         launch_data_t resp
, tmp
, tmpv
, msg
; 
 195                 fprintf(stderr
, "%s usage: setenv <key> <value>\n", getprogname()); 
 199         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 200         tmp 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 202         tmpv 
= launch_data_new_string(argv
[2]); 
 203         launch_data_dict_insert(tmp
, tmpv
, argv
[1]); 
 204         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETUSERENVIRONMENT
); 
 206         resp 
= launch_msg(msg
); 
 207         launch_data_free(msg
); 
 210                 launch_data_free(resp
); 
 212                 fprintf(stderr
, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_SETUSERENVIRONMENT
, strerror(errno
)); 
 218 static int getenv_and_export_cmd(int argc
, char *const argv
[] __attribute__((unused
))) 
 220         launch_data_t resp
, msg
; 
 223         void print_launchd_env(launch_data_t obj
, const char *key
, void *context 
__attribute__((unused
))) { 
 225                         fprintf(stdout
, "setenv %s %s;\n", key
, launch_data_get_string(obj
)); 
 227                         fprintf(stdout
, "%s=%s; export %s;\n", key
, launch_data_get_string(obj
), key
); 
 229         void print_key_value(launch_data_t obj
, const char *key
, void *context 
__attribute__((unused
))) { 
 231                         fprintf(stdout
, "%s\n", launch_data_get_string(obj
)); 
 234         if (!strcmp(argv
[0], "export")) { 
 235                 char *s 
= getenv("SHELL"); 
 237                         is_csh 
= strstr(s
, "csh") ? true : false; 
 238         } else if (argc 
!= 2) { 
 239                 fprintf(stderr
, "%s usage: getenv <key>\n", getprogname()); 
 245         msg 
= launch_data_new_string(LAUNCH_KEY_GETUSERENVIRONMENT
); 
 247         resp 
= launch_msg(msg
); 
 248         launch_data_free(msg
); 
 251                 launch_data_dict_iterate(resp
, (!strcmp(argv
[0], "export")) ? print_launchd_env 
: print_key_value
, NULL
); 
 252                 launch_data_free(resp
); 
 254                 fprintf(stderr
, "launch_msg(\"" LAUNCH_KEY_GETUSERENVIRONMENT 
"\"): %s\n", strerror(errno
)); 
 259 static void unloadjob(launch_data_t job
) 
 261         launch_data_t resp
, tmp
, tmps
, msg
; 
 264         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 265         tmp 
= launch_data_alloc(LAUNCH_DATA_STRING
); 
 266         tmps 
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LABEL
); 
 269                 fprintf(stderr
, "%s: Error: Missing Key: %s\n", getprogname(), LAUNCH_JOBKEY_LABEL
); 
 273         launch_data_set_string(tmp
, launch_data_get_string(tmps
)); 
 274         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_REMOVEJOB
); 
 275         resp 
= launch_msg(msg
); 
 276         launch_data_free(msg
); 
 278                 fprintf(stderr
, "%s: Error: launch_msg(): %s\n", getprogname(), strerror(errno
)); 
 281         if (LAUNCH_DATA_ERRNO 
== launch_data_get_type(resp
)) { 
 282                 if ((e 
= launch_data_get_errno(resp
))) 
 283                         fprintf(stderr
, "%s\n", strerror(e
)); 
 285         launch_data_free(resp
); 
 288 static launch_data_t 
read_plist_file(const char *file
, bool editondisk
, bool load
) 
 290         CFPropertyListRef plist 
= CreateMyPropertyListFromFile(file
); 
 291         launch_data_t r 
= NULL
; 
 294                 fprintf(stderr
, "%s: no plist was returned for: %s\n", getprogname(), file
); 
 300                         CFDictionaryRemoveValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
)); 
 302                         CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
), kCFBooleanTrue
); 
 303                 WriteMyPropertyListToFile(plist
, file
); 
 306         r 
= CF2launch_data(plist
); 
 313 static void delay_to_second_pass2(launch_data_t o
, const char *key
, void *context
) 
 318         if (key 
&& 0 == strcmp(key
, LAUNCH_JOBSOCKETKEY_BONJOUR
)) { 
 323         switch (launch_data_get_type(o
)) { 
 324         case LAUNCH_DATA_DICTIONARY
: 
 325                 launch_data_dict_iterate(o
, delay_to_second_pass2
, context
); 
 327         case LAUNCH_DATA_ARRAY
: 
 328                 for (i 
= 0; i 
< launch_data_array_get_count(o
); i
++) 
 329                         delay_to_second_pass2(launch_data_array_get_index(o
, i
), NULL
, context
); 
 336 static bool delay_to_second_pass(launch_data_t o
) 
 340         launch_data_t socks 
= launch_data_dict_lookup(o
, LAUNCH_JOBKEY_SOCKETS
); 
 345         delay_to_second_pass2(socks
, NULL
, &res
); 
 350 static void readfile(const char *what
, launch_data_t pass1
, launch_data_t pass2
, bool editondisk
, bool load
) 
 352         launch_data_t tmpd
, thejob
; 
 353         bool job_disabled 
= false; 
 355         if (NULL 
== (thejob 
= read_plist_file(what
, editondisk
, load
))) { 
 356                 fprintf(stderr
, "%s: no plist was returned for: %s\n", getprogname(), what
); 
 360         if ((tmpd 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_DISABLED
))) 
 361                 job_disabled 
= launch_data_get_bool(tmpd
); 
 363         if (job_disabled 
&& load
) { 
 364                 launch_data_free(thejob
); 
 368         if (delay_to_second_pass(thejob
)) 
 369                 launch_data_array_append(pass2
, thejob
); 
 371                 launch_data_array_append(pass1
, thejob
); 
 374 static void readpath(const char *what
, launch_data_t pass1
, launch_data_t pass2
, bool editondisk
, bool load
) 
 376         char buf
[MAXPATHLEN
]; 
 381         if (stat(what
, &sb
) == -1) 
 384         if (S_ISREG(sb
.st_mode
) && !(sb
.st_mode 
& S_IWOTH
)) { 
 385                 readfile(what
, pass1
, pass2
, editondisk
, load
); 
 387                 if ((d 
= opendir(what
)) == NULL
) { 
 388                         fprintf(stderr
, "%s: opendir() failed to open the directory\n", getprogname()); 
 392                 while ((de 
= readdir(d
))) { 
 393                         if ((de
->d_name
[0] == '.')) 
 395                         snprintf(buf
, sizeof(buf
), "%s/%s", what
, de
->d_name
); 
 397                         readfile(buf
, pass1
, pass2
, editondisk
, load
); 
 403 struct distill_context 
{ 
 405         launch_data_t newsockdict
; 
 408 static void distill_config_file(launch_data_t id_plist
) 
 410         struct distill_context dc 
= { id_plist
, NULL 
}; 
 413         if ((tmp 
= launch_data_dict_lookup(id_plist
, LAUNCH_JOBKEY_SOCKETS
))) { 
 414                 dc
.newsockdict 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 415                 launch_data_dict_iterate(tmp
, sock_dict_cb
, &dc
); 
 416                 launch_data_dict_insert(dc
.base
, dc
.newsockdict
, LAUNCH_JOBKEY_SOCKETS
); 
 420 static void sock_dict_cb(launch_data_t what
, const char *key
, void *context
) 
 422         struct distill_context 
*dc 
= context
; 
 423         launch_data_t fdarray 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 425         launch_data_dict_insert(dc
->newsockdict
, fdarray
, key
); 
 427         if (launch_data_get_type(what
) == LAUNCH_DATA_DICTIONARY
) { 
 428                 sock_dict_edit_entry(what
, key
, fdarray
, dc
->base
); 
 429         } else if (launch_data_get_type(what
) == LAUNCH_DATA_ARRAY
) { 
 433                 for (i 
= 0; i 
< launch_data_array_get_count(what
); i
++) { 
 434                         tmp 
= launch_data_array_get_index(what
, i
); 
 435                         sock_dict_edit_entry(tmp
, key
, fdarray
, dc
->base
); 
 440 static void sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
) 
 442         launch_data_t a
, val
; 
 443         int sfd
, st 
= SOCK_STREAM
; 
 446         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_TYPE
))) { 
 447                 if (!strcasecmp(launch_data_get_string(val
), "stream")) { 
 449                 } else if (!strcasecmp(launch_data_get_string(val
), "dgram")) { 
 451                 } else if (!strcasecmp(launch_data_get_string(val
), "seqpacket")) { 
 456         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PASSIVE
))) 
 457                 passive 
= launch_data_get_bool(val
); 
 459         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SECUREWITHKEY
))) { 
 460                 char secdir
[] = LAUNCH_SECDIR
, buf
[1024]; 
 461                 launch_data_t uenv 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
); 
 464                         uenv 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 465                         launch_data_dict_insert(thejob
, uenv
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
); 
 470                 sprintf(buf
, "%s/%s", secdir
, key
); 
 472                 a 
= launch_data_new_string(buf
); 
 473                 launch_data_dict_insert(tmp
, a
, LAUNCH_JOBSOCKETKEY_PATHNAME
); 
 474                 a 
= launch_data_new_string(buf
); 
 475                 launch_data_dict_insert(uenv
, a
, launch_data_get_string(val
)); 
 478         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHNAME
))) { 
 479                 struct sockaddr_un sun
; 
 481                 memset(&sun
, 0, sizeof(sun
)); 
 483                 sun
.sun_family 
= AF_UNIX
; 
 485                 strncpy(sun
.sun_path
, launch_data_get_string(val
), sizeof(sun
.sun_path
)); 
 487                 if ((sfd 
= _fd(socket(AF_UNIX
, st
, 0))) == -1) 
 491                         if (unlink(sun
.sun_path
) == -1 && errno 
!= ENOENT
) { 
 495                         if (bind(sfd
, (struct sockaddr 
*)&sun
, sizeof(sun
)) == -1) { 
 499                         if ((st 
== SOCK_STREAM 
|| st 
== SOCK_SEQPACKET
) 
 500                                         && listen(sfd
, SOMAXCONN
) == -1) { 
 504                 } else if (connect(sfd
, (struct sockaddr 
*)&sun
, sizeof(sun
)) == -1) { 
 509                 val 
= launch_data_new_fd(sfd
); 
 510                 launch_data_array_append(fdarray
, val
); 
 512                 launch_data_t rnames 
= NULL
; 
 513                 const char *node 
= NULL
, *serv 
= NULL
; 
 515                 struct addrinfo hints
, *res0
, *res
; 
 516                 int gerr
, sock_opt 
= 1; 
 517                 bool rendezvous 
= false; 
 519                 memset(&hints
, 0, sizeof(hints
)); 
 521                 hints
.ai_socktype 
= st
; 
 523                         hints
.ai_flags 
|= AI_PASSIVE
; 
 525                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_NODENAME
))) 
 526                         node 
= launch_data_get_string(val
); 
 527                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SERVICENAME
))) { 
 528                         if (LAUNCH_DATA_INTEGER 
== launch_data_get_type(val
)) { 
 529                                 sprintf(servnbuf
, "%lld", launch_data_get_integer(val
)); 
 532                                 serv 
= launch_data_get_string(val
); 
 535                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_FAMILY
))) { 
 536                         if (!strcasecmp("IPv4", launch_data_get_string(val
))) 
 537                                 hints
.ai_family 
= AF_INET
; 
 538                         else if (!strcasecmp("IPv6", launch_data_get_string(val
))) 
 539                                 hints
.ai_family 
= AF_INET6
; 
 541                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PROTOCOL
))) { 
 542                         if (!strcasecmp("TCP", launch_data_get_string(val
))) 
 543                                 hints
.ai_protocol 
= IPPROTO_TCP
; 
 545                 if ((rnames 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_BONJOUR
))) { 
 547                         if (LAUNCH_DATA_BOOL 
== launch_data_get_type(rnames
)) { 
 548                                 rendezvous 
= launch_data_get_bool(rnames
); 
 553                 if ((gerr 
= getaddrinfo(node
, serv
, &hints
, &res0
)) != 0) { 
 554                         fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(gerr
)); 
 558                 for (res 
= res0
; res
; res 
= res
->ai_next
) { 
 559                         launch_data_t rvs_fd 
= NULL
; 
 560                         if ((sfd 
= _fd(socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
))) == -1) { 
 561                                 fprintf(stderr
, "socket(): %s\n", strerror(errno
)); 
 564                         if (hints
.ai_flags 
& AI_PASSIVE
) { 
 565                                 if (AF_INET6 
== res
->ai_family 
&& -1 == setsockopt(sfd
, IPPROTO_IPV6
, IPV6_V6ONLY
, 
 566                                                         (void *)&sock_opt
, sizeof(sock_opt
))) { 
 567                                         fprintf(stderr
, "setsockopt(IPV6_V6ONLY): %m"); 
 570                                 if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&sock_opt
, sizeof(sock_opt
)) == -1) { 
 571                                         fprintf(stderr
, "socket(): %s\n", strerror(errno
)); 
 574                                 if (bind(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) { 
 575                                         fprintf(stderr
, "bind(): %s\n", strerror(errno
)); 
 578                                 if ((res
->ai_socktype 
== SOCK_STREAM 
|| res
->ai_socktype 
== SOCK_SEQPACKET
) 
 579                                                 && listen(sfd
, SOMAXCONN
) == -1) { 
 580                                         fprintf(stderr
, "listen(): %s\n", strerror(errno
)); 
 583                                 if (rendezvous 
&& (res
->ai_family 
== AF_INET 
|| res
->ai_family 
== AF_INET6
) && 
 584                                                 (res
->ai_socktype 
== SOCK_STREAM 
|| res
->ai_socktype 
== SOCK_DGRAM
)) { 
 585                                         launch_data_t rvs_fds 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_BONJOURFDS
); 
 586                                         if (NULL 
== rvs_fds
) { 
 587                                                 rvs_fds 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 588                                                 launch_data_dict_insert(thejob
, rvs_fds
, LAUNCH_JOBKEY_BONJOURFDS
); 
 590                                         if (NULL 
== rnames
) { 
 591                                                 rvs_fd 
= do_rendezvous_magic(res
, serv
); 
 593                                                         launch_data_array_append(rvs_fds
, rvs_fd
); 
 594                                         } else if (LAUNCH_DATA_STRING 
== launch_data_get_type(rnames
)) { 
 595                                                 rvs_fd 
= do_rendezvous_magic(res
, launch_data_get_string(rnames
)); 
 597                                                         launch_data_array_append(rvs_fds
, rvs_fd
); 
 598                                         } else if (LAUNCH_DATA_ARRAY 
== launch_data_get_type(rnames
)) { 
 599                                                 size_t rn_i
, rn_ac 
= launch_data_array_get_count(rnames
); 
 601                                                 for (rn_i 
= 0; rn_i 
< rn_ac
; rn_i
++) { 
 602                                                         launch_data_t rn_tmp 
= launch_data_array_get_index(rnames
, rn_i
); 
 604                                                         rvs_fd 
= do_rendezvous_magic(res
, launch_data_get_string(rn_tmp
)); 
 606                                                                 launch_data_array_append(rvs_fds
, rvs_fd
); 
 611                                 if (connect(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) { 
 612                                         fprintf(stderr
, "connect(): %s\n", strerror(errno
)); 
 616                         val 
= launch_data_new_fd(sfd
); 
 618                                 /* <rdar://problem/3964648> Launchd should not register the same service more than once */ 
 619                                 /* <rdar://problem/3965154> Switch to DNSServiceRegisterAddrInfo() */ 
 622                         launch_data_array_append(fdarray
, val
); 
 627 static launch_data_t 
do_rendezvous_magic(const struct addrinfo 
*res
, const char *serv
) 
 630         DNSServiceRef service
; 
 631         DNSServiceErrorType error
; 
 634         static int statres 
= 1; 
 637                 statres 
= stat("/usr/sbin/mDNSResponder", &sb
); 
 642         sprintf(rvs_buf
, "_%s._%s.", serv
, res
->ai_socktype 
== SOCK_STREAM 
? "tcp" : "udp"); 
 644         if (res
->ai_family 
== AF_INET
) 
 645                 port 
= ((struct sockaddr_in 
*)res
->ai_addr
)->sin_port
; 
 647                 port 
= ((struct sockaddr_in6 
*)res
->ai_addr
)->sin6_port
; 
 649         error 
= DNSServiceRegister(&service
, 0, 0, NULL
, rvs_buf
, NULL
, NULL
, port
, 0, NULL
, NULL
, NULL
); 
 651         if (error 
== kDNSServiceErr_NoError
) 
 652                 return launch_data_new_fd(DNSServiceRefSockFD(service
)); 
 654         fprintf(stderr
, "DNSServiceRegister(\"%s\"): %d\n", serv
, error
); 
 658 static CFPropertyListRef 
CreateMyPropertyListFromFile(const char *posixfile
) 
 660         CFPropertyListRef propertyList
; 
 661         CFStringRef       errorString
; 
 662         CFDataRef         resourceData
; 
 666         fileURL 
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, posixfile
, strlen(posixfile
), false); 
 668                 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
); 
 669         if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
)) 
 670                 fprintf(stderr
, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
); 
 671         propertyList 
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, resourceData
, kCFPropertyListMutableContainers
, &errorString
); 
 673                 fprintf(stderr
, "%s: propertyList is NULL\n", getprogname()); 
 678 static void WriteMyPropertyListToFile(CFPropertyListRef plist
, const char *posixfile
) 
 680         CFDataRef       resourceData
; 
 684         fileURL 
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, posixfile
, strlen(posixfile
), false); 
 686                 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
); 
 687         resourceData 
= CFPropertyListCreateXMLData(kCFAllocatorDefault
, plist
); 
 688         if (resourceData 
== NULL
) 
 689                 fprintf(stderr
, "%s: CFPropertyListCreateXMLData(%s) failed", getprogname(), posixfile
); 
 690         if (!CFURLWriteDataAndPropertiesToResource(fileURL
, resourceData
, NULL
, &errorCode
)) 
 691                 fprintf(stderr
, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
); 
 694 void myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
) 
 696         launch_data_t ik
, iw
, where 
= context
; 
 698         ik 
= CF2launch_data(key
); 
 699         iw 
= CF2launch_data(value
); 
 701         launch_data_dict_insert(where
, iw
, launch_data_get_string(ik
)); 
 702         launch_data_free(ik
); 
 705 static launch_data_t 
CF2launch_data(CFTypeRef cfr
) 
 708         CFTypeID cft 
= CFGetTypeID(cfr
); 
 710         if (cft 
== CFStringGetTypeID()) { 
 712                 CFStringGetCString(cfr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
); 
 713                 r 
= launch_data_alloc(LAUNCH_DATA_STRING
); 
 714                 launch_data_set_string(r
, buf
); 
 715         } else if (cft 
== CFBooleanGetTypeID()) { 
 716                 r 
= launch_data_alloc(LAUNCH_DATA_BOOL
); 
 717                 launch_data_set_bool(r
, CFBooleanGetValue(cfr
)); 
 718         } else if (cft 
== CFArrayGetTypeID()) { 
 719                 CFIndex i
, ac 
= CFArrayGetCount(cfr
); 
 720                 r 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 721                 for (i 
= 0; i 
< ac
; i
++) { 
 722                         CFTypeRef v 
= CFArrayGetValueAtIndex(cfr
, i
); 
 724                                 launch_data_t iv 
= CF2launch_data(v
); 
 725                                 launch_data_array_set_index(r
, iv
, i
); 
 728         } else if (cft 
== CFDictionaryGetTypeID()) { 
 729                 r 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 730                 CFDictionaryApplyFunction(cfr
, myCFDictionaryApplyFunction
, r
); 
 731         } else if (cft 
== CFDataGetTypeID()) { 
 732                 r 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 733                 launch_data_set_opaque(r
, CFDataGetBytePtr(cfr
), CFDataGetLength(cfr
)); 
 734         } else if (cft 
== CFNumberGetTypeID()) { 
 737                 CFNumberType cfnt 
= CFNumberGetType(cfr
); 
 739                 case kCFNumberSInt8Type
: 
 740                 case kCFNumberSInt16Type
: 
 741                 case kCFNumberSInt32Type
: 
 742                 case kCFNumberSInt64Type
: 
 743                 case kCFNumberCharType
: 
 744                 case kCFNumberShortType
: 
 745                 case kCFNumberIntType
: 
 746                 case kCFNumberLongType
: 
 747                 case kCFNumberLongLongType
: 
 748                         CFNumberGetValue(cfr
, kCFNumberLongLongType
, &n
); 
 749                         r 
= launch_data_alloc(LAUNCH_DATA_INTEGER
); 
 750                         launch_data_set_integer(r
, n
); 
 752                 case kCFNumberFloat32Type
: 
 753                 case kCFNumberFloat64Type
: 
 754                 case kCFNumberFloatType
: 
 755                 case kCFNumberDoubleType
: 
 756                         CFNumberGetValue(cfr
, kCFNumberDoubleType
, &d
); 
 757                         r 
= launch_data_alloc(LAUNCH_DATA_REAL
); 
 758                         launch_data_set_real(r
, d
); 
 770 static int help_cmd(int argc
, char *const argv
[]) 
 772         FILE *where 
= stdout
; 
 776         if (argc 
== 0 || argv 
== NULL
) 
 779         fprintf(where
, "usage: %s <subcommand>\n", getprogname()); 
 780         for (i 
= 0; i 
< (sizeof cmds 
/ sizeof cmds
[0]); i
++) { 
 781                 l 
= strlen(cmds
[i
].name
); 
 785         for (i 
= 0; i 
< (sizeof cmds 
/ sizeof cmds
[0]); i
++) 
 786                 fprintf(where
, "\t%-*s\t%s\n", cmdwidth
, cmds
[i
].name
, cmds
[i
].desc
); 
 791 static int _fd(int fd
) 
 794                 fcntl(fd
, F_SETFD
, 1); 
 798 static int load_and_unload_cmd(int argc
, char *const argv
[]) 
 800         launch_data_t pass1
, pass2
; 
 805         if (!strcmp(argv
[0], "load")) 
 808         while ((ch 
= getopt(argc
, argv
, "w")) != -1) { 
 814                         fprintf(stderr
, "usage: %s load [-w] paths...\n", getprogname()); 
 822                 fprintf(stderr
, "usage: %s load [-w] paths...\n", getprogname()); 
 826         /* I wish I didn't need to do two passes, but I need to load mDNSResponder and use it too. 
 828          * In later versions of launchd, I hope to load everything in the first pass, 
 829          * then do the Bonjour magic on the jobs that need it, and reload them, but for now, 
 830          * I haven't thought through the various complexities of reloading jobs, and therefore 
 831          * launchd doesn't have reload support right now. 
 834         pass1 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 835         pass2 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 837         for (i 
= 0; i 
< argc
; i
++) 
 838                 readpath(argv
[i
], pass1
, pass2
, wflag
, lflag
); 
 840         if (0 == launch_data_array_get_count(pass1
) && 0 == launch_data_array_get_count(pass2
)) { 
 841                 fprintf(stderr
, "nothing found to %s\n", lflag 
? "load" : "unload"); 
 842                 launch_data_free(pass1
); 
 843                 launch_data_free(pass2
); 
 848                 if (0 < launch_data_array_get_count(pass1
)) { 
 849                         submit_job_pass(pass1
); 
 851                 if (0 < launch_data_array_get_count(pass2
)) { 
 852                         submit_job_pass(pass2
); 
 855                 for (i 
= 0; i 
< (int)launch_data_array_get_count(pass1
); i
++) 
 856                         unloadjob(launch_data_array_get_index(pass1
, i
)); 
 857                 for (i 
= 0; i 
< (int)launch_data_array_get_count(pass2
); i
++) 
 858                         unloadjob(launch_data_array_get_index(pass2
, i
)); 
 864 static void submit_job_pass(launch_data_t jobs
) 
 866         launch_data_t msg
, resp
; 
 870         for (i 
= 0; i 
< launch_data_array_get_count(jobs
); i
++) 
 871                 distill_config_file(launch_data_array_get_index(jobs
, i
)); 
 873         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 875         launch_data_dict_insert(msg
, jobs
, LAUNCH_KEY_SUBMITJOB
); 
 877         resp 
= launch_msg(msg
); 
 880                 switch (launch_data_get_type(resp
)) { 
 881                 case LAUNCH_DATA_ERRNO
: 
 882                         if ((e 
= launch_data_get_errno(resp
))) 
 883                                 fprintf(stderr
, "%s\n", strerror(e
)); 
 885                 case LAUNCH_DATA_ARRAY
: 
 886                         for (i 
= 0; i 
< launch_data_array_get_count(jobs
); i
++) { 
 887                                 launch_data_t obatind 
= launch_data_array_get_index(resp
, i
); 
 888                                 launch_data_t jatind 
= launch_data_array_get_index(jobs
, i
); 
 889                                 const char *lab4job 
= launch_data_get_string(launch_data_dict_lookup(jatind
, LAUNCH_JOBKEY_LABEL
)); 
 890                                 if (LAUNCH_DATA_ERRNO 
== launch_data_get_type(obatind
)) { 
 891                                         e 
= launch_data_get_errno(obatind
); 
 894                                                 fprintf(stderr
, "%s: %s\n", lab4job
, "Already loaded"); 
 897                                                 fprintf(stderr
, "%s: %s\n", lab4job
, "Not loaded"); 
 900                                                 fprintf(stderr
, "%s: %s\n", lab4job
, strerror(e
)); 
 908                         fprintf(stderr
, "unknown respose from launchd!\n"); 
 911                 launch_data_free(resp
); 
 913                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
 916         launch_data_free(msg
); 
 919 static int start_and_stop_cmd(int argc
, char *const argv
[]) 
 921         launch_data_t resp
, msg
; 
 922         const char *lmsgcmd 
= LAUNCH_KEY_STOPJOB
; 
 925         if (!strcmp(argv
[0], "start")) 
 926                 lmsgcmd 
= LAUNCH_KEY_STARTJOB
; 
 929                 fprintf(stderr
, "usage: %s %s <job label>\n", getprogname(), argv
[0]); 
 933         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 934         launch_data_dict_insert(msg
, launch_data_new_string(argv
[1]), lmsgcmd
); 
 936         resp 
= launch_msg(msg
); 
 937         launch_data_free(msg
); 
 940                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
 942         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
 943                 if ((e 
= launch_data_get_errno(resp
))) { 
 944                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
)); 
 948                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
 952         launch_data_free(resp
); 
 956 static void print_jobs(launch_data_t j 
__attribute__((unused
)), const char *label
, void *context 
__attribute__((unused
))) 
 958         fprintf(stdout
, "%s\n", label
); 
 961 static int list_cmd(int argc
, char *const argv
[]) 
 963         launch_data_t resp
, msg
; 
 967         while ((ch 
= getopt(argc
, argv
, "v")) != -1) { 
 973                         fprintf(stderr
, "usage: %s list [-v]\n", getprogname()); 
 979                 fprintf(stderr
, "usage: %s list: \"-v\" flag not implemented yet\n", getprogname()); 
 983         msg 
= launch_data_new_string(LAUNCH_KEY_GETJOBS
); 
 984         resp 
= launch_msg(msg
); 
 985         launch_data_free(msg
); 
 988                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
 990         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_DICTIONARY
) { 
 991                 launch_data_dict_iterate(resp
, print_jobs
, NULL
); 
 993                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
 997         launch_data_free(resp
); 
1002 static int stdio_cmd(int argc
, char *const argv
[]) 
1004         launch_data_t resp
, msg
, tmp
; 
1005         int e
, fd 
= -1, r 
= 0; 
1008                 fprintf(stderr
, "usage: %s %s <path>\n", getprogname(), argv
[0]); 
1012         fd 
= open(argv
[1], O_CREAT
|O_APPEND
|O_WRONLY
, DEFFILEMODE
); 
1014         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1017                 tmp 
= launch_data_new_string(argv
[1]); 
1019                 tmp 
= launch_data_new_fd(fd
); 
1022         if (!strcmp(argv
[0], "stdout")) { 
1023                 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETSTDOUT
); 
1025                 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETSTDERR
); 
1028         resp 
= launch_msg(msg
); 
1029         launch_data_free(msg
); 
1032                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1034         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
1035                 if ((e 
= launch_data_get_errno(resp
))) { 
1036                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
)); 
1040                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1047         launch_data_free(resp
); 
1052 static int fyi_cmd(int argc
, char *const argv
[]) 
1054         launch_data_t resp
, msg
; 
1055         const char *lmsgk 
= LAUNCH_KEY_RELOADTTYS
; 
1059                 fprintf(stderr
, "usage: %s %s\n", getprogname(), argv
[0]); 
1063         if (!strcmp(argv
[0], "shutdown")) 
1064                 lmsgk 
= LAUNCH_KEY_SHUTDOWN
; 
1066         msg 
= launch_data_new_string(lmsgk
); 
1067         resp 
= launch_msg(msg
); 
1068         launch_data_free(msg
); 
1071                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1073         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
1074                 if ((e 
= launch_data_get_errno(resp
))) { 
1075                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
)); 
1079                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1083         launch_data_free(resp
); 
1088 static int logupdate_cmd(int argc
, char *const argv
[]) 
1090         launch_data_t resp
, msg
; 
1091         int e
, i
, j
, r 
= 0, m 
= 0; 
1092         bool badargs 
= false, maskmode 
= false, onlymode 
= false, levelmode 
= false; 
1093         const char *whichcmd 
= LAUNCH_KEY_SETLOGMASK
; 
1094         static const struct { 
1098                 { "debug",      LOG_DEBUG 
}, 
1099                 { "info",       LOG_INFO 
}, 
1100                 { "notice",     LOG_NOTICE 
}, 
1101                 { "warning",    LOG_WARNING 
}, 
1102                 { "error",      LOG_ERR 
}, 
1103                 { "critical",   LOG_CRIT 
}, 
1104                 { "alert",      LOG_ALERT 
}, 
1105                 { "emergency",  LOG_EMERG 
}, 
1107         int logtblsz 
= sizeof logtbl 
/ sizeof logtbl
[0]; 
1110                 if (!strcmp(argv
[1], "mask")) 
1112                 else if (!strcmp(argv
[1], "only")) 
1114                 else if (!strcmp(argv
[1], "level")) 
1121                 m 
= LOG_UPTO(LOG_DEBUG
); 
1123         if (argc 
> 2 && (maskmode 
|| onlymode
)) { 
1124                 for (i 
= 2; i 
< argc
; i
++) { 
1125                         for (j 
= 0; j 
< logtblsz
; j
++) { 
1126                                 if (!strcmp(argv
[i
], logtbl
[j
].name
)) { 
1128                                                 m 
&= ~(LOG_MASK(logtbl
[j
].level
)); 
1130                                                 m 
|= LOG_MASK(logtbl
[j
].level
); 
1134                         if (j 
== logtblsz
) { 
1139         } else if (argc 
> 2 && levelmode
) { 
1140                 for (j 
= 0; j 
< logtblsz
; j
++) { 
1141                         if (!strcmp(argv
[2], logtbl
[j
].name
)) { 
1142                                 m 
= LOG_UPTO(logtbl
[j
].level
); 
1148         } else if (argc 
== 1) { 
1149                 whichcmd 
= LAUNCH_KEY_GETLOGMASK
; 
1155                 fprintf(stderr
, "usage: %s [[mask loglevels...] | [only loglevels...] [level loglevel]]\n", getprogname()); 
1159         if (whichcmd 
== LAUNCH_KEY_SETLOGMASK
) { 
1160                 msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1161                 launch_data_dict_insert(msg
, launch_data_new_integer(m
), whichcmd
); 
1163                 msg 
= launch_data_new_string(whichcmd
); 
1166         resp 
= launch_msg(msg
); 
1167         launch_data_free(msg
); 
1170                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1172         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
1173                 if ((e 
= launch_data_get_errno(resp
))) { 
1174                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
)); 
1177         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_INTEGER
) { 
1178                 if (whichcmd 
== LAUNCH_KEY_GETLOGMASK
) { 
1179                         m 
= launch_data_get_integer(resp
); 
1180                         for (j 
= 0; j 
< logtblsz
; j
++) { 
1181                                 if (m 
& LOG_MASK(logtbl
[j
].level
)) 
1182                                         fprintf(stdout
, "%s ", logtbl
[j
].name
); 
1184                         fprintf(stdout
, "\n"); 
1187                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1191         launch_data_free(resp
); 
1196 static int limit_cmd(int argc 
__attribute__((unused
)), char *const argv
[]) 
1200         struct rlimit 
*lmts 
= NULL
; 
1201         launch_data_t resp
, resp1 
= NULL
, msg
, tmp
; 
1203         size_t i
, lsz 
= -1, which 
= 0; 
1204         rlim_t slim 
= -1, hlim 
= -1; 
1205         bool badargs 
= false; 
1206         static const struct { 
1210                 { "cpu",        RLIMIT_CPU 
}, 
1211                 { "filesize",   RLIMIT_FSIZE 
}, 
1212                 { "data",       RLIMIT_DATA 
}, 
1213                 { "stack",      RLIMIT_STACK 
}, 
1214                 { "core",       RLIMIT_CORE 
}, 
1215                 { "rss",        RLIMIT_RSS 
}, 
1216                 { "memlock",    RLIMIT_MEMLOCK 
}, 
1217                 { "maxproc",    RLIMIT_NPROC 
}, 
1218                 { "maxfiles",   RLIMIT_NOFILE 
} 
1220         size_t limlookupcnt 
= sizeof limlookup 
/ sizeof limlookup
[0]; 
1221         bool name2num(const char *n
) { 
1222                 for (i 
= 0; i 
< limlookupcnt
; i
++) { 
1223                         if (!strcmp(limlookup
[i
].name
, n
)) { 
1224                                 which 
= limlookup
[i
].lim
; 
1230         const char *num2name(int n
) { 
1231                 for (i 
= 0; i 
< limlookupcnt
; i
++) { 
1232                         if (limlookup
[i
].lim 
== n
) 
1233                                 return limlookup
[i
].name
; 
1237         const char *lim2str(rlim_t val
, char *buf
) { 
1238                 if (val 
== RLIM_INFINITY
) 
1239                         strcpy(buf
, "unlimited"); 
1241                         sprintf(buf
, "%lld", val
); 
1244         bool str2lim(const char *buf
, rlim_t 
*res
) { 
1246                 *res 
= strtoll(buf
, &endptr
, 10); 
1247                 if (!strcmp(buf
, "unlimited")) { 
1248                         *res 
= RLIM_INFINITY
; 
1250                 } else if (*endptr 
== '\0') { 
1259         if (argc 
>= 3 && str2lim(argv
[2], &slim
)) 
1264         if (argc 
== 4 && str2lim(argv
[3], &hlim
)) 
1267         if (argc 
>= 2 && name2num(argv
[1])) 
1271                 fprintf(stderr
, "usage: %s %s [", getprogname(), argv
[0]); 
1272                 for (i 
= 0; i 
< limlookupcnt
; i
++) 
1273                         fprintf(stderr
, "%s %s", limlookup
[i
].name
, (i 
+ 1) == limlookupcnt 
? "" : "| "); 
1274                 fprintf(stderr
, "[both | soft hard]]\n"); 
1278         msg 
= launch_data_new_string(LAUNCH_KEY_GETRESOURCELIMITS
); 
1279         resp 
= launch_msg(msg
); 
1280         launch_data_free(msg
); 
1283                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1285         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) { 
1286                 lmts 
= launch_data_get_opaque(resp
); 
1287                 lsz 
= launch_data_get_opaque_size(resp
); 
1289                         for (i 
= 0; i 
< (lsz 
/ sizeof(struct rlimit
)); i
++) { 
1290                                 if (argc 
== 2 && which 
!= i
) 
1292                                 fprintf(stdout
, "\t%-12s%-15s%-15s\n", num2name(i
), 
1293                                                 lim2str(lmts
[i
].rlim_cur
, slimstr
), 
1294                                                 lim2str(lmts
[i
].rlim_max
, hlimstr
)); 
1297         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) { 
1298                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
)); 
1301                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1305         if (argc 
<= 2 || r 
!= 0) { 
1306                 launch_data_free(resp
); 
1312         lmts
[which
].rlim_cur 
= slim
; 
1313         lmts
[which
].rlim_max 
= hlim
; 
1315         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1316         tmp 
= launch_data_new_opaque(lmts
, lsz
); 
1317         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETRESOURCELIMITS
); 
1318         resp 
= launch_msg(msg
); 
1319         launch_data_free(msg
); 
1322                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1324         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) { 
1325                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
)); 
1327         } else if (launch_data_get_type(resp
) != LAUNCH_DATA_OPAQUE
) { 
1328                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1332         launch_data_free(resp
); 
1333         launch_data_free(resp1
); 
1338 static int umask_cmd(int argc
, char *const argv
[]) 
1340         launch_data_t resp
, msg
; 
1341         bool badargs 
= false; 
1347                 m 
= strtol(argv
[1], &endptr
, 8); 
1348                 if (*endptr 
!= '\0' || m 
> 0777) 
1352         if (argc 
> 2 || badargs
) { 
1353                 fprintf(stderr
, "usage: %s %s <mask>\n", getprogname(), argv
[0]); 
1359                 msg 
= launch_data_new_string(LAUNCH_KEY_GETUMASK
); 
1361                 msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1362                 launch_data_dict_insert(msg
, launch_data_new_integer(m
), LAUNCH_KEY_SETUMASK
); 
1364         resp 
= launch_msg(msg
); 
1365         launch_data_free(msg
); 
1368                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1370         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) { 
1371                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
)); 
1373         } else if (launch_data_get_type(resp
) != LAUNCH_DATA_INTEGER
) { 
1374                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1376         } else if (argc 
== 1) { 
1377                 fprintf(stdout
, "%o\n", (unsigned int)launch_data_get_integer(resp
)); 
1380         launch_data_free(resp
); 
1385 static int getrusage_cmd(int argc
, char *const argv
[]) 
1387         launch_data_t resp
, msg
; 
1388         bool badargs 
= false; 
1393         else if (strcmp(argv
[1], "self") && strcmp(argv
[1], "children")) 
1397                 fprintf(stderr
, "usage: %s %s self | children\n", getprogname(), argv
[0]); 
1401         if (!strcmp(argv
[1], "self")) { 
1402                 msg 
= launch_data_new_string(LAUNCH_KEY_GETRUSAGESELF
); 
1404                 msg 
= launch_data_new_string(LAUNCH_KEY_GETRUSAGECHILDREN
); 
1407         resp 
= launch_msg(msg
); 
1408         launch_data_free(msg
); 
1411                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1413         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
1414                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(launch_data_get_errno(resp
))); 
1416         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) { 
1417                 struct rusage 
*rusage 
= launch_data_get_opaque(resp
); 
1418                 fprintf(stdout
, "\t%-10f\tuser time used\n", 
1419                                 (double)rusage
->ru_utime
.tv_sec 
+ (double)rusage
->ru_utime
.tv_usec 
/ (double)1000000); 
1420                 fprintf(stdout
, "\t%-10f\tsystem time used\n", 
1421                                 (double)rusage
->ru_stime
.tv_sec 
+ (double)rusage
->ru_stime
.tv_usec 
/ (double)1000000); 
1422                 fprintf(stdout
, "\t%-10ld\tmax resident set size\n", rusage
->ru_maxrss
); 
1423                 fprintf(stdout
, "\t%-10ld\tshared text memory size\n", rusage
->ru_ixrss
); 
1424                 fprintf(stdout
, "\t%-10ld\tunshared data size\n", rusage
->ru_idrss
); 
1425                 fprintf(stdout
, "\t%-10ld\tunshared stack size\n", rusage
->ru_isrss
); 
1426                 fprintf(stdout
, "\t%-10ld\tpage reclaims\n", rusage
->ru_minflt
); 
1427                 fprintf(stdout
, "\t%-10ld\tpage faults\n", rusage
->ru_majflt
); 
1428                 fprintf(stdout
, "\t%-10ld\tswaps\n", rusage
->ru_nswap
); 
1429                 fprintf(stdout
, "\t%-10ld\tblock input operations\n", rusage
->ru_inblock
); 
1430                 fprintf(stdout
, "\t%-10ld\tblock output operations\n", rusage
->ru_oublock
); 
1431                 fprintf(stdout
, "\t%-10ld\tmessages sent\n", rusage
->ru_msgsnd
); 
1432                 fprintf(stdout
, "\t%-10ld\tmessages received\n", rusage
->ru_msgrcv
); 
1433                 fprintf(stdout
, "\t%-10ld\tsignals received\n", rusage
->ru_nsignals
); 
1434                 fprintf(stdout
, "\t%-10ld\tvoluntary context switches\n", rusage
->ru_nvcsw
); 
1435                 fprintf(stdout
, "\t%-10ld\tinvoluntary context switches\n", rusage
->ru_nivcsw
); 
1437                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1441         launch_data_free(resp
); 
1446 static bool launch_data_array_append(launch_data_t a
, launch_data_t o
) 
1448         size_t offt 
= launch_data_array_get_count(a
); 
1450         return launch_data_array_set_index(a
, o
, offt
);