Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

CodeBreaker

macrumors 6502
Original poster
Nov 5, 2010
494
1
Sea of Tranquility
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?
 
Last edited:

chown33

Moderator
Staff member
Aug 9, 2009
10,760
8,452
A sea of green
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.
 

CodeBreaker

macrumors 6502
Original poster
Nov 5, 2010
494
1
Sea of Tranquility
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.

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
 

chown33

Moderator
Staff member
Aug 9, 2009
10,760
8,452
A sea of green
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.

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.
 

CodeBreaker

macrumors 6502
Original poster
Nov 5, 2010
494
1
Sea of Tranquility
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.

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.
 

KnightWRX

macrumors Pentium
Jan 28, 2009
15,046
4
Quebec, Canada
Ok, so apparently NSLogs don't work.

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.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,760
8,452
A sea of green
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.

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.
 

CodeBreaker

macrumors 6502
Original poster
Nov 5, 2010
494
1
Sea of Tranquility
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.

Thanks for the tip. I basically needed logs to just find out if my code was working.

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.

Login window seems just the right time for my program to launch. Thanks for the info.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.