1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/mac/launchd.h"
6
7 #include "base/logging.h"
8 #include "base/mac/scoped_launch_data.h"
9
10 // This file is written in terms of launch_data_t, which is deprecated but has
11 // no replacement. Ignore the deprecation warnings for now.
12 #pragma clang diagnostic push
13 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
14
15 namespace base {
16 namespace mac {
17
18 // MessageForJob sends a single message to launchd with a simple dictionary
19 // mapping |operation| to |job_label|, and returns the result of calling
20 // launch_msg to send that message. On failure, returns NULL. The caller
21 // assumes ownership of the returned launch_data_t object.
MessageForJob(const std::string & job_label,const char * operation)22 launch_data_t MessageForJob(const std::string& job_label,
23 const char* operation) {
24 // launch_data_alloc returns something that needs to be freed.
25 ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY));
26 if (!message.is_valid()) {
27 LOG(ERROR) << "launch_data_alloc";
28 return NULL;
29 }
30
31 // launch_data_new_string returns something that needs to be freed, but
32 // the dictionary will assume ownership when launch_data_dict_insert is
33 // called, so put it in a scoper and .release() it when given to the
34 // dictionary.
35 ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str()));
36 if (!job_label_launchd.is_valid()) {
37 LOG(ERROR) << "launch_data_new_string";
38 return NULL;
39 }
40
41 if (!launch_data_dict_insert(message.get(), job_label_launchd.release(),
42 operation)) {
43 return NULL;
44 }
45
46 return launch_msg(message.get());
47 }
48
PIDForJob(const std::string & job_label)49 pid_t PIDForJob(const std::string& job_label) {
50 ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB));
51 if (!response.is_valid()) {
52 return -1;
53 }
54
55 launch_data_type_t response_type = launch_data_get_type(response.get());
56 if (response_type != LAUNCH_DATA_DICTIONARY) {
57 if (response_type == LAUNCH_DATA_ERRNO) {
58 LOG(ERROR) << "PIDForJob: error "
59 << launch_data_get_errno(response.get());
60 } else {
61 LOG(ERROR) << "PIDForJob: expected dictionary, got " << response_type;
62 }
63 return -1;
64 }
65
66 launch_data_t pid_data =
67 launch_data_dict_lookup(response.get(), LAUNCH_JOBKEY_PID);
68 if (!pid_data)
69 return 0;
70
71 if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) {
72 LOG(ERROR) << "PIDForJob: expected integer";
73 return -1;
74 }
75
76 return launch_data_get_integer(pid_data);
77 }
78
79 } // namespace mac
80 } // namespace base
81
82 #pragma clang diagnostic pop
83