Can a launchd job get any access to its invoking plist?
Greetings. Can a launchd job get any access to its invoking plist? I'm writing a small application intended to be invoked, almost exclusively, from launchd. Its interface would be simpler if it could read the contents of the dictionary/plist which controls the job which launchd starts. It could potentially be invoked by more than one plist, and I'd like to preserve state keyed on (say) the job Label; it's invoked based on the WatchPaths element, and if it could see that key in the dictionary, then these paths wouldn't have to be duplicated in the ProgramArguments. I can work round the problem, but it feels like I'm missing a trick. Is there any way to get access to this dictionary; or (since I know about SMJobCopyDictionary) is there any way to get access to the job's Label? The existence of SMJobCopyDictionary indicates that this information is available in principle. I can't think of anything to google that gives me more than tutorials on using launchd. I've tried asking on StackOverflow <http://stackoverflow.com/questions/20338636/>, but without success (the answer there is sensible, but somewhat tangential to the question). Thanks for any pointers. Best wishes, Norman -- Norman Gray : http://nxg.me.uk SUPA School of Physics and Astronomy, University of Glasgow, UK
Why not just set a relevant environment variable or pass an argument that's different in each plist? -- Damien Sorresso dsorresso@apple.com On 4 Dec, 2013, at 9:03, Norman Gray <norman@astro.gla.ac.uk> wrote:
Greetings.
Can a launchd job get any access to its invoking plist?
I'm writing a small application intended to be invoked, almost exclusively, from launchd. Its interface would be simpler if it could read the contents of the dictionary/plist which controls the job which launchd starts. It could potentially be invoked by more than one plist, and I'd like to preserve state keyed on (say) the job Label; it's invoked based on the WatchPaths element, and if it could see that key in the dictionary, then these paths wouldn't have to be duplicated in the ProgramArguments. I can work round the problem, but it feels like I'm missing a trick.
Is there any way to get access to this dictionary; or (since I know about SMJobCopyDictionary) is there any way to get access to the job's Label? The existence of SMJobCopyDictionary indicates that this information is available in principle.
I can't think of anything to google that gives me more than tutorials on using launchd.
I've tried asking on StackOverflow <http://stackoverflow.com/questions/20338636/>, but without success (the answer there is sensible, but somewhat tangential to the question).
Thanks for any pointers.
Best wishes,
Norman
-- Norman Gray : http://nxg.me.uk SUPA School of Physics and Astronomy, University of Glasgow, UK
_______________________________________________ launchd-dev mailing list launchd-dev@lists.macosforge.org https://lists.macosforge.org/mailman/listinfo/launchd-dev
On 2013 Dec 04, at 11:22, Damien Sorresso <dsorresso@apple.com> wrote:
Why not just set a relevant environment variable or pass an argument that's different in each plist?
I’ve done that, Damien, but like Norman I have wondered why the job’s parameters are not more readily available. From a shell, you can run launchctl with the subcommand info, and pass the job’s label. It gives you most of the plist, but not all. WatchPath is one key I recall which is not included. And, sadly, I don’t think there is any C API equivalent of launchctl.
On 4 Dec, 2013, at 12:05, Jerry Krinock <jerry@ieee.org> wrote:
On 2013 Dec 04, at 11:22, Damien Sorresso <dsorresso@apple.com> wrote:
Why not just set a relevant environment variable or pass an argument that's different in each plist?
I’ve done that, Damien, but like Norman I have wondered why the job’s parameters are not more readily available.
Because the launchd.plist is not a preferences container. It's not meant to be a state store.
From a shell, you can run launchctl with the subcommand info, and pass the job’s label.
Yes, but that is only meant for informational purposes; programs should not be making decisions based on that output, and that output is not (and never will be) reflective of the complete contents of the launchd.plist. If you need to modify your program's behavior, you should specify different arguments or a different environment in the plist. That is what those entries are for. -- Damien Sorresso dsorresso@apple.com
It gives you most of the plist, but not all. WatchPath is one key I recall which is not included. And, sadly, I don’t think there is any C API equivalent of launchctl.
Damien (and Jerry), hello. On 2013 Dec 4, at 20:10, Damien Sorresso <dsorresso@apple.com> wrote:
On 4 Dec, 2013, at 12:05, Jerry Krinock <jerry@ieee.org> wrote:
On 2013 Dec 04, at 11:22, Damien Sorresso <dsorresso@apple.com> wrote:
Why not just set a relevant environment variable or pass an argument that's different in each plist?
I’ve done that, Damien, but like Norman I have wondered why the job’s parameters are not more readily available.
Because the launchd.plist is not a preferences container. It's not meant to be a state store.
Sure, and I'm storing the actual state in preferences, using NSUserDefaults. All I really want to know is "Have I been invoked from A.plist or B.plist?" I've tried setting an environment variable, and passing an --ident option to the program. That does work, but in each case it involves copying the Label from one part of the plist to another: that looks ugly, is redundant, and requires extra documentation ("Copy the Label to the --ident option; don't ask why..."). I've even resorted to concatenating various arguments and options, and using that as the 'identifier', but that ends up looking needlessly obscure. In fact, if I could read the Label and (in my case) the WatchPaths from the calling environment, then several of my program options would disappear. So I'm not thinking of the job parameters as _state_, quite, but as part of the program launch environment. Rather than (argc, argv, environ), it's effectively (argc, argv, environ, plist). That's not traditional unix, of course, but then launchd isn't traditional unix either.
If you need to modify your program's behavior, you should specify different arguments or a different environment in the plist. That is what those entries are for.
Indeed, but in this case the information being communicated is information about the plist itself, which seems... clumsy. That in turn makes me suspect I'm doing something the Hard Way. @Graham: thanks. launch_data_dict_lookup looks like it would do the job, and demonstrates that Apple feel that the information is legitimately available in at least some circumstances. But the fact that it's not documented _anywhere_ I can find (other than being implicitly documented as part of Apple example code), makes me nervous of using it. All the best, Norman -- Norman Gray : http://nxg.me.uk SUPA School of Physics and Astronomy, University of Glasgow, UK
On 4 Dec, 2013, at 12:58, Norman Gray <norman@astro.gla.ac.uk> wrote:
Damien (and Jerry), hello.
On 2013 Dec 4, at 20:10, Damien Sorresso <dsorresso@apple.com> wrote:
On 4 Dec, 2013, at 12:05, Jerry Krinock <jerry@ieee.org> wrote:
On 2013 Dec 04, at 11:22, Damien Sorresso <dsorresso@apple.com> wrote:
Why not just set a relevant environment variable or pass an argument that's different in each plist?
I’ve done that, Damien, but like Norman I have wondered why the job’s parameters are not more readily available.
Because the launchd.plist is not a preferences container. It's not meant to be a state store.
Sure, and I'm storing the actual state in preferences, using NSUserDefaults. All I really want to know is "Have I been invoked from A.plist or B.plist?"
I've tried setting an environment variable, and passing an --ident option to the program. That does work, but in each case it involves copying the Label from one part of the plist to another: that looks ugly, is redundant, and requires extra documentation ("Copy the Label to the --ident option; don't ask why...").
I've even resorted to concatenating various arguments and options, and using that as the 'identifier', but that ends up looking needlessly obscure. In fact, if I could read the Label and (in my case) the WatchPaths from the calling environment, then several of my program options would disappear.
So I'm not thinking of the job parameters as _state_, quite, but as part of the program launch environment. Rather than (argc, argv, environ), it's effectively (argc, argv, environ, plist). That's not traditional unix, of course, but then launchd isn't traditional unix either.
It seems like you're basing a ton of behaviors simply on the job's label. Why do they have to be based on that? That said, I think it's reasonable to export the job's label in an environment variable or something. But plist is not there as part of the program's environment. It *defines* the program's environment. Also, I can see how WatchPaths are clumsy in this case, but then again, the entire mechanism of WatchPaths is clumsy. You're virtually guaranteed to miss modifications a certain amount of the time, and you have no guarantee that the write which triggered the modification event left the file in a consistent state anyway.
If you need to modify your program's behavior, you should specify different arguments or a different environment in the plist. That is what those entries are for.
Indeed, but in this case the information being communicated is information about the plist itself, which seems... clumsy. That in turn makes me suspect I'm doing something the Hard Way.
@Graham: thanks. launch_data_dict_lookup looks like it would do the job, and demonstrates that Apple feel that the information is legitimately available in at least some circumstances. But the fact that it's not documented _anywhere_ I can find (other than being implicitly documented as part of Apple example code), makes me nervous of using it.
All the best,
Those interfaces are really only so that jobs can check in with launchd to obtain listening sockets. They were way too general at the outset. -- Damien Sorresso dsorresso@apple.com
Damien, hello. Thanks for your thoughtful remarks here. On 2013 Dec 4, at 21:51, Damien Sorresso <dsorresso@apple.com> wrote:
@Graham: thanks. launch_data_dict_lookup looks like it would do the job, and demonstrates that Apple feel that the information is legitimately available in at least some circumstances. But the fact that it's not documented _anywhere_ I can find (other than being implicitly documented as part of Apple example code), makes me nervous of using it.
All the best,
Those interfaces are really only so that jobs can check in with launchd to obtain listening sockets. They were way too general at the outset.
Righto. I'll take that as a clear indication that I should avoid the launch_data_dict_lookup API. Or were you referring to the ServiceManagement.h API as well? [The following is thinking aloud; feel free, all, to ignore me] Thinking of the broader question....
On 4 Dec, 2013, at 12:58, Norman Gray <norman@astro.gla.ac.uk> wrote:
[...]
Sure, and I'm storing the actual state in preferences, using NSUserDefaults. All I really want to know is "Have I been invoked from A.plist or B.plist?"
[...] So I'm not thinking of the job parameters as _state_, quite, but as part of the program launch environment. Rather than (argc, argv, environ), it's effectively (argc, argv, environ, plist). That's not traditional unix, of course, but then launchd isn't traditional unix either.
It seems like you're basing a ton of behaviors simply on the job's label.
Well, not really. The program can be invoked in a couple of different contexts, and it wants to respect that, and behave slightly differently in those two contexts, in ways which are related to its own internal bookkeeping, and nothing that the author of the plist should have to care about. The only real difference between those two contexts is that they're different plists, and it seems slightly perverse that in order to find that out, I've got to 'fake' it by copying (or requiring the plist's author to copy) the Label or some other unique identifier into an EnvironmentVariables entry.
Why do they have to be based on that? That said, I think it's reasonable to export the job's label in an environment variable or something. But plist is not there as part of the program's environment. It *defines* the program's environment.
Yeeeees, but I'm not sure this distinction makes much difference. The more I think about this, the _less_ I feel able to identify a secure distinction between the program's environment as a char**, and the plist dictionary which, as you say, defines that environment. The best I can do is say that certain elements within the launchd.plist dictionary are describing the actions which launchd is to take, and that these are formally distinct from the environment that launchd subsequently constructs for the program. I could potentially -- just -- see why it might be desirable for a program to be kept ignorant of this information (*mumble*... security/privacy... *mumble*), but since the above APIs exist, that's clearly not the case in fact, and this smells of post hoc rationalisation on my part. Another possibility is that the structure of the launchd.plist dictionary isn't necessarily stable long-term, so a program can't rely on it. True: but that doesn't matter, since programs already have cope with the fact that the content of the char** environment isn't completely guaranteed either. So I'm left without identifiable clear blue water between the char** environment and the broader plist environment, other than that the char** environment is The Unix Way. I'm a sturdy defender of The Unix Way, but since the very existence of launchd is a smack in the face of The Unix Way (garhhhh... cron, at and batch were good enough for me when I were a young 'un), why stop here? Indeed, if there were (say) a <key>CFEnvironment</key> within the plist, that could take as value any plist type and which could be easily retrieved within the job, that would potentially provide a much more natural way of providing ready-Cocoad-up context to sit along side the char* -> char* dictionary of the unix environment. The overview of the Service Management framework says that it "...provides support for loading and unloading launchd jobs and reading and manipulating job dictionaries from within an application." That seems an eminently sensible goal and, based on the second half of that sentence, the fact that there isn't a function SMJobGetLabel(void), for example, looks like an omission rather than a design decision. That's probably enough of that! Best wishes, Norman -- Norman Gray : http://nxg.me.uk SUPA School of Physics and Astronomy, University of Glasgow, UK
Hey Norman: I was struggling with that sample code last week. I found similar code and a better explanation in Amit Singh's book, Mac OS X Internals: A Systems Approach. /Mick On Dec 4, 2013, at 12:58 PM, Norman Gray wrote:
@Graham: thanks. launch_data_dict_lookup looks like it would do the job, and demonstrates that Apple feel that the information is legitimately available in at least some circumstances. But the fact that it's not documented _anywhere_ I can find (other than being implicitly documented as part of Apple example code), makes me nervous of using it.
On 2013 Dec 4, at 17:03, Norman Gray <norman@astro.gla.ac.uk> wrote:
Can a launchd job get any access to its invoking plist?
(I realise I should have followed this up with the list) This appears to be broadly possible in fact, but the interface discussed (and described in Apple's SampleD sample code) is apparently documented nowhere other than in this sample code, and also possibly in Mac OS X Internals: A Systems Approach (Amit Singh, http://osxbook.com, thanks to Mitchell J Laurren-Ring for pointing this out). Also, it is actually catering to, and specific to, the case where an application wants to check in to get access to a launchd-created socket, so (on further investigation) it doesn't actually work in the case I'm interested in. Put together, I'm left with the feeling that, while the behaviour I want seems possible, and while I think it's neater in this case than passing more state in environment variables, the API to support such behaviour is, if not deprecated, than at least somewhat discouraged, and at any rate not idiomatic. For completeness, I've created an enhancement request (15720781) for something like this to be supported, with a pointer back to the discussion here (who knows, I speculate this may even find its way back to you, Damien!). Thanks to all for your suggestions. All the best, Norman -- Norman Gray : http://nxg.me.uk SUPA School of Physics and Astronomy, University of Glasgow, UK
participants (4)
-
Damien Sorresso
-
Jerry Krinock
-
Mitchell J Laurren-Ring
-
Norman Gray