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