{
	"id": "5b2a0c42-f248-41b5-a61c-95aab8ff2b75",
	"created_at": "2026-04-06T01:32:36.233674Z",
	"updated_at": "2026-04-10T03:35:21.513436Z",
	"deleted_at": null,
	"sha1_hash": "148c0beef8aa8534cbbe73efcfea68414b2ffc67",
	"title": "Creating Launch Daemons and Agents",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 200951,
	"plain_text": "Creating Launch Daemons and Agents\r\nPublished: 2016-09-13 · Archived: 2026-04-06 00:10:52 UTC\r\nIf you are developing daemons to run on OS X, it is highly recommended that you design your daemons to be\r\nlaunchd compliant. Using launchd provides better performance and flexibility for daemons. It also improves the\r\nability of administrators to manage the daemons running on a given system.\r\nIf you are running per-user background processes for OS X, launchd is also the preferred way to start these\r\nprocesses. These per-user processes are referred to as user agents. A user agent is essentially identical to a daemon, but\r\nis specific to a given logged-in user and executes only while that user is logged in.\r\nUnless otherwise noted, for the purposes of this chapter, the terms “daemon” and “agent” can be used interchangeably.\r\nThus, the term “daemon” is used generically in this section to encompass both system-level daemons and user agents\r\nexcept where otherwise noted.\r\nThere are four ways to launch daemons using launchd . The preferred method is on-demand launching, but launchd\r\ncan launch daemons that run continuously, and can replace inetd for launching inetd -style daemons. In addition,\r\nlaunchd can start jobs at timed intervals.\r\nAlthough launchd supports non-launch-on-demand daemons, this use is not recommended. The launchd daemon\r\nwas designed to remove the need for dependency ordering among daemons. If you do not make your daemon be\r\nlaunched on demand, you will have to handle these dependencies in another way, such as by using the legacy startup\r\nitem mechanism.\r\nLaunching Custom Daemons Using launchd\r\nWith the introduction of launchd in OS X v10.4, an effort was made to improve the steps needed to launch and\r\nmaintain daemons. What launchd provides is a harness for launching your daemon as needed. To client programs,\r\nthe port representing your daemon’s service is always available and ready to handle requests. In reality, the daemon\r\nmay or may not be running. When a client sends a request to the port, launchd may have to launch the daemon so\r\nthat it can handle the request. Once launched, the daemon can continue running or shut itself down to free up the\r\nmemory and resources it holds. If a daemon shuts itself down, launchd once again relaunches it as needed to process\r\nrequests.\r\nIn addition to the launch-on-demand feature, launchd provides the following benefits to daemon developers:\r\nSimplifies the process of making a daemon by handling many of the standard housekeeping chores normally\r\nassociated with launching a daemon.\r\nProvides system administrators with a central place to manage daemons on the system.\r\nSupports inetd -style daemons.\r\nEliminates the primary reason for running daemons as root. Because launchd runs as root, it can create low-numbered TCP/IP listen sockets and hand them off to the daemon.\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 1 of 20\n\nSimplifies error handling and dependency management for inter-daemon communication. Because daemons\r\nlaunch on demand, communication requests do not fail if the daemon is not launched. They are simply delayed\r\nuntil the daemon can launch and process them.\r\nThe launchd Startup Process\r\nAfter the system is booted and the kernel is running, launchd is run to finish the system initialization. As part of that\r\ninitialization, it goes through the following steps:\r\n1. It loads the parameters for each launch-on-demand system-level daemon from the property list files found in\r\n/System/Library/LaunchDaemons/ and /Library/LaunchDaemons/ .\r\n2. It registers the sockets and file descriptors requested by those daemons.\r\n3. It launches any daemons that requested to be running all the time.\r\n4. As requests for a particular service arrive, it launches the corresponding daemon and passes the request to it.\r\n5. When the system shuts down, it sends a SIGTERM signal to all of the daemons that it started.\r\nThe process for per-user agents is similar. When a user logs in, a per-user launchd is started. It does the following:\r\n1. It loads the parameters for each launch-on-demand user agent from the property list files found in\r\n/System/Library/LaunchAgents , /Library/LaunchAgents , and the user’s individual Library/LaunchAgents\r\ndirectory.\r\n2. It registers the sockets and file descriptors requested by those user agents.\r\n3. It launches any user agents that requested to be running all the time.\r\n4. As requests for a particular service arrive, it launches the corresponding user agent and passes the request to it.\r\n5. When the user logs out, it sends a SIGTERM signal to all of the user agents that it started.\r\nBecause launchd registers the sockets and file descriptors used by all daemons before it launches any of them,\r\ndaemons can be launched in any order. If a request comes in for a daemon that is not yet running, the requesting\r\nprocess is suspended until the target daemon finishes launching and responds.\r\nIf a daemon does not receive any requests over a specific period of time, it can choose to shut itself down and release\r\nthe resources it holds. When this happens, launchd monitors the shutdown and makes a note to launch the daemon\r\nagain when future requests arrive.\r\nCreating a launchd Property List File\r\nTo run under launchd , you must provide a configuration property list file for your daemon. This file contains\r\ninformation about your daemon, including the list of sockets or file descriptors it uses to process requests. Specifying\r\nthis information in a property list file lets launchd register the corresponding file descriptors and launch your\r\ndaemon only after a request arrives for your daemon’s services. Table 5-1 lists the required and recommended keys for\r\nall daemons.\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 2 of 20\n\nThe property list file is structured the same for both daemons and agents. You indicate whether it describes a daemon\r\nor agent by the directory you place it in. Property list files describing daemons are installed in\r\n/Library/LaunchDaemons , and those describing agents are installed in /Library/LaunchAgents or in the\r\nLaunchAgents subdirectory of an individual user’s Library directory. (The appropriate location for executables that\r\nyou launch from your job is /usr/local/libexec .)\r\nTable 5-1  Required and recommended property list keys\r\nKey Description\r\nLabel Contains a unique string that identifies your daemon to launchd . (required)\r\nProgramArguments Contains the arguments used to launch your daemon. (required)\r\ninetdCompatibility\r\nIndicates that your daemon requires a separate instance per incoming connection. This\r\ncauses launchd to behave like inetd , passing each daemon a single socket that is\r\nalready connected to the incoming client. (required if your daemon was designed to be\r\nlaunched by inetd ; otherwise, must not be included)\r\nKeepAlive\r\nThis key specifies whether your daemon launches on-demand or must always be\r\nrunning. It is recommended that you design your daemon to be launched on-demand.\r\nWriting a “Hello World!” launchd Job\r\nThe following simple example launches a daemon named hello , passing world as a single argument, and instructs\r\nlaunchd to keep the job running:\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 3 of 20\n\nLabelcom.example.helloProgramArgumentshelloworldKeepAlive https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\nPage 4 of 20\n\nIn this example, there are three keys in the top level dictionary. The first is Label , which uniquely identifies the job.\r\nwhen. The second is ProgramArguments which has a value of an array of strings which represent the tokenized\r\narguments and the program to run. The third and final key is KeepAlive which indicates that this job needs to be\r\nrunning at all times, rather than the default launch-on-demand behavior, so launchd should always try to keep this job\r\nrunning.\r\nListening on Sockets\r\nYou can also include other keys in your configuration property list file. For example, if your daemon monitors a well-known port (one of the ports listed in /etc/services ), add a Sockets entry as follows:\r\n\u003ckey\u003eSockets\u003c/key\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eListeners\u003c/key\u003e\r\n \u003cdict\u003e\r\n \u003ckey\u003eSockServiceName\u003c/key\u003e\r\n \u003cstring\u003ebootps\u003c/string\u003e\r\n \u003ckey\u003eSockType\u003c/key\u003e\r\n \u003cstring\u003edgram\u003c/string\u003e\r\n \u003ckey\u003eSockFamily\u003c/key\u003e\r\n \u003cstring\u003eIPv4\u003c/string\u003e\r\n \u003c/dict\u003e\r\n\u003c/dict\u003e\r\nThe string for SockServiceName typically comes from the leftmost column in /etc/services . The SockType is one\r\nof dgram (UDP) or stream (TCP/IP). If you need to pass a port number that is not listed in the well-known ports\r\nlist, the format is the same, except the string contains a number instead of a name. For example:\r\n\u003ckey\u003eSockServiceName\u003c/key\u003e\r\n\u003cstring\u003e23\u003c/string\u003e\r\nDebugging launchd Jobs\r\nThere are some options that are useful for debugging your launchd job.\r\nThe following example enables core dumps, sets standard out and error to go to a log file, and instructs launchd to\r\ntemporarily increase the debug level of its logging while acting on behalf of your job (remember to adjust your\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 5 of 20\n\nsyslog.conf accordingly):\r\n \r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.example.sleep\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003esleep\u003c/string\u003e\r\n \u003cstring\u003e100\u003c/string\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 6 of 20\n\nStandardOutPath/var/log/myjob.logStandardErrorPath/var/log/myjob.logDebugSoftResourceLimitsCore9223372036854775807 https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\nPage 7 of 20\n\n\u003ckey\u003eHardResourceLimits\u003c/key\u003e\r\n \u003cdict\u003e\r\n \u003ckey\u003eCore\u003c/key\u003e\r\n \u003cinteger\u003e9223372036854775807\u003c/integer\u003e\r\n \u003c/dict\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nRunning a Job Periodically\r\nThe following example creates a job that is run every five minutes (300 seconds):\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 8 of 20\n\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.example.touchsomefile\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003etouch\u003c/string\u003e\r\n \u003cstring\u003e/tmp/helloworld\u003c/string\u003e\r\n \u003c/array\u003e\r\n \u003ckey\u003eStartInterval\u003c/key\u003e\r\n \u003cinteger\u003e300\u003c/integer\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 9 of 20\n\nAlternately, you can specify a calendar-based interval. The following example starts the job on the 7th day of every\r\nmonth at 13:45 (1:45 pm). Like the Unix cron subsystem, any missing key of the StartCalendarInterval dictionary\r\nis treated as a wildcard—in this case, the month is omitted, so the job is run every month.\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.example.touchsomefile\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003etouch\u003c/string\u003e\r\n \u003cstring\u003e/tmp/helloworld\u003c/string\u003e\r\n \u003c/array\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 10 of 20\n\n\u003ckey\u003eStartCalendarInterval\u003c/key\u003e\r\n \u003cdict\u003e\r\n \u003ckey\u003eMinute\u003c/key\u003e\r\n \u003cinteger\u003e45\u003c/integer\u003e\r\n \u003ckey\u003eHour\u003c/key\u003e\r\n \u003cinteger\u003e13\u003c/integer\u003e\r\n \u003ckey\u003eDay\u003c/key\u003e\r\n \u003cinteger\u003e7\u003c/integer\u003e\r\n \u003c/dict\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nMonitoring a Directory\r\nThe following example starts the job whenever any of the paths being watched have changed:\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 11 of 20\n\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.example.watchhostconfig\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003esyslog\u003c/string\u003e\r\n \u003cstring\u003e-s\u003c/string\u003e\r\n \u003cstring\u003e-l\u003c/string\u003e\r\n \u003cstring\u003enotice\u003c/string\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 12 of 20\n\n\u003cstring\u003esomebody touched /etc/hostconfig\u003c/string\u003e\r\n \u003c/array\u003e\r\n \u003ckey\u003eWatchPaths\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003e/etc/hostconfig\u003c/string\u003e\r\n \u003c/array\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nAn additional file system trigger is the notion of a queue directory. The launchd daemon starts your job whenever the\r\ngiven directories are non-empty, and it keeps your job running as long as those directories are not empty:\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 13 of 20\n\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.example.mailpush\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003emy_custom_mail_push_tool\u003c/string\u003e\r\n \u003c/array\u003e\r\n \u003ckey\u003eQueueDirectories\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003e/var/spool/mymailqdir\u003c/string\u003e\r\n \u003c/array\u003e\r\n\u003c/dict\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 14 of 20\n\n\u003c/plist\u003e\r\nEmulating inetd\r\nThe launchd daemon emulates the older inetd -style daemon semantics if you provide the inetdCompatibility\r\nkey:\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n \u003ckey\u003eLabel\u003c/key\u003e\r\n \u003cstring\u003ecom.example.telnetd\u003c/string\u003e\r\n \u003ckey\u003eProgramArguments\u003c/key\u003e\r\n \u003carray\u003e\r\n \u003cstring\u003e/usr/libexec/telnetd\u003c/string\u003e\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 15 of 20\n\ninetdCompatibilityWaitSocketsListenersSockServiceNametelnet https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\nPage 16 of 20\n\n\u003ckey\u003eSockType\u003c/key\u003e\r\n \u003cstring\u003estream\u003c/string\u003e\r\n \u003c/dict\u003e\r\n \u003c/dict\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e\r\nBehavior for Processes Managed by launchd\r\nProcesses that are managed by launchd must follow certain requirements so that they interact properly with\r\nlaunchd . This includes launch daemons and launch agents.\r\nRequired Behaviors\r\nTo support launchd , you must obey the following guidelines when writing your daemon code:\r\nYou must provide a property list with some basic launch-on-demand criteria for your daemon. See Creating a\r\nlaunchd Property List File.\r\nYou must not daemonize your process. This includes calling the daemon function, calling fork followed by\r\nexec , or calling fork followed by exit . If you do, launchd thinks your process has died. Depending on\r\nyour property list key settings, launchd will either keep trying to relaunch your process until it gives up (with\r\na “respawning too fast” error message) or will be unable to restart it if it really does die.\r\nDaemons and agents that are installed globally must be owned by the root user. Agents installed for the current\r\nuser must be owned by that user. All daemons and agents must not be group writable or world writable. (That\r\nis, they must have file mode set to 600 or 400 .)\r\nRecommended Behaviors\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 17 of 20\n\nTo support launchd , it is recommended that you obey the following guidelines when writing your daemon code:\r\nWait until your daemon is fully initialized before attempting to process requests. Your daemon should always\r\nprovide a reasonable response (rather than an error) when processing requests.\r\nRegister the sockets and file descriptors used by your daemon in your launchd configuration property list file.\r\nIf your daemon advertises a socket, check in with launchd as part of your daemon initialization. For an\r\nexample implementation of the check-in process, see SampleD.\r\nDuring check-in, get the launch dictionary from launchd , extract and store its contents, and then discard the\r\ndictionary. Accessing the data structure used for the dictionary is very slow, so storing the whole dictionary\r\nlocally and accessing it frequently could hurt performance.\r\nProvide a handler to catch the SIGTERM signal.\r\nIn addition to the preceding list, the following is a list of things it is recommended you avoid in your code:\r\nDo not set the user or group ID for your daemon. Include the UserName , UID , GroupName , or GID keys in\r\nyour daemon’s configuration property list instead.\r\nDo not set the working directory. Include the WorkingDirectory key in your daemon’s configuration property\r\nlist instead.\r\nDo not call chroot to change the root directory. Include the RootDirectory key in your daemon’s\r\nconfiguration property list instead.\r\nDo not call setsid to create a new session.\r\nDo not close any stray file descriptors.\r\nDo not change stdio to point to /dev/null . Include the StandardOutPath or StandardErrorPath keys in\r\nyour daemon’s configuration property list file instead.\r\nDo not set up resource limits with setrusage .\r\nDo not set the daemon priority with setpriority\r\nAlthough many of the preceding behaviors may be standard tasks for daemons to perform, they are not recommended\r\nwhen running under launchd . The reason is that launchd configures the operating environment for the daemons\r\nthat it manages. Changing this environment could interfere with the normal operation of your daemon.\r\nDeciding When to Shut Down\r\nIf you do not expect your daemon to handle many requests, you might want to shut it down after a predetermined\r\namount of idle time, rather than continue running. Although a well-written daemon does not consume any CPU\r\nresources when idle, it still consumes memory and could be paged out during periods of intense memory use.\r\nThe timing of when to shut down is different for each daemon and depends on several factors, including:\r\nThe number and frequency of requests it receives\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 18 of 20\n\nThe time it takes to launch the daemon\r\nThe time it takes to shut down the daemon\r\nThe need to retain state information\r\nIf your daemon does not receive frequent requests and can be launched and shut down quickly, you might prefer to\r\nshut it down rather than wait for it to be paged out to disk. Paging memory to disk, and subsequently reading it back,\r\nincurs two disk operations. If you do not need the data stored in memory, your daemon can shut down and avoid the\r\nstep of writing memory to disk.\r\nSpecial Dependencies\r\nWhile launchd takes care of dependencies between daemons, in some cases, your daemon may depend on other\r\nsystem functionality that cannot be addressed in this manner. This section describes many of these special cases and\r\nhow to handle them.\r\nNetwork Availability\r\nIf your daemon depends on the network being available, this cannot be handled with dependencies because network\r\ninterfaces can come and go at any time in OS X. To solve this problem, you should use the network reachability\r\nfunctionality or the dynamic store functionality in the System Configuration framework. This is documented in System\r\nConfiguration Programming Guidelines and System Configuration Framework Reference. For more information about\r\nnetwork reachability, see Determining Reachability and Getting Connected in System Configuration Programming\r\nGuidelines.\r\nDisk or Server Availability\r\nIf your daemon depends on the availability of a mounted volume (whether local or remote), you can determine the\r\nstatus of that volume using the Disk Arbitration framework. This is documented in Disk Arbitration Framework\r\nReference.\r\nNon-launchd Daemons\r\nIf your daemon has a dependency on a non- launchd daemon, you must take additional care to ensure that your\r\ndaemon works correctly if that non- launchd daemon has not started when your daemon is started. The best way to do\r\nthis is to include a loop at start time that checks to see if the non- launchd daemon is running, and if not, sleeps for\r\nseveral seconds before checking again.\r\nBe sure to set up handlers for SIGTERM prior to this loop to ensure that you are able to properly shut down if the\r\ndaemon you rely on never becomes available.\r\nUser Logins\r\nIn general, a daemon should not care whether a user is logged in, and user agents should be used to provide per-user\r\nfunctionality. However, in some cases, this may be useful.\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 19 of 20\n\nTo determine what user is logged in at the console, you can use the System Configuration framework, as described in\r\nTechnical Q\u0026A QA1133.\r\nKernel Extensions\r\nIf your daemon requires that a certain kernel extension be loaded prior to executing, you have two options: load it\r\nyourself, or wait for it to be loaded.\r\nThe daemon may manually request that an extension be loaded. To do this, run kextload with the appropriate\r\narguments using exec or variants thereof. I/O Kit kernel extensions should not be loaded with kextload ; the I/O\r\nKit will load them automatically when they are needed.\r\nAlternatively, our daemon may wait for a kernel service to be available. To do this, you should first register for service\r\nchange notification. This is further documented in I/O Kit Framework Reference.\r\nAfter registering for these notifications, you should check to see if the service is already available. By doing this after\r\nregistering for notifications, you avoid waiting forever if the service becomes available between checking for\r\navailability and registering for the notification.\r\nFor more information about I/O Kit services and matching, see IOKit Fundamentals, I/O Kit Framework Reference\r\n(user space reference), and Kernel Framework Reference (kernel space reference).\r\nFor More Information\r\nThe manual pages for launchd and launchd.plist are the two best sources for information about launchd .\r\nIn addition, you can find a source daemon accompanying the launchd source code (available from\r\nhttp://www.macosforge.org/). This daemon is also provided from the Mac Developer Library as the SampleD sample\r\ncode project.\r\nThe Daemons and Agents technical note provides additional information about how launchd daemons and agents\r\nwork under the hood.\r\nFinally, many Apple-provided daemons support launchd . Their property list files can be found in\r\n/System/Library/LaunchDaemons . Some of these daemons are also available as open source from\r\nhttp://www.opensource.apple.com/ or http://www.macosforge.org/.\r\nSource: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nhttps://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html\r\nPage 20 of 20",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html"
	],
	"report_names": [
		"CreatingLaunchdJobs.html"
	],
	"threat_actors": [
		{
			"id": "eb3f4e4d-2573-494d-9739-1be5141cf7b2",
			"created_at": "2022-10-25T16:07:24.471018Z",
			"updated_at": "2026-04-10T02:00:05.002374Z",
			"deleted_at": null,
			"main_name": "Cron",
			"aliases": [],
			"source_name": "ETDA:Cron",
			"tools": [
				"Catelites",
				"Catelites Bot",
				"CronBot",
				"TinyZBot"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "2864e40a-f233-4618-ac61-b03760a41cbb",
			"created_at": "2023-12-01T02:02:34.272108Z",
			"updated_at": "2026-04-10T02:00:04.97558Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "ETDA:WildCard",
			"tools": [
				"RustDown",
				"SysJoker"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "256a6a2d-e8a2-4497-b399-628a7fad4b3e",
			"created_at": "2023-11-30T02:00:07.299845Z",
			"updated_at": "2026-04-10T02:00:03.484788Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "MISPGALAXY:WildCard",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775439156,
	"ts_updated_at": 1775792121,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/148c0beef8aa8534cbbe73efcfea68414b2ffc67.pdf",
		"text": "https://archive.orkl.eu/148c0beef8aa8534cbbe73efcfea68414b2ffc67.txt",
		"img": "https://archive.orkl.eu/148c0beef8aa8534cbbe73efcfea68414b2ffc67.jpg"
	}
}