1 //===-- RNBServices.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Christopher Friesen on 3/21/08.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #import "RNBServices.h"
15 
16 #import <CoreFoundation/CoreFoundation.h>
17 #include <libproc.h>
18 #import <unistd.h>
19 #include <sys/sysctl.h>
20 #include "CFString.h"
21 #include <vector>
22 #import "DNBLog.h"
23 #include "MacOSX/CFUtils.h"
24 
25 #ifdef WITH_SPRINGBOARD
26 #import <SpringBoardServices/SpringBoardServices.h>
27 #endif
28 
29 // From DNB.cpp
30 size_t GetAllInfos (std::vector<struct kinfo_proc>& proc_infos);
31 
32 int
GetPrcoesses(CFMutableArrayRef plistMutableArray,bool all_users)33 GetPrcoesses (CFMutableArrayRef plistMutableArray, bool all_users)
34 {
35     if (plistMutableArray == NULL)
36         return -1;
37 
38     // Running as root, get all processes
39     std::vector<struct kinfo_proc> proc_infos;
40     const size_t num_proc_infos = GetAllInfos(proc_infos);
41     if (num_proc_infos > 0)
42     {
43         const pid_t our_pid = getpid();
44         const uid_t our_uid = getuid();
45         uint32_t i;
46         CFAllocatorRef alloc = kCFAllocatorDefault;
47 
48         for (i=0; i<num_proc_infos; i++)
49         {
50             struct kinfo_proc &proc_info = proc_infos[i];
51 
52             bool kinfo_user_matches;
53             // Special case, if lldb is being run as root we can attach to anything.
54             if (all_users)
55                 kinfo_user_matches = true;
56             else
57                 kinfo_user_matches = proc_info.kp_eproc.e_pcred.p_ruid == our_uid;
58 
59 
60             const pid_t pid = proc_info.kp_proc.p_pid;
61             // Skip zombie processes and processes with unset status
62             if (kinfo_user_matches == false             || // User is acceptable
63                 pid == our_pid                          || // Skip this process
64                 pid == 0                                || // Skip kernel (kernel pid is zero)
65                 proc_info.kp_proc.p_stat == SZOMB       || // Zombies are bad, they like brains...
66                 proc_info.kp_proc.p_flag & P_TRACED     || // Being debugged?
67                 proc_info.kp_proc.p_flag & P_WEXIT      || // Working on exiting?
68                 proc_info.kp_proc.p_flag & P_TRANSLATED)   // Skip translated ppc (Rosetta)
69                 continue;
70 
71             // Create a new mutable dictionary for each application
72             CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
73 
74             // Get the process id for the app (if there is one)
75             const int32_t pid_int32 = pid;
76             CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc,  kCFNumberSInt32Type, &pid_int32));
77             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get());
78 
79             // Set the a boolean to indicate if this is the front most
80             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse);
81 
82             const char *pid_basename = proc_info.kp_proc.p_comm;
83             char proc_path_buf[PATH_MAX];
84 
85             int return_val = proc_pidpath (pid, proc_path_buf, PATH_MAX);
86             if (return_val > 0)
87             {
88                 // Okay, now search backwards from that to see if there is a
89                 // slash in the name.  Note, even though we got all the args we don't care
90                 // because the list data is just a bunch of concatenated null terminated strings
91                 // so strrchr will start from the end of argv0.
92 
93                 pid_basename = strrchr(proc_path_buf, '/');
94                 if (pid_basename)
95                 {
96                     // Skip the '/'
97                     ++pid_basename;
98                 }
99                 else
100                 {
101                     // We didn't find a directory delimiter in the process argv[0], just use what was in there
102                     pid_basename = proc_path_buf;
103                 }
104                 CFString cf_pid_path (proc_path_buf);
105                 if (cf_pid_path.get())
106                     ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, cf_pid_path.get());
107             }
108 
109             if (pid_basename && pid_basename[0])
110             {
111                 CFString pid_name (pid_basename);
112                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, pid_name.get());
113             }
114 
115             // Append the application info to the plist array
116             ::CFArrayAppendValue (plistMutableArray, appInfoDict.get());
117         }
118     }
119     return 0;
120 }
121 int
ListApplications(std::string & plist,bool opt_runningApps,bool opt_debuggable)122 ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable)
123 {
124     int result = -1;
125 
126     CFAllocatorRef alloc = kCFAllocatorDefault;
127 
128     // Create a mutable array that we can populate. Specify zero so it can be of any size.
129     CFReleaser<CFMutableArrayRef> plistMutableArray (::CFArrayCreateMutable (alloc, 0, &kCFTypeArrayCallBacks));
130 
131     const uid_t our_uid = getuid();
132 
133 #ifdef WITH_SPRINGBOARD
134 
135 
136     if (our_uid == 0)
137     {
138         bool all_users = true;
139         result = GetPrcoesses (plistMutableArray.get(), all_users);
140     }
141     else
142     {
143         CFReleaser<CFStringRef> sbsFrontAppID (::SBSCopyFrontmostApplicationDisplayIdentifier ());
144         CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
145 
146         // Need to check the return value from SBSCopyApplicationDisplayIdentifiers.
147         CFIndex count = sbsAppIDs.get() ? ::CFArrayGetCount (sbsAppIDs.get()) : 0;
148         CFIndex i = 0;
149         for (i = 0; i < count; i++)
150         {
151             CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
152 
153             // Create a new mutable dictionary for each application
154             CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
155 
156             // Get the process id for the app (if there is one)
157             pid_t pid = INVALID_NUB_PROCESS;
158             if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &pid) == true)
159             {
160                 CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc,  kCFNumberSInt32Type, &pid));
161                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get());
162             }
163 
164             // Set the a boolean to indicate if this is the front most
165             if (sbsFrontAppID.get() && displayIdentifier && (::CFStringCompare (sbsFrontAppID.get(), displayIdentifier, 0) == kCFCompareEqualTo))
166                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanTrue);
167             else
168                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse);
169 
170 
171             CFReleaser<CFStringRef> executablePath (::SBSCopyExecutablePathForDisplayIdentifier (displayIdentifier));
172             if (executablePath.get() != NULL)
173             {
174                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, executablePath.get());
175             }
176 
177             CFReleaser<CFStringRef> iconImagePath (::SBSCopyIconImagePathForDisplayIdentifier (displayIdentifier)) ;
178             if (iconImagePath.get() != NULL)
179             {
180                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, iconImagePath.get());
181             }
182 
183             CFReleaser<CFStringRef> localizedDisplayName (::SBSCopyLocalizedApplicationNameForDisplayIdentifier (displayIdentifier));
184             if (localizedDisplayName.get() != NULL)
185             {
186                 ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, localizedDisplayName.get());
187             }
188 
189             // Append the application info to the plist array
190             ::CFArrayAppendValue (plistMutableArray.get(), appInfoDict.get());
191         }
192     }
193 #else
194     // When root, show all processes
195     bool all_users = (our_uid == 0);
196     result = GetPrcoesses (plistMutableArray.get(), all_users);
197 #endif
198 
199     CFReleaser<CFDataRef> plistData (::CFPropertyListCreateXMLData (alloc, plistMutableArray.get()));
200 
201     // write plist to service port
202     if (plistData.get() != NULL)
203     {
204         CFIndex size = ::CFDataGetLength (plistData.get());
205         const UInt8 *bytes = ::CFDataGetBytePtr (plistData.get());
206         if (bytes != NULL && size > 0)
207         {
208             plist.assign((char *)bytes, size);
209             return 0;   // Success
210         }
211         else
212         {
213             DNBLogError("empty application property list.");
214             result = -2;
215         }
216     }
217     else
218     {
219         DNBLogError("serializing task list.");
220         result = -3;
221     }
222 
223     return result;
224 
225 }
226 
227 
228 bool
IsSBProcess(nub_process_t pid)229 IsSBProcess (nub_process_t pid)
230 {
231 #ifdef WITH_SPRINGBOARD
232     CFReleaser<CFArrayRef> appIdsForPID (::SBSCopyDisplayIdentifiersForProcessID(pid));
233     return appIdsForPID.get() != NULL;
234 #else
235     return false;
236 #endif
237 }
238 
239