Changeset 30332 for trunk/base


Ignore:
Timestamp:
Oct 25, 2007, 3:11:41 AM (12 years ago)
Author:
jberry@…
Message:

daemondo whitespace changes only. Convert to soft tabs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/programs/daemondo/main.c

    r30313 r30332  
    11/*
    2         daemondo - main.c
    3        
    4         Copyright (c) 2005 James Berry <jberry@macports.org>
    5         All rights reserved.
    6 
    7         Redistribution and use in source and binary forms, with or without
    8         modification, are permitted provided that the following conditions
    9         are met:
    10         1. Redistributions of source code must retain the above copyright
    11            notice, this list of conditions and the following disclaimer.
    12         2. Redistributions in binary form must reproduce the above copyright
    13            notice, this list of conditions and the following disclaimer in the
    14            documentation and/or other materials provided with the distribution.
    15         3. Neither the name of Apple Computer, Inc. nor the names of its contributors
    16            may be used to endorse or promote products derived from this software
    17            without specific prior written permission.
    18        
    19         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    20         AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    21         IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    22         ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    23         LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    24         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    25         SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    26         INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    27         CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    28         ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    29         POSSIBILITY OF SUCH DAMAGE.
    30 
    31         $Id$
     2    daemondo - main.c
     3   
     4    Copyright (c) 2005 James Berry <jberry@macports.org>
     5    All rights reserved.
     6
     7    Redistribution and use in source and binary forms, with or without
     8    modification, are permitted provided that the following conditions
     9    are met:
     10    1. Redistributions of source code must retain the above copyright
     11       notice, this list of conditions and the following disclaimer.
     12    2. Redistributions in binary form must reproduce the above copyright
     13       notice, this list of conditions and the following disclaimer in the
     14       documentation and/or other materials provided with the distribution.
     15    3. Neither the name of Apple Computer, Inc. nor the names of its contributors
     16       may be used to endorse or promote products derived from this software
     17       without specific prior written permission.
     18   
     19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     20    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     23    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29    POSSIBILITY OF SUCH DAMAGE.
     30
     31    $Id$
    3232*/
    3333
    3434/*
    35         Potentially useful System Configuration regex patterns:
    36 
    37                 (backslash quoting below is only to protect the C comment)
    38                 State:/Network/Interface/.*\/Link
    39                 State:/Network/Interface/.*\/IPv4
    40                 State:/Network/Interface/.*\/IPv6
    41                
    42                 State:/Network/Global/DNS
    43                 State:/Network/Global/IPv4
    44                
    45         Potentially useful notifications from Darwin Notify Center:
    46        
    47                 com.apple.system.config.network_change
     35    Potentially useful System Configuration regex patterns:
     36
     37        (backslash quoting below is only to protect the C comment)
     38        State:/Network/Interface/.*\/Link
     39        State:/Network/Interface/.*\/IPv4
     40        State:/Network/Interface/.*\/IPv6
     41       
     42        State:/Network/Global/DNS
     43        State:/Network/Global/IPv4
     44       
     45    Potentially useful notifications from Darwin Notify Center:
     46   
     47        com.apple.system.config.network_change
    4848*/
    4949
    5050/*
    51         New parameters:
    52        
    53                 --pid=none              - no pid is available; we start/stop only through the commands,
    54                                                   and have no real knowledge of whether the process is running
    55                 --pid=exec              - we track the pid we receive from exec of the start cmd
    56                 --pid=fileauto  - we track the pid available in first word of pidfile
    57                 --pid=fileclean - we track the pid available in first word of pidfile,
    58                                                   and clean it up when the process dies
    59                
    60                 --pidfile=name  - the name of the pidfile to use
     51    New parameters:
     52   
     53        --pid=none      - no pid is available; we start/stop only through the commands,
     54                          and have no real knowledge of whether the process is running
     55        --pid=exec      - we track the pid we receive from exec of the start cmd
     56        --pid=fileauto  - we track the pid available in first word of pidfile
     57        --pid=fileclean - we track the pid available in first word of pidfile,
     58                          and clean it up when the process dies
     59       
     60        --pidfile=name  - the name of the pidfile to use
    6161*/
    62        
     62   
    6363#include <stdio.h>
    6464#include <unistd.h>
     
    8585
    8686typedef enum {
    87         kPidStyleUnknown = 0,
    88         kPidStyleNone,
    89         kPidStyleExec,
    90         kPidStyleFileAuto,
    91         kPidStyleFileClean
     87    kPidStyleUnknown = 0,
     88    kPidStyleNone,
     89    kPidStyleExec,
     90    kPidStyleFileAuto,
     91    kPidStyleFileClean
    9292} PidStyle;
    9393
    9494// Globals
    95 CFStringRef                     kProgramName            = NULL;
    96 CFStringRef                     kChildWatchMode         = NULL;
    97 
    98 int                                     verbosity                       = 0;            // Verbosity level
    99 const char*                     label                           = NULL;
    100 
    101 const char* const*      startArgs                       = NULL;         // Argvs for start-cmd, stop-cmd, and restart-cmd
    102 const char* const*      stopArgs                        = NULL;
    103 const char* const*      restartArgs                     = NULL;
    104 
    105 PidStyle                        pidStyle                        = kPidStyleUnknown;
    106 const char*                     pidFile                         = NULL;
    107 
    108 int                                     terminating                     = 0;            // TRUE if we're terminating
    109 pid_t                           runningPid                      = 0;            // Current running pid (0 while stopped, -1 if we don't know pid)
    110 
    111 int                                     kqfd                            = 0;            // Kqueue file descriptor
    112 
    113 mach_port_t                     sigChild_m_port         = 0;            // Mach port to send signals through
    114 mach_port_t                     sigGeneric_m_port       = 0;            // Mach port to send signals through
    115 
    116 CFMutableArrayRef       scRestartPatterns       = NULL;         // Array of sc patterns to restart daemon on
    117 CFMutableArrayRef       distNotifyNames         = NULL;         // Array of distributed notification names to restart daemon on
    118 CFMutableArrayRef       darwinNotifyNames       = NULL;         // Array of darwin notification names to restart daemon on
    119 
    120 io_connect_t            pwrRootPort                     = 0;
    121 int                                     restartOnWakeup         = 0;            // TRUE to restart daemon on wake from sleep
    122 CFRunLoopTimerRef       restartTimer            = NULL;         // Timer for scheduled restart
    123 CFTimeInterval          restartHysteresis       = 5.0;          // Default hysteresis is 5 seconds
     95CFStringRef         kProgramName        = NULL;
     96CFStringRef         kChildWatchMode     = NULL;
     97
     98int                 verbosity           = 0;        // Verbosity level
     99const char*         label               = NULL;
     100
     101const char* const*  startArgs           = NULL;     // Argvs for start-cmd, stop-cmd, and restart-cmd
     102const char* const*  stopArgs            = NULL;
     103const char* const*  restartArgs         = NULL;
     104
     105PidStyle            pidStyle            = kPidStyleUnknown;
     106const char*         pidFile             = NULL;
     107
     108int                 terminating         = 0;        // TRUE if we're terminating
     109pid_t               runningPid          = 0;        // Current running pid (0 while stopped, -1 if we don't know pid)
     110
     111int                 kqfd                = 0;        // Kqueue file descriptor
     112
     113mach_port_t         sigChild_m_port     = 0;        // Mach port to send signals through
     114mach_port_t         sigGeneric_m_port   = 0;        // Mach port to send signals through
     115
     116CFMutableArrayRef   scRestartPatterns   = NULL;     // Array of sc patterns to restart daemon on
     117CFMutableArrayRef   distNotifyNames     = NULL;     // Array of distributed notification names to restart daemon on
     118CFMutableArrayRef   darwinNotifyNames   = NULL;     // Array of darwin notification names to restart daemon on
     119
     120io_connect_t        pwrRootPort         = 0;
     121int                 restartOnWakeup     = 0;        // TRUE to restart daemon on wake from sleep
     122CFRunLoopTimerRef   restartTimer        = NULL;     // Timer for scheduled restart
     123CFTimeInterval      restartHysteresis   = 5.0;      // Default hysteresis is 5 seconds
    124124
    125125
     
    127127LogMessage(const char* fmt, ...)
    128128{
    129         struct tm tm;
    130         time_t timestamp;
    131         char datestring[32];
    132        
    133         // Format the date-time stamp
    134         time(&timestamp);
    135         strftime(datestring, sizeof(datestring), "%F %T", localtime_r(&timestamp, &tm));
    136        
    137         // Output the log header
    138         if (label != NULL)
    139                 printf("%s %s: ", datestring, label);
    140         else
    141                 printf("%s ", datestring);
    142        
    143         // Output the message
    144         va_list ap;
    145         va_start(ap, fmt);
    146         vprintf(fmt, ap);
    147         va_end(ap);
     129    struct tm tm;
     130    time_t timestamp;
     131    char datestring[32];
     132   
     133    // Format the date-time stamp
     134    time(&timestamp);
     135    strftime(datestring, sizeof(datestring), "%F %T", localtime_r(&timestamp, &tm));
     136   
     137    // Output the log header
     138    if (label != NULL)
     139        printf("%s %s: ", datestring, label);
     140    else
     141        printf("%s ", datestring);
     142   
     143    // Output the message
     144    va_list ap;
     145    va_start(ap, fmt);
     146    vprintf(fmt, ap);
     147    va_end(ap);
    148148}
    149149
     
    152152CatArray(const char* const* strarray, char* buf, size_t size)
    153153{
    154         const char* sep = " ";
    155         int cnt = 0;
    156         if (size == 0)
    157                 return NULL;
    158         *buf = '\0';
    159         for (cnt = 0; *strarray; ++strarray) {
    160                 if (cnt++ > 0)
    161                         strlcat(buf, sep, size);
    162                 strlcat(buf, *strarray, size);
    163         }
    164         return buf;
     154    const char* sep = " ";
     155    int cnt = 0;
     156    if (size == 0)
     157        return NULL;
     158    *buf = '\0';
     159    for (cnt = 0; *strarray; ++strarray) {
     160        if (cnt++ > 0)
     161            strlcat(buf, sep, size);
     162        strlcat(buf, *strarray, size);
     163    }
     164    return buf;
    165165}
    166166
     
    169169DoVersion(void)
    170170{
    171         printf("daemondo, version 1.1\n\n");
     171    printf("daemondo, version 1.1\n\n");
    172172}
    173173
     
    176176DoHelp(void)
    177177{
    178         DoVersion();
    179        
    180         const char* helpText =
    181                 "usage: daemondo [-hv] [--version]\n"
    182                 "                     --start-cmd prog args... ;\n"
    183                 "                     [--stop-cmd prog arg... ;]\n"
    184                 "                     [--restart-cmd prog arg... ;]\n"
    185                 "                     [--restart-wakeup]\n"
    186                 "                     [--restart-netchange]\n"
    187                 "\n"
    188                 "daemondo is a wrapper program that runs daemons. It starts the specified\n"
    189                 "daemon on launch, stops it when given SIGTERM, and restarts it on SIGHUP.\n"
    190                 "It can also watch for transitions in system state, such as a change in\n"
    191                 "network availability or system power state, and restart the daemon on such\n"
    192                 "an event.\n"
    193                 "\n"
    194                 "daemondo works well as an adapter between darwin 8's launchd, and daemons\n"
    195                 "that are normally started via traditional rc.d style scripts or parameters.\n"
    196                 "\n"
    197                 "Parameters:\n"
    198                 "\n"
    199                 "  -h, --help                      Provide this help.\n"
    200                 "  -v                              Increase verbosity.\n"
    201                 "      --verbosity=n               Set verbosity to n.\n"
    202                 "  -V, --version                   Display program version information.\n"
    203                 "  -l, --label=desc                Label used to describe the daemon.\n"
    204                 "\n"
    205                 "  -s, --start-cmd args... ;       Required: command that will start the daemon.\n"
    206                 "  -k, --stop-cmd args... ;        Command that will stop the daemon.\n"
    207                 "  -r, --restart-cmd args... ;     Command that will restart the daemon.\n"
    208                 "      --restart-config regex... ; SC patterns on which to restart the daemon.\n"
    209                 "      --restart-dist-notify names... ;\n"
    210                 "                                  Distributed Notification Center notifications\n"
    211                 "                                  on which to restart the daemon.\n"
    212                 "      --restart-darwin-notify names... ;\n"
    213                 "                                  Darwin Notification Center notifications\n"
    214                 "                                  on which to restart the daemon.\n"
    215                 "      --restart-config regex... ; SC patterns on which to restart the daemon.\n"
    216                 "      --restart-wakeup            Restart daemon on wake from sleep.\n"
    217                 "      --restart-netchange         Restart daemon on a network change.\n"
    218                 "\n"
    219                 "daemondo responds to SIGHUP by restarting the daemon, and to SIGTERM by\n"
    220                 "stopping it. daemondo exits on receipt of SIGTERM, or when it detects\n"
    221                 "that the daemon process has died.\n"
    222                 "\n"
    223                 "The arguments start-cmd, stop-cmd, restart-cmd, restart-config,\n"
    224                 "restart-dist-notify, and restart-darwin-notify, if present,\n"
    225                 "must each be followed by arguments terminated by a ';'. You may need to\n"
    226                 "escape or quote the ';' to protect it from special handling by your shell.\n"
    227                 "\n"
    228                 "daemondo runs in one of two modes: (1) If no stop-cmd is given, daemondo\n"
    229                 "executes start-cmd asyncronously, and tracks the process id; that process id\n"
    230                 "is used to signal the daemon for later stop and/or restart. (2) If stop-cmd\n"
    231                 "is given, then both start-cmd and stop-cmd are issued syncronously, and are\n"
    232                 "assumed to do all the work of controlling the daemon. In such cases there is\n"
    233                 "no process id to track. In either mode, restart-cmd, if present, is used to\n"
    234                 "restart the daemon. If in mode 1, restart-cmd must not disrupt the process id.\n"
    235                 "If restart-cmd is not provided, the daemon is restarted via a stop/start\n"
    236                 "sequence.\n"
    237                 "\n"
    238                 "The argument restart-config specifies a set of regex patterns corresponding\n"
    239                 "to system configuration keys, on notification of change for which the daemon\n"
    240                 "will be restarted\n"
    241                 "\n"
    242                 "The arguments restart-dist-notify and restart-darwin-notify specify a set of\n"
    243                 "notification names from the distributed and darwin notification centers,\n"
    244                 "respectively, on receipt of which the daemon will be restarted.\n"
    245                 "\n"
    246                 "The argument restart-wakeup will cause the daemon to be restarted when the\n"
    247                 "computer wakes from sleep.\n"
    248                 "\n"
    249                 "The argument restart-netchange will cause the daemon to be restarted when\n"
    250                 "the network configuration changes. This is a shortcut for the more\n"
    251                 "verbose --restart-darwin-notify com.apple.system.config.network_change.\n"
    252                 "\n"
    253                 "In mode 1 only, daemondo will exit when it detects that the daemon being\n"
    254                 "monitored has exited.\n"
    255                 "\n"
    256                 ;
    257                
    258         printf(helpText);
     178    DoVersion();
     179   
     180    const char* helpText =
     181        "usage: daemondo [-hv] [--version]\n"
     182        "                     --start-cmd prog args... ;\n"
     183        "                     [--stop-cmd prog arg... ;]\n"
     184        "                     [--restart-cmd prog arg... ;]\n"
     185        "                     [--restart-wakeup]\n"
     186        "                     [--restart-netchange]\n"
     187        "\n"
     188        "daemondo is a wrapper program that runs daemons. It starts the specified\n"
     189        "daemon on launch, stops it when given SIGTERM, and restarts it on SIGHUP.\n"
     190        "It can also watch for transitions in system state, such as a change in\n"
     191        "network availability or system power state, and restart the daemon on such\n"
     192        "an event.\n"
     193        "\n"
     194        "daemondo works well as an adapter between darwin 8's launchd, and daemons\n"
     195        "that are normally started via traditional rc.d style scripts or parameters.\n"
     196        "\n"
     197        "Parameters:\n"
     198        "\n"
     199        "  -h, --help                      Provide this help.\n"
     200        "  -v                              Increase verbosity.\n"
     201        "      --verbosity=n               Set verbosity to n.\n"
     202        "  -V, --version                   Display program version information.\n"
     203        "  -l, --label=desc                Label used to describe the daemon.\n"
     204        "\n"
     205        "  -s, --start-cmd args... ;       Required: command that will start the daemon.\n"
     206        "  -k, --stop-cmd args... ;        Command that will stop the daemon.\n"
     207        "  -r, --restart-cmd args... ;     Command that will restart the daemon.\n"
     208        "      --restart-config regex... ; SC patterns on which to restart the daemon.\n"
     209        "      --restart-dist-notify names... ;\n"
     210        "                                  Distributed Notification Center notifications\n"
     211        "                                  on which to restart the daemon.\n"
     212        "      --restart-darwin-notify names... ;\n"
     213        "                                  Darwin Notification Center notifications\n"
     214        "                                  on which to restart the daemon.\n"
     215        "      --restart-config regex... ; SC patterns on which to restart the daemon.\n"
     216        "      --restart-wakeup            Restart daemon on wake from sleep.\n"
     217        "      --restart-netchange         Restart daemon on a network change.\n"
     218        "\n"
     219        "daemondo responds to SIGHUP by restarting the daemon, and to SIGTERM by\n"
     220        "stopping it. daemondo exits on receipt of SIGTERM, or when it detects\n"
     221        "that the daemon process has died.\n"
     222        "\n"
     223        "The arguments start-cmd, stop-cmd, restart-cmd, restart-config,\n"
     224        "restart-dist-notify, and restart-darwin-notify, if present,\n"
     225        "must each be followed by arguments terminated by a ';'. You may need to\n"
     226        "escape or quote the ';' to protect it from special handling by your shell.\n"
     227        "\n"
     228        "daemondo runs in one of two modes: (1) If no stop-cmd is given, daemondo\n"
     229        "executes start-cmd asyncronously, and tracks the process id; that process id\n"
     230        "is used to signal the daemon for later stop and/or restart. (2) If stop-cmd\n"
     231        "is given, then both start-cmd and stop-cmd are issued syncronously, and are\n"
     232        "assumed to do all the work of controlling the daemon. In such cases there is\n"
     233        "no process id to track. In either mode, restart-cmd, if present, is used to\n"
     234        "restart the daemon. If in mode 1, restart-cmd must not disrupt the process id.\n"
     235        "If restart-cmd is not provided, the daemon is restarted via a stop/start\n"
     236        "sequence.\n"
     237        "\n"
     238        "The argument restart-config specifies a set of regex patterns corresponding\n"
     239        "to system configuration keys, on notification of change for which the daemon\n"
     240        "will be restarted\n"
     241        "\n"
     242        "The arguments restart-dist-notify and restart-darwin-notify specify a set of\n"
     243        "notification names from the distributed and darwin notification centers,\n"
     244        "respectively, on receipt of which the daemon will be restarted.\n"
     245        "\n"
     246        "The argument restart-wakeup will cause the daemon to be restarted when the\n"
     247        "computer wakes from sleep.\n"
     248        "\n"
     249        "The argument restart-netchange will cause the daemon to be restarted when\n"
     250        "the network configuration changes. This is a shortcut for the more\n"
     251        "verbose --restart-darwin-notify com.apple.system.config.network_change.\n"
     252        "\n"
     253        "In mode 1 only, daemondo will exit when it detects that the daemon being\n"
     254        "monitored has exited.\n"
     255        "\n"
     256        ;
     257       
     258    printf(helpText);
    259259}
    260260
     
    263263CreatePidFile(void)
    264264{
    265         // Write a pid file if we're expected to
    266         if (pidFile != NULL)
    267         {
    268                 FILE* f = NULL;
    269                 switch (pidStyle)
    270                 {
    271                 default:
    272                 case kPidStyleNone:                     // No pid is available
    273                 case kPidStyleFileAuto:         // The process should create its own pid file
    274                 case kPidStyleFileClean:        // The process should create its own pid file
    275                         break;
    276                 case kPidStyleExec:                     // We know the pid, and will write it to the pid file
    277                         f = fopen(pidFile, "w");
    278                         if (f != NULL)
    279                         {
    280                                 fprintf(f, "%d", runningPid);
    281                                 fclose(f);
    282                         }
    283                         break;
    284                 }
    285         }
     265    // Write a pid file if we're expected to
     266    if (pidFile != NULL)
     267    {
     268        FILE* f = NULL;
     269        switch (pidStyle)
     270        {
     271        default:
     272        case kPidStyleNone:         // No pid is available
     273        case kPidStyleFileAuto:     // The process should create its own pid file
     274        case kPidStyleFileClean:    // The process should create its own pid file
     275            break;
     276        case kPidStyleExec:         // We know the pid, and will write it to the pid file
     277            f = fopen(pidFile, "w");
     278            if (f != NULL)
     279            {
     280                fprintf(f, "%d", runningPid);
     281                fclose(f);
     282            }
     283            break;
     284        }
     285    }
    286286}
    287287
     
    289289DestroyPidFile(void)
    290290{
    291         // Cleanup the pid file
    292         if (pidFile != NULL)
    293         {
    294                 switch (pidStyle)
    295                 {
    296                 default:
    297                 case kPidStyleNone:                     // No pid is available
    298                 case kPidStyleFileAuto:         // The process should remove its own pid file
    299                         break;
    300                 case kPidStyleExec:                     // We wrote the file, and we'll remove it
    301                 case kPidStyleFileClean:        // The process wrote the file, but we'll remove it
    302                         unlink(pidFile);
    303                         break;
    304                 }
    305         }
     291    // Cleanup the pid file
     292    if (pidFile != NULL)
     293    {
     294        switch (pidStyle)
     295        {
     296        default:
     297        case kPidStyleNone:         // No pid is available
     298        case kPidStyleFileAuto:     // The process should remove its own pid file
     299            break;
     300        case kPidStyleExec:         // We wrote the file, and we'll remove it
     301        case kPidStyleFileClean:    // The process wrote the file, but we'll remove it
     302            unlink(pidFile);
     303            break;
     304        }
     305    }
    306306}
    307307
     
    310310CheckForValidPidFile(void)
    311311{
    312         // Try to read the pid from the pid file
    313         pid_t pid = -1;
    314         FILE* f = fopen(pidFile, "r");
    315         if (f != NULL)
    316         {
    317                 if (1 != fscanf(f, "%d", &pid))
    318                         pid = -1;
    319                 if (pid == 0)
    320                         pid = -1;
    321                 fclose(f);
    322         }
    323        
    324         // Check whether the pid represents a valid process
    325         if (pid != -1 && 0 != kill(pid, 0))
    326                 pid = -1;
    327        
    328         return pid;
     312    // Try to read the pid from the pid file
     313    pid_t pid = -1;
     314    FILE* f = fopen(pidFile, "r");
     315    if (f != NULL)
     316    {
     317        if (1 != fscanf(f, "%d", &pid))
     318            pid = -1;
     319        if (pid == 0)
     320            pid = -1;
     321        fclose(f);
     322    }
     323   
     324    // Check whether the pid represents a valid process
     325    if (pid != -1 && 0 != kill(pid, 0))
     326        pid = -1;
     327   
     328    return pid;
    329329}
    330330
     
    333333WaitForValidPidFile(void)
    334334{
    335         CFAbsoluteTime patience = CFAbsoluteTimeGetCurrent() + kChildStartPidTimeout;
    336        
    337         // Poll for a child process and pidfile to be generated, until we lose patience.
    338         pid_t pid = -1;
    339         while ((pid = CheckForValidPidFile()) == -1 && (patience - CFAbsoluteTimeGetCurrent() > 0))
    340                 sleep(1);
    341                
    342         if (verbosity >= 3)
    343                 LogMessage("Discovered pid %d from pidfile %s\n", pid, pidFile);
    344 
    345         return pid;
     335    CFAbsoluteTime patience = CFAbsoluteTimeGetCurrent() + kChildStartPidTimeout;
     336   
     337    // Poll for a child process and pidfile to be generated, until we lose patience.
     338    pid_t pid = -1;
     339    while ((pid = CheckForValidPidFile()) == -1 && (patience - CFAbsoluteTimeGetCurrent() > 0))
     340        sleep(1);
     341       
     342    if (verbosity >= 3)
     343        LogMessage("Discovered pid %d from pidfile %s\n", pid, pidFile);
     344
     345    return pid;
    346346}
    347347
     
    351351MonitorChild(pid_t childPid)
    352352{
    353         runningPid = childPid;
    354        
    355         if (runningPid != 0 && runningPid != -1) {
    356                 if (verbosity >=3 )
    357                         LogMessage("Start monitoring of pid %d via kevent\n", runningPid);
    358                
    359                 // Monitor the process deaths for that pid
    360                 struct kevent ke;
    361                 EV_SET(&ke, childPid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, NULL);
    362                 if (-1 == kevent(kqfd, &ke, 1, NULL, 0, NULL))
    363                         LogMessage("Could not monitor kevent for pid %d (%d)\n", runningPid, errno);
    364         }
     353    runningPid = childPid;
     354   
     355    if (runningPid != 0 && runningPid != -1) {
     356        if (verbosity >=3 )
     357            LogMessage("Start monitoring of pid %d via kevent\n", runningPid);
     358       
     359        // Monitor the process deaths for that pid
     360        struct kevent ke;
     361        EV_SET(&ke, childPid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, NULL);
     362        if (-1 == kevent(kqfd, &ke, 1, NULL, 0, NULL))
     363            LogMessage("Could not monitor kevent for pid %d (%d)\n", runningPid, errno);
     364    }
    365365}
    366366
     
    369369UnmonitorChild()
    370370{
    371         runningPid = 0;
     371    runningPid = 0;
    372372}
    373373
     
    376376MonitoringChild()
    377377{
    378         return runningPid != 0;
     378    return runningPid != 0;
    379379}
    380380
     
    383383ProcessChildDeath(pid_t childPid)
    384384{
    385         // Take special note if process runningPid dies
    386         if (runningPid != 0 && runningPid != -1 && childPid == runningPid)
    387         {
    388                 if (verbosity >= 3)
    389                         LogMessage("Target process id %d has died.\n", childPid);
    390                        
    391                 UnmonitorChild();
    392                 DestroyPidFile();
    393                
    394                 CFRunLoopStop(CFRunLoopGetCurrent());
    395         }
     385    // Take special note if process runningPid dies
     386    if (runningPid != 0 && runningPid != -1 && childPid == runningPid)
     387    {
     388        if (verbosity >= 3)
     389            LogMessage("Target process id %d has died.\n", childPid);
     390           
     391        UnmonitorChild();
     392        DestroyPidFile();
     393       
     394        CFRunLoopStop(CFRunLoopGetCurrent());
     395    }
    396396}
    397397
     
    400400WaitChildDeath(pid_t childPid)
    401401{
    402         // Wait for the death of a particular child
    403         int wait_result = 0;
    404         int wait_stat = 0;
    405        
    406         // Set up a timer for how long we'll wait for child death before we
    407         // kill the child outright with SIGKILL (infanticide)
    408         CFAbsoluteTime patience = CFAbsoluteTimeGetCurrent() + kChildDeathTimeout;
    409        
    410         // Wait for the death of child, calling into our run loop if it's not dead yet.
    411         // Note that the wait may actually be processed by our runloop callback, in which
    412         // case the wait here will simply return -1.
    413         while ((wait_result = wait4(childPid, &wait_stat, WNOHANG, NULL)) == 0)
    414         {
    415                 CFTimeInterval patienceRemaining = patience - CFAbsoluteTimeGetCurrent();
    416                 if (patienceRemaining > 0)
    417                         CFRunLoopRunInMode(kChildWatchMode, patienceRemaining, true);
    418                 else
    419                 {
    420                         // We've run out of patience; kill the child with SIGKILL
    421                         if (verbosity >= 3)
    422                                 LogMessage("Child %d didn't die; Killing with SIGKILL.\n", childPid);
    423                        
    424                         if (0 != kill(childPid, SIGKILL))
    425                         {
    426                                 if (verbosity >= 3)
    427                                         LogMessage("Attempt to kill process %d failed.\n", childPid);
    428                         }
    429                 }
    430         }
    431        
    432         // The child should be dead and gone by now.
    433         ProcessChildDeath(childPid);
     402    // Wait for the death of a particular child
     403    int wait_result = 0;
     404    int wait_stat = 0;
     405   
     406    // Set up a timer for how long we'll wait for child death before we
     407    // kill the child outright with SIGKILL (infanticide)
     408    CFAbsoluteTime patience = CFAbsoluteTimeGetCurrent() + kChildDeathTimeout;
     409   
     410    // Wait for the death of child, calling into our run loop if it's not dead yet.
     411    // Note that the wait may actually be processed by our runloop callback, in which
     412    // case the wait here will simply return -1.
     413    while ((wait_result = wait4(childPid, &wait_stat, WNOHANG, NULL)) == 0)
     414    {
     415        CFTimeInterval patienceRemaining = patience - CFAbsoluteTimeGetCurrent();
     416        if (patienceRemaining > 0)
     417            CFRunLoopRunInMode(kChildWatchMode, patienceRemaining, true);
     418        else
     419        {
     420            // We've run out of patience; kill the child with SIGKILL
     421            if (verbosity >= 3)
     422                LogMessage("Child %d didn't die; Killing with SIGKILL.\n", childPid);
     423           
     424            if (0 != kill(childPid, SIGKILL))
     425            {
     426                if (verbosity >= 3)
     427                    LogMessage("Attempt to kill process %d failed.\n", childPid);
     428            }
     429        }
     430    }
     431   
     432    // The child should be dead and gone by now.
     433    ProcessChildDeath(childPid);
    434434}
    435435
     
    438438CheckChildren(void)
    439439{
    440         // Process any pending child deaths
    441         int wait_stat = 0;
    442         pid_t pid = 0;
    443         while ((pid = wait4(0, &wait_stat, WNOHANG, NULL)) != 0 && pid != -1)
    444                 ProcessChildDeath(pid);
     440    // Process any pending child deaths
     441    int wait_stat = 0;
     442    pid_t pid = 0;
     443    while ((pid = wait4(0, &wait_stat, WNOHANG, NULL)) != 0 && pid != -1)
     444        ProcessChildDeath(pid);
    445445}
    446446
     
    449449Exec(const char* const argv[], int sync)
    450450{
    451         if (!argv || !argv[0] || !*argv[0])
    452                 return -1;
    453                
    454         pid_t pid = fork();
    455         switch (pid)
    456         {
    457         case 0:
    458                 // In the child process
    459                 {                       
    460                         // Child process has no stdin, but shares stdout and stderr with us
    461                         // Is that the right behavior?
    462                         int nullfd = 0;
    463                         if ((nullfd = open("/dev/null", O_RDONLY)) == -1)
    464                                 _exit(1);
    465                         dup2(nullfd, STDIN_FILENO);
    466 
    467                         // Launch the child
    468                         execvp(argv[0], (char* const*)argv);
    469                        
    470                         // We get here only if the exec fails.
    471                         LogMessage("Unable to launch process %s.\n", argv[0]);
    472                         _exit(1);
    473                 }
    474                 break;
    475        
    476         case -1:
    477                 // error starting child process
    478                 LogMessage("Unable to fork child process %s.\n", argv[0]);
    479                 break;
    480        
    481         default:
    482                 // In the original process
    483                 if (sync)
    484                 {
    485                         // If synchronous, wait for the child process to complete
    486                         WaitChildDeath(pid);
    487                         pid = 0;
    488                 }
    489                 break;
    490         }
    491        
    492         return pid;
     451    if (!argv || !argv[0] || !*argv[0])
     452        return -1;
     453       
     454    pid_t pid = fork();
     455    switch (pid)
     456    {
     457    case 0:
     458        // In the child process
     459        {           
     460            // Child process has no stdin, but shares stdout and stderr with us
     461            // Is that the right behavior?
     462            int nullfd = 0;
     463            if ((nullfd = open("/dev/null", O_RDONLY)) == -1)
     464                _exit(1);
     465            dup2(nullfd, STDIN_FILENO);
     466
     467            // Launch the child
     468            execvp(argv[0], (char* const*)argv);
     469           
     470            // We get here only if the exec fails.
     471            LogMessage("Unable to launch process %s.\n", argv[0]);
     472            _exit(1);
     473        }
     474        break;
     475   
     476    case -1:
     477        // error starting child process
     478        LogMessage("Unable to fork child process %s.\n", argv[0]);
     479        break;
     480   
     481    default:
     482        // In the original process
     483        if (sync)
     484        {
     485            // If synchronous, wait for the child process to complete
     486            WaitChildDeath(pid);
     487            pid = 0;
     488        }
     489        break;
     490    }
     491   
     492    return pid;
    493493}
    494494
     
    496496int
    497497Start(void)
    498 {       
    499         char buf[1024];
    500        
    501         if (!startArgs || !startArgs[0])
    502         {
    503                 LogMessage("There is nothing to start. No start-cmd was specified.\n");
    504                 return 2;
    505         }
    506        
    507         if (verbosity >= 1)
    508                 LogMessage("starting process\n");
    509         if (verbosity >= 2)
    510                 LogMessage("Running start-cmd %s.\n", CatArray(startArgs, buf, sizeof(buf)));
    511                
    512         // Exec the start-cmd
    513         pid_t pid = Exec(startArgs, pidStyle == kPidStyleNone);
    514        
    515         // Process error during Exec
    516         if (pid == -1)
    517         {
    518                 if (verbosity >= 2)
    519                         LogMessage("Error running start-cmd %s.\n", CatArray(startArgs, buf, sizeof(buf)));
    520                 if (verbosity >= 1)
    521                         LogMessage("error while starting\n");
    522                 return 2;
    523         }
    524        
    525         // Try to discover the pid of the running process
    526         switch (pidStyle)
    527         {
    528         case kPidStyleNone:                     // The command should have completed: we have no pid (should be zero)
    529                 pid = -1;
    530                 break;
    531                
    532         case kPidStyleExec:                     // The pid comes from the Exec
    533                 break;
    534                
    535         case kPidStyleFileAuto:         // Poll pid from the pidfile
    536         case kPidStyleFileClean:
    537                 pid = WaitForValidPidFile();
    538                 if (pid == -1)
    539                 {
    540                         if (verbosity >= 2)
    541                                 LogMessage("Error; expected pidfile not found following Exec of start-cmd %s.\n", CatArray(startArgs, buf, sizeof(buf)));
    542                         if (verbosity >= 1)
    543                                 LogMessage("error while starting\n");
    544                         return 2;
    545                 }
    546                 break;
    547                
    548         default:
    549                 break;
    550         }
    551        
    552         // If we have a pid, then begin tracking it
    553         MonitorChild(pid);
    554         if (pid != 0 && pid != -1)
    555         {
    556                 if (verbosity >= 1)
    557                         LogMessage("Target process id is %d\n", pid);
    558 
    559                 // Create a pid file if we need to             
    560                 CreatePidFile();
    561         }
    562        
    563         return 0;
     498{   
     499    char buf[1024];
     500   
     501    if (!startArgs || !startArgs[0])
     502    {
     503        LogMessage("There is nothing to start. No start-cmd was specified.\n");
     504        return 2;
     505    }
     506   
     507    if (verbosity >= 1)
     508        LogMessage("starting process\n");
     509    if (verbosity >= 2)
     510        LogMessage("Running start-cmd %s.\n", CatArray(startArgs, buf, sizeof(buf)));
     511       
     512    // Exec the start-cmd
     513    pid_t pid = Exec(startArgs, pidStyle == kPidStyleNone);
     514   
     515    // Process error during Exec
     516    if (pid == -1)
     517    {
     518        if (verbosity >= 2)
     519            LogMessage("Error running start-cmd %s.\n", CatArray(startArgs, buf, sizeof(buf)));
     520        if (verbosity >= 1)
     521            LogMessage("error while starting\n");
     522        return 2;
     523    }
     524   
     525    // Try to discover the pid of the running process
     526    switch (pidStyle)
     527    {
     528    case kPidStyleNone:         // The command should have completed: we have no pid (should be zero)
     529        pid = -1;
     530        break;
     531       
     532    case kPidStyleExec:         // The pid comes from the Exec
     533        break;
     534       
     535    case kPidStyleFileAuto:     // Poll pid from the pidfile
     536    case kPidStyleFileClean:
     537        pid = WaitForValidPidFile();
     538        if (pid == -1)
     539        {
     540            if (verbosity >= 2)
     541                LogMessage("Error; expected pidfile not found following Exec of start-cmd %s.\n", CatArray(startArgs, buf, sizeof(buf)));
     542            if (verbosity >= 1)
     543                LogMessage("error while starting\n");
     544            return 2;
     545        }
     546        break;
     547       
     548    default:
     549        break;
     550    }
     551   
     552    // If we have a pid, then begin tracking it
     553    MonitorChild(pid);
     554    if (pid != 0 && pid != -1)
     555    {
     556        if (verbosity >= 1)
     557            LogMessage("Target process id is %d\n", pid);
     558
     559        // Create a pid file if we need to     
     560        CreatePidFile();
     561    }
     562   
     563    return 0;
    564564}
    565565
     
    568568Stop(void)
    569569{
    570         char buf[1024];
    571 
    572         pid_t pid;
    573         if (!stopArgs || !stopArgs[0])
    574         {
    575                 // We don't have a stop command, so we try to kill the process
    576                 // we're tracking with runningPid
    577                 if ((pid = runningPid) != 0 && pid != -1)
    578                 {
    579                         if (verbosity >= 1)
    580                                 LogMessage("stopping process %d\n", pid);
    581                        
    582                         // Send the process a SIGTERM to ask it to quit
    583                         kill(pid, SIGTERM);
    584                        
    585                         // Wait for process to quit, killing it after a timeout
    586                         WaitChildDeath(pid);
    587                 }
    588                 else
    589                 {
    590                         if (verbosity >= 1)
    591                                 LogMessage("process was already stopped\n");
    592                 }
    593         }
    594         else
    595         {
    596                 // We have a stop-cmd to use. We execute it synchronously,
    597                 // and trust it to do the job.
    598                 if (verbosity >= 1)
    599                         LogMessage("stopping process\n");
    600                 if (verbosity >= 2)
    601                         LogMessage("Running stop-cmd %s.\n", CatArray(stopArgs, buf, sizeof(buf)));
    602                 pid = Exec(stopArgs, TRUE);
    603                 if (pid == -1)
    604                 {
    605                         if (verbosity >= 2)
    606                                 LogMessage("Error while running stop-cmd %s\n", CatArray(stopArgs, buf, sizeof(buf)));
    607                         if (verbosity >= 1)
    608                                 LogMessage("error stopping process\n");
    609                         return 2;
    610                 }
    611 
    612                 // We've executed stop-cmd, so we assume any runningPid process is gone
    613                 UnmonitorChild();
    614                 DestroyPidFile();
    615         }
    616        
    617         return 0;
     570    char buf[1024];
     571
     572    pid_t pid;
     573    if (!stopArgs || !stopArgs[0])
     574    {
     575        // We don't have a stop command, so we try to kill the process
     576        // we're tracking with runningPid
     577        if ((pid = runningPid) != 0 && pid != -1)
     578        {
     579            if (verbosity >= 1)
     580                LogMessage("stopping process %d\n", pid);
     581           
     582            // Send the process a SIGTERM to ask it to quit
     583            kill(pid, SIGTERM);
     584           
     585            // Wait for process to quit, killing it after a timeout
     586            WaitChildDeath(pid);
     587        }
     588        else
     589        {
     590            if (verbosity >= 1)
     591                LogMessage("process was already stopped\n");
     592        }
     593    }
     594    else
     595    {
     596        // We have a stop-cmd to use. We execute it synchronously,
     597        // and trust it to do the job.
     598        if (verbosity >= 1)
     599            LogMessage("stopping process\n");
     600        if (verbosity >= 2)
     601            LogMessage("Running stop-cmd %s.\n", CatArray(stopArgs, buf, sizeof(buf)));
     602        pid = Exec(stopArgs, TRUE);
     603        if (pid == -1)
     604        {
     605            if (verbosity >= 2)
     606                LogMessage("Error while running stop-cmd %s\n", CatArray(stopArgs, buf, sizeof(buf)));
     607            if (verbosity >= 1)
     608                LogMessage("error stopping process\n");
     609            return 2;
     610        }
     611
     612        // We've executed stop-cmd, so we assume any runningPid process is gone
     613        UnmonitorChild();
     614        DestroyPidFile();
     615    }
     616   
     617    return 0;
    618618}
    619619
     
    622622Restart(void)
    623623{
    624         char buf[1024];
    625 
    626         if (!restartArgs || !restartArgs[0])
    627         {
    628                 // We weren't given a restart command, so just use stop/start
    629                 if (verbosity >= 1)
    630                         LogMessage("restarting process\n");
    631                 Stop();
    632                 Start();
    633         }
    634         else
    635         {
    636                 // Execute the restart-cmd and trust it to do the job
    637                 if (verbosity >= 1)
    638                         LogMessage("restarting process\n");
    639                 if (verbosity >= 2)
    640                         LogMessage("Running restart-cmd %s.\n", CatArray(restartArgs, buf, sizeof(buf)));
    641                 pid_t pid = Exec(restartArgs, TRUE);
    642                 if (pid == -1)
    643                 {
    644                         if (verbosity >= 2)
    645                                 LogMessage("Error running restart-cmd %s\n", CatArray(restartArgs, buf, sizeof(buf)));
    646                         if (verbosity >= 1)
    647                                 LogMessage("error restarting process\n");
    648                         return 2;
    649                 }
    650         }
    651        
    652         return 0;
     624    char buf[1024];
     625
     626    if (!restartArgs || !restartArgs[0])
     627    {
     628        // We weren't given a restart command, so just use stop/start
     629        if (verbosity >= 1)
     630            LogMessage("restarting process\n");
     631        Stop();
     632        Start();
     633    }
     634    else
     635    {
     636        // Execute the restart-cmd and trust it to do the job
     637        if (verbosity >= 1)
     638            LogMessage("restarting process\n");
     639        if (verbosity >= 2)
     640            LogMessage("Running restart-cmd %s.\n", CatArray(restartArgs, buf, sizeof(buf)));
     641        pid_t pid = Exec(restartArgs, TRUE);
     642        if (pid == -1)
     643        {
     644            if (verbosity >= 2)
     645                LogMessage("Error running restart-cmd %s\n", CatArray(restartArgs, buf, sizeof(buf)));
     646            if (verbosity >= 1)
     647                LogMessage("error restarting process\n");
     648            return 2;
     649        }
     650    }
     651   
     652    return 0;
    653653}
    654654
     
    657657ScheduledRestartCallback(CFRunLoopTimerRef timer, void *info)
    658658{
    659         if (verbosity >= 3)
    660                 LogMessage("Scheduled restart time has arrived.\n");
    661                
    662         // Our scheduled restart fired, so restart now
    663         Restart();
     659    if (verbosity >= 3)
     660        LogMessage("Scheduled restart time has arrived.\n");
     661       
     662    // Our scheduled restart fired, so restart now
     663    Restart();
    664664}
    665665
     
    668668CancelScheduledRestart(void)
    669669{
    670         // Kill off any existing timer
    671         if (restartTimer)
    672         {
    673                 if (CFRunLoopTimerIsValid(restartTimer))
    674                         CFRunLoopTimerInvalidate(restartTimer);
    675                 CFRelease(restartTimer);
    676                 restartTimer = NULL;
    677         }
     670    // Kill off any existing timer
     671    if (restartTimer)
     672    {
     673        if (CFRunLoopTimerIsValid(restartTimer))
     674            CFRunLoopTimerInvalidate(restartTimer);
     675        CFRelease(restartTimer);
     676        restartTimer = NULL;
     677    }
    678678}
    679679
     
    682682ScheduleRestartForTime(CFAbsoluteTime absoluteTime)
    683683{
    684         // Cancel any currently scheduled restart
    685         CancelScheduledRestart();
    686        
    687         // Schedule a new restart
    688         restartTimer = CFRunLoopTimerCreate(NULL, absoluteTime, 0, 0, 0, ScheduledRestartCallback, NULL);
    689         if (restartTimer)
    690                 CFRunLoopAddTimer(CFRunLoopGetCurrent(), restartTimer, kCFRunLoopDefaultMode);
     684    // Cancel any currently scheduled restart
     685    CancelScheduledRestart();
     686   
     687    // Schedule a new restart
     688    restartTimer = CFRunLoopTimerCreate(NULL, absoluteTime, 0, 0, 0, ScheduledRestartCallback, NULL);
     689    if (restartTimer)
     690        CFRunLoopAddTimer(CFRunLoopGetCurrent(), restartTimer, kCFRunLoopDefaultMode);
    691691}
    692692
     
    695695ScheduleDelayedRestart(void)
    696696{
    697         // The hysteresis here allows us to take multiple restart requests within a small
    698         // period of time, and coalesce them together into only one. It also allows for
    699         // a certain amount of "slop time" for things to stabilize following whatever
    700         // event is triggering the restart.
    701         if (verbosity >= 3)
    702                 LogMessage("Scheduling restart %f seconds in future.\n", restartHysteresis);
    703         ScheduleRestartForTime(CFAbsoluteTimeGetCurrent() + restartHysteresis);
     697    // The hysteresis here allows us to take multiple restart requests within a small
     698    // period of time, and coalesce them together into only one. It also allows for
     699    // a certain amount of "slop time" for things to stabilize following whatever
     700    // event is triggering the restart.
     701    if (verbosity >= 3)
     702        LogMessage("Scheduling restart %f seconds in future.\n", restartHysteresis);
     703    ScheduleRestartForTime(CFAbsoluteTimeGetCurrent() + restartHysteresis);
    704704}
    705705
     
    707707void
    708708DynamicStoreChanged(
    709                                         SCDynamicStoreRef       store,
    710                                         CFArrayRef                      changedKeys,
    711                                         void                            *info
    712                                         )
    713 {
    714         if (verbosity >= 3)
    715         {
    716                 char bigBuf[1024];
    717                 *bigBuf = '\0';
    718                
    719                 CFIndex cnt = CFArrayGetCount(changedKeys);
    720                 CFIndex i;
    721                 for (i = 0; i < cnt; ++i)
    722                 {
    723                         char buf[256];
    724                         CFStringRef value = CFArrayGetValueAtIndex(changedKeys, i);
    725                         CFStringGetCString(value, buf, sizeof(buf), kCFStringEncodingUTF8);
    726                         if (i > 0)
    727                                 strlcat(bigBuf, ", ", sizeof(bigBuf));
    728                         strlcat(bigBuf, buf, sizeof(bigBuf));
    729                 }
    730 
    731                 LogMessage("Restarting daemon because of the following changes in the dynamic store: %s\n", bigBuf);
    732         }
    733        
    734         ScheduleDelayedRestart();
     709                    SCDynamicStoreRef   store,
     710                    CFArrayRef          changedKeys,
     711                    void                *info
     712                    )
     713{
     714    if (verbosity >= 3)
     715    {
     716        char bigBuf[1024];
     717        *bigBuf = '\0';
     718       
     719        CFIndex cnt = CFArrayGetCount(changedKeys);
     720        CFIndex i;
     721        for (i = 0; i < cnt; ++i)
     722        {
     723            char buf[256];
     724            CFStringRef value = CFArrayGetValueAtIndex(changedKeys, i);
     725            CFStringGetCString(value, buf, sizeof(buf), kCFStringEncodingUTF8);
     726            if (i > 0)
     727                strlcat(bigBuf, ", ", sizeof(bigBuf));
     728            strlcat(bigBuf, buf, sizeof(bigBuf));
     729        }
     730
     731        LogMessage("Restarting daemon because of the following changes in the dynamic store: %s\n", bigBuf);
     732    }
     733   
     734    ScheduleDelayedRestart();
    735735}
    736736
     
    740740{
    741741    switch (messageType)
    742         {
    743         case kIOMessageSystemWillSleep:
    744         case kIOMessageCanSystemSleep:
    745                 /*  Power Manager waits for your reply via one of these functions for up
    746                 to 30 seconds. If you don't acknowledge the power change by calling
    747                 IOAllowPowerChange(), you'll delay sleep by 30 seconds. */
    748                 IOAllowPowerChange(pwrRootPort, (long)messageArgument);
    749                 break;
    750         case kIOMessageSystemHasPoweredOn:
    751                 if (restartOnWakeup)
    752                 {
    753                         if (verbosity >= 3)
    754                                 LogMessage("Restarting daemon because of system wake from sleep\n");
    755                         ScheduleDelayedRestart();
    756                 }
    757                 break;
     742    {
     743    case kIOMessageSystemWillSleep:
     744    case kIOMessageCanSystemSleep:
     745        /*  Power Manager waits for your reply via one of these functions for up
     746        to 30 seconds. If you don't acknowledge the power change by calling
     747        IOAllowPowerChange(), you'll delay sleep by 30 seconds. */
     748        IOAllowPowerChange(pwrRootPort, (long)messageArgument);
     749        break;
     750    case kIOMessageSystemHasPoweredOn:
     751        if (restartOnWakeup)
     752        {
     753            if (verbosity >= 3)
     754                LogMessage("Restarting daemon because of system wake from sleep\n");
     755            ScheduleDelayedRestart();
     756        }
     757        break;
    758758    }
    759759}
     
    762762void
    763763NotificationCenterCallback(
    764                                                                 CFNotificationCenterRef center,
    765                                                                 void *observer,
    766                                                                 CFStringRef name,
    767                                                                 const void *object,
    768                                                                 CFDictionaryRef userInfo)
    769 {
    770         if (verbosity >= 3)
    771         {
    772                 char buf[256];
    773                 CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8);
    774                 LogMessage("Restarting daemon due to receipt of the notification %s\n", buf);
    775         }
    776                
    777         ScheduleDelayedRestart();
     764                                CFNotificationCenterRef center,
     765                                void *observer,
     766                                CFStringRef name,
     767                                const void *object,
     768                                CFDictionaryRef userInfo)
     769{
     770    if (verbosity >= 3)
     771    {
     772        char buf[256];
     773        CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8);
     774        LogMessage("Restarting daemon due to receipt of the notification %s\n", buf);
     775    }
     776       
     777    ScheduleDelayedRestart();
    778778}
    779779
     
    782782SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
    783783{
    784         mach_msg_header_t* hdr = (mach_msg_header_t*)msg;
    785         switch (hdr->msgh_id)
    786         {
    787         case SIGTERM:           
    788                 // On receipt of SIGTERM we set our terminate flag and stop the process
    789                 if (!terminating)
    790                 {
    791                         terminating = true;
    792                         Stop();
    793                 }
    794                 break;
    795        
    796         case SIGHUP:
    797                 if (!terminating)
    798                         Restart();
    799                 break;
    800                
    801         case SIGCHLD:
    802                 CheckChildren();
    803                 break;
    804                
    805         default:
    806                 break;
    807         }
     784    mach_msg_header_t* hdr = (mach_msg_header_t*)msg;
     785    switch (hdr->msgh_id)
     786    {
     787    case SIGTERM:       
     788        // On receipt of SIGTERM we set our terminate flag and stop the process
     789        if (!terminating)
     790        {
     791            terminating = true;
     792            Stop();
     793        }
     794        break;
     795   
     796    case SIGHUP:
     797        if (!terminating)
     798            Restart();
     799        break;
     800       
     801    case SIGCHLD:
     802        CheckChildren();
     803        break;
     804       
     805    default:
     806        break;
     807    }
    808808}
    809809
     
    812812             CFDataRef address, const void *data, void *context)
    813813{
    814         int fd = CFSocketGetNative(socketRef);
    815        
     814    int fd = CFSocketGetNative(socketRef);
     815   
    816816    struct kevent event;
    817         memset(&event, 0x00, sizeof(struct kevent));
    818        
     817    memset(&event, 0x00, sizeof(struct kevent));
     818   
    819819    if (kevent(fd, NULL, 0, &event, 1, NULL) == -1) {
    820820        LogMessage("Couldn't get kevent.  Error %d/%s\n", errno, strerror(errno));
    821821    } else {
    822         if (event.fflags & NOTE_EXIT) {
    823        
    824                 pid_t pid = event.ident;
    825                
    826                         if (verbosity >= 3)
    827                                 LogMessage("Received kevent: pid %d has exited\n", pid);
    828                                
    829                         ProcessChildDeath(pid);
    830         } else
    831                 LogMessage("Unexpected kevent received: %d\n", event.fflags);
     822        if (event.fflags & NOTE_EXIT) {
     823       
     824            pid_t pid = event.ident;
     825           
     826            if (verbosity >= 3)
     827                LogMessage("Received kevent: pid %d has exited\n", pid);
     828               
     829            ProcessChildDeath(pid);
     830        } else
     831            LogMessage("Unexpected kevent received: %d\n", event.fflags);
    832832    }
    833833
     
    838838AddNotificationToCenter(const void* value, void* context)
    839839{
    840         CFNotificationCenterAddObserver((CFNotificationCenterRef)context,
    841                 kProgramName,
    842                 NotificationCenterCallback,
    843                 value,          // name of notification
    844                 NULL,           // object to observe
    845                 CFNotificationSuspensionBehaviorDeliverImmediately);
     840    CFNotificationCenterAddObserver((CFNotificationCenterRef)context,
     841        kProgramName,
     842        NotificationCenterCallback,
     843        value,      // name of notification
     844        NULL,       // object to observe
     845        CFNotificationSuspensionBehaviorDeliverImmediately);
    846846}
    847847
     
    849849void handle_child_signal(int sig)
    850850{
    851         // Because there's a limited environment in which we can operate while
    852         // handling a signal, we send a mach message to our run loop, and handle
    853         // things from there.
    854         mach_msg_header_t header;
    855         header.msgh_bits                = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
    856         header.msgh_size                = sizeof(header);
    857         header.msgh_remote_port = sigChild_m_port;
    858         header.msgh_local_port  = MACH_PORT_NULL;
    859         header.msgh_reserved    = 0;
    860         header.msgh_id                  = sig;
    861        
    862         mach_msg_return_t status = mach_msg_send(&header);
    863         status = 0;
     851    // Because there's a limited environment in which we can operate while
     852    // handling a signal, we send a mach message to our run loop, and handle
     853    // things from there.
     854    mach_msg_header_t header;
     855    header.msgh_bits        = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
     856    header.msgh_size        = sizeof(header);
     857    header.msgh_remote_port = sigChild_m_port;
     858    header.msgh_local_port  = MACH_PORT_NULL;
     859    header.msgh_reserved    = 0;
     860    header.msgh_id          = sig;
     861   
     862    mach_msg_return_t status = mach_msg_send(&header);
     863    status = 0;
    864864}
    865865
     
    867867void handle_generic_signal(int sig)
    868868{
    869         // Because there's a limited environment in which we can operate while
    870         // handling a signal, we send a mach message to our run loop, and handle
    871         // things from there.
    872         mach_msg_header_t header;
    873         header.msgh_bits                = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
    874         header.msgh_size                = sizeof(header);
    875         header.msgh_remote_port = sigGeneric_m_port;
    876         header.msgh_local_port  = MACH_PORT_NULL;
    877         header.msgh_reserved    = 0;
    878         header.msgh_id                  = sig;
    879        
    880         mach_msg_return_t status = mach_msg_send(&header);
    881         status = 0;
     869    // Because there's a limited environment in which we can operate while
     870    // handling a signal, we send a mach message to our run loop, and handle
     871    // things from there.
     872    mach_msg_header_t header;
     873    header.msgh_bits        = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
     874    header.msgh_size        = sizeof(header);
     875    header.msgh_remote_port = sigGeneric_m_port;
     876    header.msgh_local_port  = MACH_PORT_NULL;
     877    header.msgh_reserved    = 0;
     878    header.msgh_id          = sig;
     879   
     880    mach_msg_return_t status = mach_msg_send(&header);
     881    status = 0;
    882882}
    883883
     
    886886MainLoop(void)
    887887{
    888         // *** TODO: This routine needs more error checking
    889        
    890         int status = 0;
    891        
    892         if (verbosity >= 3)
    893                 LogMessage("Initializing; daemondo pid is %d\n", getpid());
    894        
    895         // === Setup Notifications of Changes to System Configuration ===
    896         // Create a new SCDynamicStore session and an associated runloop source, adding it default mode
    897         SCDynamicStoreRef       dsRef                   = SCDynamicStoreCreate(NULL, kProgramName, DynamicStoreChanged, NULL);
    898         CFRunLoopSourceRef      dsSrc                   = SCDynamicStoreCreateRunLoopSource(NULL, dsRef, 0);
    899         CFRunLoopAddSource(CFRunLoopGetCurrent(), dsSrc, kCFRunLoopDefaultMode);
    900        
    901         // Tell the DynamicStore which keys to notify us on: this is the set of keys on which the
    902         // daemon will be restarted, at least for now--we may want to give more flexibility at some point.
    903         (void) SCDynamicStoreSetNotificationKeys(dsRef, NULL, scRestartPatterns);
    904        
    905        
    906         // === Setup Notifications from Notification Centers  ===
    907         CFArrayApplyFunction(distNotifyNames, CFRangeMake(0, CFArrayGetCount(distNotifyNames)),
    908                 AddNotificationToCenter, CFNotificationCenterGetDistributedCenter());
    909         CFArrayApplyFunction(darwinNotifyNames, CFRangeMake(0, CFArrayGetCount(darwinNotifyNames)),
    910                 AddNotificationToCenter, CFNotificationCenterGetDarwinNotifyCenter());
    911 
    912 
    913         // === Setup Notifications of Changes to System Power State ===
    914         // Register for system power notifications, adding a runloop source to handle then
    915         IONotificationPortRef   powerRef = NULL;
    916     io_object_t                         pwrNotifier = 0;
     888    // *** TODO: This routine needs more error checking
     889   
     890    int status = 0;
     891   
     892    if (verbosity >= 3)
     893        LogMessage("Initializing; daemondo pid is %d\n", getpid());
     894   
     895    // === Setup Notifications of Changes to System Configuration ===
     896    // Create a new SCDynamicStore session and an associated runloop source, adding it default mode
     897    SCDynamicStoreRef   dsRef           = SCDynamicStoreCreate(NULL, kProgramName, DynamicStoreChanged, NULL);
     898    CFRunLoopSourceRef  dsSrc           = SCDynamicStoreCreateRunLoopSource(NULL, dsRef, 0);
     899    CFRunLoopAddSource(CFRunLoopGetCurrent(), dsSrc, kCFRunLoopDefaultMode);
     900   
     901    // Tell the DynamicStore which keys to notify us on: this is the set of keys on which the
     902    // daemon will be restarted, at least for now--we may want to give more flexibility at some point.
     903    (void) SCDynamicStoreSetNotificationKeys(dsRef, NULL, scRestartPatterns);
     904   
     905   
     906    // === Setup Notifications from Notification Centers  ===
     907    CFArrayApplyFunction(distNotifyNames, CFRangeMake(0, CFArrayGetCount(distNotifyNames)),
     908        AddNotificationToCenter, CFNotificationCenterGetDistributedCenter());
     909    CFArrayApplyFunction(darwinNotifyNames, CFRangeMake(0, CFArrayGetCount(darwinNotifyNames)),
     910        AddNotificationToCenter, CFNotificationCenterGetDarwinNotifyCenter());
     911
     912
     913    // === Setup Notifications of Changes to System Power State ===
     914    // Register for system power notifications, adding a runloop source to handle then
     915    IONotificationPortRef   powerRef = NULL;
     916    io_object_t             pwrNotifier = 0;
    917917    pwrRootPort = IORegisterForSystemPower(0, &powerRef, PowerCallBack, &pwrNotifier);
    918918    if (pwrRootPort != 0)
    919                 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerRef), kCFRunLoopDefaultMode);
    920                
    921        
    922         // === Setup Notifications of Signals ===
    923         // Add a mach port source to our runloop for handling of the signals
    924         CFMachPortRef           sigChildPort    = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
    925         CFMachPortRef           sigGenericPort  = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
    926        
    927         CFRunLoopSourceRef      sigChildSrc             = CFMachPortCreateRunLoopSource(NULL, sigChildPort, 0);
    928         CFRunLoopSourceRef      sigGenericSrc   = CFMachPortCreateRunLoopSource(NULL, sigGenericPort, 0);
    929        
    930        
    931         // === Setup kevent notifications of process death
    932         kqfd = kqueue();
    933     CFSocketRef kqSocket                                = CFSocketCreateWithNative(NULL,  kqfd,
    934                                                                 kCFSocketReadCallBack, KQueueCallBack, NULL);
    935     CFRunLoopSourceRef  kqueueSrc               = CFSocketCreateRunLoopSource(NULL, kqSocket, 0);       
    936        
    937        
    938         // Add only the child signal sources to the childwatch mode
    939         CFRunLoopAddSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
    940         CFRunLoopAddSource(CFRunLoopGetCurrent(), kqueueSrc, kChildWatchMode);
    941        
    942         // Add both child and generic signal sources to the default mode
    943         CFRunLoopAddSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
    944         CFRunLoopAddSource(CFRunLoopGetCurrent(), kqueueSrc, kCFRunLoopDefaultMode);
    945         CFRunLoopAddSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
    946        
    947         // Install signal handlers
    948         sigChild_m_port         = CFMachPortGetPort(sigChildPort);
    949         sigGeneric_m_port       = CFMachPortGetPort(sigGenericPort);
    950 
    951         signal(SIGCHLD, handle_child_signal);
    952         signal(SIGTERM, handle_generic_signal);
    953         signal(SIGHUP, handle_generic_signal);
    954        
    955        
    956         // === Core Loop ===
    957         // Start the daemon
    958         status = Start();
    959        
    960         if (verbosity >= 3)
    961                 LogMessage("Start event loop\n");
    962        
    963         // Run the run loop until we stop it, or until the process we're tracking stops
    964         while (status == 0 && !terminating && MonitoringChild())
    965                 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 99999999.0, true);
    966                
    967         if (verbosity >= 3)
    968                 LogMessage("End event loop\n");
    969        
    970                
    971         // === Tear Down (we don't really need to do all of this) ===
    972         // The daemon should by now have either been stopped, or stopped of its own accord
    973                
    974         // Remove signal handlers
    975         signal(SIGTERM, SIG_DFL);
    976         signal(SIGHUP, SIG_DFL);
    977         signal(SIGCHLD, SIG_DFL);
    978        
    979         sigChild_m_port = 0;
    980         sigGeneric_m_port = 0;
    981        
    982         // Remove run loop sources
    983         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
    984         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), kqueueSrc, kChildWatchMode);
    985        
    986         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
    987         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), kqueueSrc, kCFRunLoopDefaultMode);
    988         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
    989        
    990         // Tear down signal handling infrastructure
    991         CFRelease(sigChildSrc);
    992         CFRelease(sigGenericSrc);
    993        
    994         CFRelease(sigChildPort);
    995         CFRelease(sigGenericPort);
    996        
    997         // Tear down kqueue infrastructure
    998         CFRelease(kqueueSrc);
    999         CFRelease(kqSocket);
    1000         close(kqfd);
    1001 
    1002         // Tear down DynamicStore stuff
    1003         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), dsSrc, kCFRunLoopDefaultMode);
    1004        
    1005         CFRelease(dsSrc);
    1006         CFRelease(dsRef);
    1007        
    1008         // Tear down notifications from Notification Center
    1009         CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDistributedCenter(), kProgramName);
    1010         CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), kProgramName);
    1011 
    1012         // Tear down power management stuff
    1013         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerRef), kCFRunLoopDefaultMode);
    1014         IODeregisterForSystemPower(&pwrNotifier);
    1015        
    1016         if (verbosity >= 3)
    1017                 LogMessage("Terminating\n");
    1018        
    1019         return status; 
     919        CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerRef), kCFRunLoopDefaultMode);
     920       
     921   
     922    // === Setup Notifications of Signals ===
     923    // Add a mach port source to our runloop for handling of the signals
     924    CFMachPortRef       sigChildPort    = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
     925    CFMachPortRef       sigGenericPort  = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
     926   
     927    CFRunLoopSourceRef  sigChildSrc     = CFMachPortCreateRunLoopSource(NULL, sigChildPort, 0);
     928    CFRunLoopSourceRef  sigGenericSrc   = CFMachPortCreateRunLoopSource(NULL, sigGenericPort, 0);
     929   
     930   
     931    // === Setup kevent notifications of process death
     932    kqfd = kqueue();
     933    CFSocketRef kqSocket                = CFSocketCreateWithNative(NULL,  kqfd,
     934                                            kCFSocketReadCallBack, KQueueCallBack, NULL);
     935    CFRunLoopSourceRef  kqueueSrc       = CFSocketCreateRunLoopSource(NULL, kqSocket, 0);   
     936   
     937   
     938    // Add only the child signal sources to the childwatch mode
     939    CFRunLoopAddSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
     940    CFRunLoopAddSource(CFRunLoopGetCurrent(), kqueueSrc, kChildWatchMode);
     941   
     942    // Add both child and generic signal sources to the default mode
     943    CFRunLoopAddSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
     944    CFRunLoopAddSource(CFRunLoopGetCurrent(), kqueueSrc, kCFRunLoopDefaultMode);
     945    CFRunLoopAddSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
     946   
     947    // Install signal handlers
     948    sigChild_m_port     = CFMachPortGetPort(sigChildPort);
     949    sigGeneric_m_port   = CFMachPortGetPort(sigGenericPort);
     950
     951    signal(SIGCHLD, handle_child_signal);
     952    signal(SIGTERM, handle_generic_signal);
     953    signal(SIGHUP, handle_generic_signal);
     954   
     955   
     956    // === Core Loop ===
     957    // Start the daemon
     958    status = Start();
     959   
     960    if (verbosity >= 3)
     961        LogMessage("Start event loop\n");
     962   
     963    // Run the run loop until we stop it, or until the process we're tracking stops
     964    while (status == 0 && !terminating && MonitoringChild())
     965        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 99999999.0, true);
     966       
     967    if (verbosity >= 3)
     968        LogMessage("End event loop\n");
     969   
     970       
     971    // === Tear Down (we don't really need to do all of this) ===
     972    // The daemon should by now have either been stopped, or stopped of its own accord
     973       
     974    // Remove signal handlers
     975    signal(SIGTERM, SIG_DFL);
     976    signal(SIGHUP, SIG_DFL);
     977    signal(SIGCHLD, SIG_DFL);
     978   
     979    sigChild_m_port = 0;
     980    sigGeneric_m_port = 0;
     981   
     982    // Remove run loop sources
     983    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kChildWatchMode);
     984    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), kqueueSrc, kChildWatchMode);
     985   
     986    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigChildSrc, kCFRunLoopDefaultMode);
     987    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), kqueueSrc, kCFRunLoopDefaultMode);
     988    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sigGenericSrc, kCFRunLoopDefaultMode);
     989   
     990    // Tear down signal handling infrastructure
     991    CFRelease(sigChildSrc);
     992    CFRelease(sigGenericSrc);
     993   
     994    CFRelease(sigChildPort);
     995    CFRelease(sigGenericPort);
     996   
     997    // Tear down kqueue infrastructure
     998    CFRelease(kqueueSrc);
     999    CFRelease(kqSocket);
     1000    close(kqfd);
     1001
     1002    // Tear down DynamicStore stuff
     1003    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), dsSrc, kCFRunLoopDefaultMode);
     1004   
     1005    CFRelease(dsSrc);
     1006    CFRelease(dsRef);
     1007   
     1008    // Tear down notifications from Notification Center
     1009    CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDistributedCenter(), kProgramName);
     1010    CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), kProgramName);
     1011
     1012    // Tear down power management stuff
     1013    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerRef), kCFRunLoopDefaultMode);
     1014    IODeregisterForSystemPower(&pwrNotifier);
     1015   
     1016    if (verbosity >= 3)
     1017        LogMessage("Terminating\n");
     1018   
     1019    return status; 
    10201020}
    10211021
     
    10241024CollectCmdArgs(char* arg1, int argc, char* const argv[], const char * const ** args)
    10251025{
    1026         // Count the number of additional arguments up until end of args or the marker argument ";"
    1027         int moreArgs = 0;
    1028         for (; moreArgs < argc && 0 != strcmp(";", argv[moreArgs]); ++moreArgs)
    1029                 ;
    1030                
    1031         // We were given one argument for free
    1032         int nargs = moreArgs + 1;
    1033                
    1034         // Allocate an array for the arguments
    1035         *args = calloc(sizeof(char**), nargs+1);
    1036         if (!*args)
    1037                 return 0;
    1038                
    1039         // Copy the arguments into our new array
    1040         (*(char***)args)[0] = arg1;
    1041        
    1042         int i;
    1043         for (i = 0; i < moreArgs; ++i)
    1044                 (*(char***)args)[i+1] = argv[i];
    1045                
    1046         // NULL-terminate the argument array
    1047         (*(char***)args)[nargs] = NULL;
    1048        
    1049         // Return number of args we consumed, accounting for potential trailing ";"
    1050         return (moreArgs == argc) ? moreArgs : moreArgs + 1;
     1026    // Count the number of additional arguments up until end of args or the marker argument ";"
     1027    int moreArgs = 0;
     1028    for (; moreArgs < argc && 0 != strcmp(";", argv[moreArgs]); ++moreArgs)
     1029        ;
     1030       
     1031    // We were given one argument for free
     1032    int nargs = moreArgs + 1;
     1033       
     1034    // Allocate an array for the arguments
     1035    *args = calloc(sizeof(char**), nargs+1);
     1036    if (!*args)
     1037        return 0;
     1038       
     1039    // Copy the arguments into our new array
     1040    (*(char***)args)[0] = arg1;
     1041   
     1042    int i;
     1043    for (i = 0; i < moreArgs; ++i)
     1044        (*(char***)args)[i+1] = argv[i];
     1045       
     1046    // NULL-terminate the argument array
     1047    (*(char***)args)[nargs] = NULL;
     1048   
     1049    // Return number of args we consumed, accounting for potential trailing ";"
     1050    return (moreArgs == argc) ? moreArgs : moreArgs + 1;
    10511051}
    10521052
     
    10551055AddSingleArrayArg(const char* arg, CFMutableArrayRef array)
    10561056{
    1057         CFStringRef s = CFStringCreateWithCString(NULL, arg, kCFStringEncodingUTF8);
    1058         CFArrayAppendValue(array, s);
    1059         CFRelease(s);
     1057    CFStringRef s = CFStringCreateWithCString(NULL, arg, kCFStringEncodingUTF8);
     1058    CFArrayAppendValue(array, s);
     1059    CFRelease(s);
    10601060}
    10611061
     
    10641064CollectArrayArgs(char* arg1, int argc, char* const argv[], CFMutableArrayRef array)
    10651065{
    1066         // Let CollectCmdArgs do the grunt work
    1067         const char* const* args = NULL;
    1068         int argsUsed = CollectCmdArgs(arg1, argc, argv, &args);
    1069        
    1070         // Add arguments to the mutable array
    1071         if (args != NULL)
    1072         {
    1073                 const char* const* argp = args;
    1074                 for (; *argp != NULL; ++argp)
    1075                         AddSingleArrayArg(*argp, array);
    1076                 free((void*)args);
    1077         }
    1078        
    1079         return argsUsed;
     1066    // Let CollectCmdArgs do the grunt work
     1067    const char* const* args = NULL;
     1068    int argsUsed = CollectCmdArgs(arg1, argc, argv, &args);
     1069   
     1070    // Add arguments to the mutable array
     1071    if (args != NULL)
     1072    {
     1073        const char* const* argp = args;
     1074        for (; *argp != NULL; ++argp)
     1075            AddSingleArrayArg(*argp, array);
     1076        free((void*)args);
     1077    }
     1078   
     1079    return argsUsed;
    10801080}
    10811081
    10821082
    10831083enum {
    1084         kVerbosityOpt                   = 256,
    1085         kRestartConfigOpt,
    1086         kRestartDistNotifyOpt,
    1087         kRestartDarwinNotifyOpt,
    1088         kRestartWakeupOpt,
    1089         kRestartNetChangeOpt,
    1090         kPidOpt,
    1091         kPidFileOpt,
    1092         kRestartHysteresisOpt
     1084    kVerbosityOpt           = 256,
     1085    kRestartConfigOpt,
     1086    kRestartDistNotifyOpt,
     1087    kRestartDarwinNotifyOpt,
     1088    kRestartWakeupOpt,
     1089    kRestartNetChangeOpt,
     1090    kPidOpt,
     1091    kPidFileOpt,
     1092    kRestartHysteresisOpt
    10931093};
    10941094
     
    10971097main(int argc, char* argv[])
    10981098{
    1099         int status = 0;
    1100        
    1101         // Initialization
    1102         kProgramName            = CFSTR("daemondo");
    1103         kChildWatchMode         = CFSTR("ChildWatch");          // A runloop mode
    1104        
    1105         scRestartPatterns       = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
    1106         distNotifyNames         = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
    1107         darwinNotifyNames       = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
    1108        
    1109         // Make stdout flush after every line
    1110         setvbuf(stdout, (char *)NULL, _IOLBF, 0);
    1111        
    1112         // Process arguments
    1113         static struct option longopts[] = {
    1114                         // Start/Stop/Restart the process
    1115                 { "start-cmd",          required_argument,              0,                              's' },
    1116                 { "stop-cmd",           required_argument,              0,                              'k' },
    1117                 { "restart-cmd",        required_argument,              0,                              'r' },
    1118                
    1119                         // Dynamic Store Keys to monitor
    1120                 { "restart-config",     required_argument,              0,                              kRestartConfigOpt },
    1121                
    1122                         // Notifications to monitor
    1123                 { "restart-dist-notify",
    1124                                                         required_argument,              0,                              kRestartDistNotifyOpt },
    1125                 { "restart-darwin-notify",
    1126                                                         required_argument,              0,                              kRestartDarwinNotifyOpt },
    1127                
    1128                         // Control over behavior on power state
    1129                 { "restart-wakeup",     no_argument,                    0,                              kRestartWakeupOpt },
    1130 
    1131                         // Short-cuts
    1132                 { "restart-netchange",
    1133                                                         no_argument,                    0,                              kRestartNetChangeOpt },
    1134                                                        
    1135                         // Pid-files
    1136                 { "pid",                        required_argument,              0,                              kPidOpt },
    1137                 { "pidfile",            required_argument,              0,                              kPidFileOpt },
    1138                
    1139                         // other
    1140                 { "help",                       no_argument,                    0,                              'h' },
    1141                 { "v",                          no_argument,                    0,                              'v' },
    1142                 { "verbosity",          optional_argument,              0,                              kVerbosityOpt },
    1143                 { "version",            no_argument,                    0,                              'V' },
    1144                 { "label",                      required_argument,              0,                              'l' },
    1145                 { "restart-hysteresis",
    1146                                                         required_argument,              0,                              kRestartHysteresisOpt },
    1147                
    1148                 { 0,                            0,                      0,              0 }
    1149         };
    1150 
    1151         while (status == 0 && optind < argc)
    1152         {
    1153                 int optindex = 0;
    1154                 int ret = getopt_long(argc, argv, ":s:k:r:l:hvV", longopts, &optindex);
    1155                 int opt = ret;
    1156                 switch (opt)
    1157                 {
    1158                 case ':':
    1159                         printf("Option error: missing argument for option %s\n", longopts[optindex].name);
    1160                         exit(1);
    1161                         break;
    1162                        
    1163                 case 's':
    1164                         if (startArgs)
    1165                         {
    1166                                 printf("Option error: start-cmd option may be given only once.\n");
    1167                                 exit(1);
    1168                         }
    1169                         else
    1170                         {
    1171                                 optind += CollectCmdArgs(optarg, argc - optind, argv + optind, &startArgs);
    1172                                 optreset = 1;
    1173                         }
    1174                         break;
    1175                        
    1176                 case 'k':
    1177                         if (stopArgs)
    1178                         {
    1179                                 printf("Option error: stop-cmd option may be given only once.\n");
    1180                                 exit(1);
    1181                         }
    1182                         else
    1183                         {
    1184                                 optind += CollectCmdArgs(optarg, argc - optind, argv + optind, &stopArgs);
    1185                                 optreset = 1;
    1186                         }
    1187                         break;
    1188 
    1189                 case 'r':
    1190                         if (restartArgs)
    1191                         {
    1192                                 printf("Option error: restart-cmd option may be given only once.\n");
    1193                                 exit(1);
    1194                         }
    1195                         else
    1196                         {
    1197                                 optind += CollectCmdArgs(optarg, argc - optind, argv + optind, &restartArgs);
    1198                                 optreset = 1;
    1199                         }
    1200                         break;
    1201                        
    1202                 case kRestartConfigOpt:
    1203                         optind += CollectArrayArgs(optarg, argc - optind, argv + optind, scRestartPatterns);
    1204                         optreset = 1;
    1205                         break;
    1206                        
    1207                 case kRestartDistNotifyOpt:
    1208                         optind += CollectArrayArgs(optarg, argc - optind, argv + optind, distNotifyNames);
    1209                         optreset = 1;
    1210                         break;
    1211                        
    1212                 case kRestartDarwinNotifyOpt:
    1213                         optind += CollectArrayArgs(optarg, argc - optind, argv + optind, darwinNotifyNames);
    1214                         optreset = 1;
    1215                         break;
    1216                        
    1217                 case kRestartWakeupOpt:
    1218                         restartOnWakeup = TRUE;
    1219                         break;
    1220                        
    1221                 case kRestartNetChangeOpt:
    1222                         AddSingleArrayArg("com.apple.system.config.network_change", darwinNotifyNames);
    1223                         break;
    1224                        
    1225                 case kRestartHysteresisOpt:
    1226                         restartHysteresis = strtof(optarg, NULL);
    1227                         if (restartHysteresis < 0)
    1228                                 restartHysteresis = 0;
    1229                         break;
    1230                        
    1231                 case kPidOpt:
    1232                         if      (0 == strcasecmp(optarg, "none"))
    1233                                 pidStyle = kPidStyleNone;
    1234                         else if (0 == strcasecmp(optarg, "exec"))
    1235                                 pidStyle = kPidStyleExec;
    1236                         else if (0 == strcasecmp(optarg, "fileauto"))
    1237                                 pidStyle = kPidStyleFileAuto;
    1238                         else if (0 == strcasecmp(optarg, "fileclean"))
    1239                                 pidStyle = kPidStyleFileClean;
    1240                         else {
    1241                                 status = 1;
    1242                                 LogMessage("Unexpected pid style %s\n", optarg);
    1243                         }
    1244                         break;
    1245                
    1246                 case kPidFileOpt:
    1247                         if (pidFile != NULL)
    1248                                 free((char*)pidFile);
    1249                         pidFile = strdup(optarg);
    1250                         break;
    1251                
    1252                 case 'h':
    1253                         DoHelp();
    1254                         exit(0);
    1255                         break;
    1256                        
    1257                 case 'l':
    1258                         if (label != NULL)
    1259                                 free((char*)label);
    1260                         label = strdup(optarg);
    1261                         break;
    1262                        
    1263                 case 'v':
    1264                         ++verbosity;
    1265                         break;
    1266                
    1267                 case kVerbosityOpt:
    1268                         if (optarg)
    1269                                 verbosity = strtol(optarg, NULL,  10);
    1270                         else
    1271                                 ++verbosity;
    1272                         break;
    1273        
    1274                 case 'V':
    1275                         DoVersion();
    1276                         break;
    1277                        
    1278                 default:
    1279                         LogMessage("unexpected parameter: %s\n", argv[optind]);
    1280                         status = 1;
    1281                         break;
    1282                 }
    1283         }
    1284        
    1285         // Default the pid style if it wasn't given
    1286         if (pidStyle == kPidStyleUnknown)
    1287         {
    1288                 if (startArgs && !stopArgs && !restartArgs)
    1289                         pidStyle = kPidStyleExec;
    1290                 else
    1291                         pidStyle = kPidStyleNone;
    1292         }
    1293        
    1294         // Go into our main loop
    1295         if (status == 0 && startArgs)
    1296                 status = MainLoop();
    1297         else
    1298                 DoHelp();
    1299                
     1099    int status = 0;
     1100   
     1101    // Initialization
     1102    kProgramName        = CFSTR("daemondo");
     1103    kChildWatchMode     = CFSTR("ChildWatch");      // A runloop mode
     1104   
     1105    scRestartPatterns   = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     1106    distNotifyNames     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     1107    darwinNotifyNames   = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     1108   
     1109    // Make stdout flush after every line
     1110    setvbuf(stdout, (char *)NULL, _IOLBF, 0);
     1111   
     1112    // Process arguments
     1113    static struct option longopts[] = {
     1114            // Start/Stop/Restart the process
     1115        { "start-cmd",      required_argument,      0,              's' },
     1116        { "stop-cmd",       required_argument,      0,              'k' },
     1117        { "restart-cmd",    required_argument,      0,              'r' },
     1118       
     1119            // Dynamic Store Keys to monitor
     1120        { "restart-config", required_argument,      0,              kRestartConfigOpt },
     1121       
     1122            // Notifications to monitor
     1123        { "restart-dist-notify",
     1124                            required_argument,      0,              kRestartDistNotifyOpt },
     1125        { "restart-darwin-notify",
     1126                            required_argument,      0,              kRestartDarwinNotifyOpt },
     1127       
     1128            // Control over behavior on power state
     1129        { "restart-wakeup", no_argument,            0,              kRestartWakeupOpt },
     1130
     1131            // Short-cuts
     1132        { "restart-netchange",
     1133                            no_argument,            0,              kRestartNetChangeOpt },
     1134                           
     1135            // Pid-files
     1136        { "pid",            required_argument,      0,              kPidOpt },
     1137        { "pidfile",        required_argument,      0,              kPidFileOpt },
     1138       
     1139            // other
     1140        { "help",           no_argument,            0,              'h' },
     1141        { "v",              no_argument,            0,              'v' },
     1142        { "verbosity",      optional_argument,      0,              kVerbosityOpt },
     1143        { "version",        no_argument,            0,              'V' },
     1144        { "label",          required_argument,      0,              'l' },
     1145        { "restart-hysteresis",
     1146                            required_argument,      0,              kRestartHysteresisOpt },
     1147       
     1148        { 0,                0,                      0,              0 }
     1149    };
     1150
     1151    while (status == 0 && optind < argc)
     1152    {
     1153        int optindex = 0;
     1154        int ret = getopt_long(argc, argv, ":s:k:r:l:hvV", longopts, &optindex);
     1155        int opt = ret;
     1156        switch (opt)
     1157        {
     1158        case ':':
     1159            printf("Option error: missing argument for option %s\n", longopts[optindex].name);
     1160            exit(1);
     1161            break;
     1162           
     1163        case 's':
     1164            if (startArgs)
     1165            {
     1166                printf("Option error: start-cmd option may be given only once.\n");
     1167                exit(1);
     1168            }
     1169            else
     1170            {
     1171                optind += CollectCmdArgs(optarg, argc - optind, argv + optind, &startArgs);
     1172                optreset = 1;
     1173            }
     1174            break;
     1175           
     1176        case 'k':
     1177            if (stopArgs)
     1178            {
     1179                printf("Option error: stop-cmd option may be given only once.\n");
     1180                exit(1);
     1181            }
     1182            else
     1183            {
     1184                optind += CollectCmdArgs(optarg, argc - optind, argv + optind, &stopArgs);
     1185                optreset = 1;
     1186            }
     1187            break;
     1188
     1189        case 'r':
     1190            if (restartArgs)
     1191            {
     1192                printf("Option error: restart-cmd option may be given only once.\n");
     1193                exit(1);
     1194            }
     1195            else
     1196            {
     1197                optind += CollectCmdArgs(optarg, argc - optind, argv + optind, &restartArgs);
     1198                optreset = 1;
     1199            }
     1200            break;
     1201           
     1202        case kRestartConfigOpt:
     1203            optind += CollectArrayArgs(optarg, argc - optind, argv + optind, scRestartPatterns);
     1204            optreset = 1;
     1205            break;
     1206           
     1207        case kRestartDistNotifyOpt:
     1208            optind += CollectArrayArgs(optarg, argc - optind, argv + optind, distNotifyNames);
     1209            optreset = 1;
     1210            break;
     1211           
     1212        case kRestartDarwinNotifyOpt:
     1213            optind += CollectArrayArgs(optarg, argc - optind, argv + optind, darwinNotifyNames);
     1214            optreset = 1;
     1215            break;
     1216           
     1217        case kRestartWakeupOpt:
     1218            restartOnWakeup = TRUE;
     1219            break;
     1220           
     1221        case kRestartNetChangeOpt:
     1222            AddSingleArrayArg("com.apple.system.config.network_change", darwinNotifyNames);
     1223            break;
     1224           
     1225        case kRestartHysteresisOpt:
     1226            restartHysteresis = strtof(optarg, NULL);
     1227            if (restartHysteresis < 0)
     1228                restartHysteresis = 0;
     1229            break;
     1230           
     1231        case kPidOpt:
     1232            if      (0 == strcasecmp(optarg, "none"))
     1233                pidStyle = kPidStyleNone;
     1234            else if (0 == strcasecmp(optarg, "exec"))
     1235                pidStyle = kPidStyleExec;
     1236            else if (0 == strcasecmp(optarg, "fileauto"))
     1237                pidStyle = kPidStyleFileAuto;
     1238            else if (0 == strcasecmp(optarg, "fileclean"))
     1239                pidStyle = kPidStyleFileClean;
     1240            else {
     1241                status = 1;
     1242                LogMessage("Unexpected pid style %s\n", optarg);
     1243            }
     1244            break;
     1245       
     1246        case kPidFileOpt:
     1247            if (pidFile != NULL)
     1248                free((char*)pidFile);
     1249            pidFile = strdup(optarg);
     1250            break;
     1251       
     1252        case 'h':
     1253            DoHelp();
     1254            exit(0);
     1255            break;
     1256           
     1257        case 'l':
     1258            if (label != NULL)
     1259                free((char*)label);
     1260            label = strdup(optarg);
     1261            break;
     1262           
     1263        case 'v':
     1264            ++verbosity;
     1265            break;
     1266       
     1267        case kVerbosityOpt:
     1268            if (optarg)
     1269                verbosity = strtol(optarg, NULL,  10);
     1270            else
     1271                ++verbosity;
     1272            break;
     1273   
     1274        case 'V':
     1275            DoVersion();
     1276            break;
     1277           
     1278        default:
     1279            LogMessage("unexpected parameter: %s\n", argv[optind]);
     1280            status = 1;
     1281            break;
     1282        }
     1283    }
     1284   
     1285    // Default the pid style if it wasn't given
     1286    if (pidStyle == kPidStyleUnknown)
     1287    {
     1288        if (startArgs && !stopArgs && !restartArgs)
     1289            pidStyle = kPidStyleExec;
     1290        else
     1291            pidStyle = kPidStyleNone;
     1292    }
     1293   
     1294    // Go into our main loop
     1295    if (status == 0 && startArgs)
     1296        status = MainLoop();
     1297    else
     1298        DoHelp();
     1299       
    13001300    return status;
    13011301}
Note: See TracChangeset for help on using the changeset viewer.