Resolved Creating a simple Hello World launch daemon

Discussion in 'Mac Programming' started by CodeBreaker, Mar 10, 2012.

  1. CodeBreaker, Mar 10, 2012
    Last edited: Mar 10, 2012

    macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #1
    I'm having a hard time creating a simple hello world launch daemon. It is launched every 10 seconds and just logs "hello world" to the console. So I just compiled the Command Tool (Foundation) template of Xcode. Then I moved the product to /tmp/ and created a plist for launchd:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>Label</key>
    	<string>helloDaemon</string>
    	<key>ProgramArguments</key>
    	<array>
    		<string>/tmp/helloDaemon</string>
    	</array>
    	<key>StartInterval</key>
    	<integer>10</integer>
    </dict>
    </plist>
    
    I loaded it into launchd using launchctl.
    Launchd starts the process every 10 seconds, but it does not log "hello world". Also I keep getting this in the console:
    Code:
    11/03/2012 00:55:35.141 com.apple.launchd: (helloDaemon) Throttling respawn: Will start in 1 seconds
    11/03/2012 00:55:45.141 com.apple.launchd: (helloDaemon) Throttling respawn: Will start in 2 seconds
    11/03/2012 00:55:55.140 com.apple.launchd: (helloDaemon) Throttling respawn: Will start in 3 seconds
    
    So what's going wrong?
     
  2. macrumors 603

    Joined:
    Aug 9, 2009
    #2
    Post the source code for helloDaemon.

    Have you read TN2083? It's indispensible:
    https://developer.apple.com/library/mac/#technotes/tn2083/_index.html

    Have you tried running your program as a LaunchAgent?
    Is there a specific reason you're not running it as a LaunchAgent?


    You have two separable issues:
    1. The code in helloDaemon.
    2. The launchd plist.

    I recommend separating them. I also recommend not relying on system console output. Instead, append any output to a specific file.

    For example, to append output to a specific file in /tmp, the following shell command would work:
    Code:
    echo "Hello daemon" >>/tmp/hello.txt
    
    Since you can't use shell redirection operators in a launchd plist, you must tell launchd that bash is the program to run, then it will interpret the command line. Bash has a -c option which interprets the remaining args as the commands to run. So:
    Code:
    <array>
    	<string>/bin/bash</string>
    	<string>-c</string>
    	<string>echo "Hello daemon" >>/tmp/hello.txt</string>
    </array>
    
    Or look up the launchd plist keys StandardOutPath and StandardErrorPath.
     
  3. thread starter macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #3
    I started off this project after reading Apple's TN and the launchd.plist man page. My app should be a daemon because i need it to be always running in the background regardless of who logs in to the computer. I will be running it as root. The source for my app is nothing special, it is just Apple's code. There is only one class (main.m), linked against the Foundation framework (which is daemon safe). Here's the content of main.m:
    Code:
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[])
    {
    
        @autoreleasepool {
            
            // insert code here...
            NSLog(@"Hello, World!");
            
        }
        return 0;
    }
    
    
    I tried you shell code, which works perfectly.

    Thanks
     
  4. thread starter macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #4
    Ok, so apparently NSLogs don't work. I directed the output to a file and it worked. Thanks chown33.
     
  5. macrumors 603

    Joined:
    Aug 9, 2009
    #5
    These do not disqualify it from running as a launch agent. There is a system-wide launch agents directory in /Library. They are run as root by default.
     
  6. thread starter macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #6
    Correct me if I am wrong. I believe Launch Agents are run on behalf of a user and hence need a user to be logged in to the OS, whereas Launch Daemons can be run even if no one is logged into the OS.
     
  7. macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #7
    Why not use the good old syslog() call ?

    Code:
    SYSLOG(3)                BSD Library Functions Manual                SYSLOG(3)
    
    NAME
         closelog, openlog, setlogmask, syslog, vsyslog -- control system log
    
    LIBRARY
         Standard C Library (libc, -lc)
    
    SYNOPSIS
         #include <syslog.h>
    ...
    void
         syslog(int priority, const char *message, ...);
    
    That way you don't have to worry about rotating your log file/configuring its location and other details the system syslog daemon takes care of.
     
  8. macrumors 603

    Joined:
    Aug 9, 2009
    #8
    That's basically right, but see the man pages for launchd.plist and launchctl. Look at the plist key LimitLoadToSessionTypes, then at the -S option to launchctl which lists the session types. The LoginWindow session type will run a launch agent at the login window. For example, I have a wacom graphics tablet whose LaunchAgents plist file contains Aqua and LoginWindow session types. This means it runs even when no one is logged in. The file is owned by root, and is unwritable to others.

    I have not experimented with the other session types.
     
  9. thread starter macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #9
    Thanks for the tip. I basically needed logs to just find out if my code was working.

    Login window seems just the right time for my program to launch. Thanks for the info.
     

Share This Page