brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · bb57fb5 Raw
232 lines · cpp
1//===-- RNBServices.cpp -----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  Created by Christopher Friesen on 3/21/08.10//11//===----------------------------------------------------------------------===//12 13#include "RNBServices.h"14 15#include "DNB.h"16#include "CFString.h"17#include "DNBLog.h"18#include "MacOSX/CFUtils.h"19#include <CoreFoundation/CoreFoundation.h>20#include <libproc.h>21#include <sys/sysctl.h>22#include <unistd.h>23#include <vector>24 25// For now only SpringBoard has a notion of "Applications" that it can list for26// us.27// So we have to use the SpringBoard API's here.28#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS)29#include <SpringBoardServices/SpringBoardServices.h>30#endif31 32int GetProcesses(CFMutableArrayRef plistMutableArray, bool all_users) {33  if (plistMutableArray == NULL)34    return -1;35 36  // Running as root, get all processes37  std::vector<struct kinfo_proc> proc_infos;38  const size_t num_proc_infos = DNBGetAllInfos(proc_infos);39  if (num_proc_infos > 0) {40    const pid_t our_pid = getpid();41    const uid_t our_uid = getuid();42    uint32_t i;43    CFAllocatorRef alloc = kCFAllocatorDefault;44 45    for (i = 0; i < num_proc_infos; i++) {46      struct kinfo_proc &proc_info = proc_infos[i];47 48      bool kinfo_user_matches;49      // Special case, if lldb is being run as root we can attach to anything.50      if (all_users)51        kinfo_user_matches = true;52      else53        kinfo_user_matches = proc_info.kp_eproc.e_pcred.p_ruid == our_uid;54 55      const pid_t pid = proc_info.kp_proc.p_pid;56      // Skip zombie processes and processes with unset status57      if (!kinfo_user_matches || // User is acceptable58          pid == our_pid ||      // Skip this process59          pid == 0 ||            // Skip kernel (kernel pid is zero)60          proc_info.kp_proc.p_stat ==61              SZOMB || // Zombies are bad, they like brains...62          proc_info.kp_proc.p_flag & P_TRACED || // Being debugged?63          proc_info.kp_proc.p_flag & P_WEXIT     // Working on exiting?64      )65        continue;66 67      // Create a new mutable dictionary for each application68      CFReleaser<CFMutableDictionaryRef> appInfoDict(69          ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks,70                                      &kCFTypeDictionaryValueCallBacks));71 72      // Get the process id for the app (if there is one)73      const int32_t pid_int32 = pid;74      CFReleaser<CFNumberRef> pidCFNumber(75          ::CFNumberCreate(alloc, kCFNumberSInt32Type, &pid_int32));76      ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PID_KEY,77                             pidCFNumber.get());78 79      // Set a boolean to indicate if this is the front most80      ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY,81                             kCFBooleanFalse);82 83      const char *pid_basename = proc_info.kp_proc.p_comm;84      char proc_path_buf[PATH_MAX];85 86      int return_val = proc_pidpath(pid, proc_path_buf, PATH_MAX);87      if (return_val > 0) {88        // Okay, now search backwards from that to see if there is a89        // slash in the name.  Note, even though we got all the args we don't90        // care91        // because the list data is just a bunch of concatenated null terminated92        // strings93        // so strrchr will start from the end of argv0.94 95        pid_basename = strrchr(proc_path_buf, '/');96        if (pid_basename) {97          // Skip the '/'98          ++pid_basename;99        } else {100          // We didn't find a directory delimiter in the process argv[0], just101          // use what was in there102          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,107                                 cf_pid_path.get());108      }109 110      if (pid_basename && pid_basename[0]) {111        CFString pid_name(pid_basename);112        ::CFDictionarySetValue(appInfoDict.get(),113                               DTSERVICES_APP_DISPLAY_NAME_KEY, pid_name.get());114      }115 116      // Append the application info to the plist array117      ::CFArrayAppendValue(plistMutableArray, appInfoDict.get());118    }119  }120  return 0;121}122int ListApplications(std::string &plist, bool opt_runningApps,123                     bool opt_debuggable) {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 of129  // any size.130  CFReleaser<CFMutableArrayRef> plistMutableArray(131      ::CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks));132 133  const uid_t our_uid = getuid();134 135#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS)136 137  if (our_uid == 0) {138    bool all_users = true;139    result = GetProcesses(plistMutableArray.get(), all_users);140  } else {141    CFReleaser<CFStringRef> sbsFrontAppID(142        ::SBSCopyFrontmostApplicationDisplayIdentifier());143    CFReleaser<CFArrayRef> sbsAppIDs(::SBSCopyApplicationDisplayIdentifiers(144        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      CFStringRef displayIdentifier =151          (CFStringRef)::CFArrayGetValueAtIndex(sbsAppIDs.get(), i);152 153      // Create a new mutable dictionary for each application154      CFReleaser<CFMutableDictionaryRef> appInfoDict(155          ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks,156                                      &kCFTypeDictionaryValueCallBacks));157 158      // Get the process id for the app (if there is one)159      pid_t pid = INVALID_NUB_PROCESS;160      if (::SBSProcessIDForDisplayIdentifier((CFStringRef)displayIdentifier,161                                             &pid) == true) {162        CFReleaser<CFNumberRef> pidCFNumber(163            ::CFNumberCreate(alloc, kCFNumberSInt32Type, &pid));164        ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PID_KEY,165                               pidCFNumber.get());166      }167 168      // Set a boolean to indicate if this is the front most169      if (sbsFrontAppID.get() && displayIdentifier &&170          (::CFStringCompare(sbsFrontAppID.get(), displayIdentifier, 0) ==171           kCFCompareEqualTo))172        ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY,173                               kCFBooleanTrue);174      else175        ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY,176                               kCFBooleanFalse);177 178      CFReleaser<CFStringRef> executablePath(179          ::SBSCopyExecutablePathForDisplayIdentifier(displayIdentifier));180      if (executablePath.get() != NULL) {181        ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PATH_KEY,182                               executablePath.get());183      }184 185      CFReleaser<CFStringRef> iconImagePath(186          ::SBSCopyIconImagePathForDisplayIdentifier(displayIdentifier));187      if (iconImagePath.get() != NULL) {188        ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY,189                               iconImagePath.get());190      }191 192      CFReleaser<CFStringRef> localizedDisplayName(193          ::SBSCopyLocalizedApplicationNameForDisplayIdentifier(194              displayIdentifier));195      if (localizedDisplayName.get() != NULL) {196        ::CFDictionarySetValue(appInfoDict.get(),197                               DTSERVICES_APP_DISPLAY_NAME_KEY,198                               localizedDisplayName.get());199      }200 201      // Append the application info to the plist array202      ::CFArrayAppendValue(plistMutableArray.get(), appInfoDict.get());203    }204  }205#else // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS)206  // When root, show all processes207  bool all_users = (our_uid == 0);208  GetProcesses(plistMutableArray.get(), all_users);209#endif210 211  CFReleaser<CFDataRef> plistData(::CFPropertyListCreateData(212      alloc, plistMutableArray.get(), kCFPropertyListXMLFormat_v1_0, 0, NULL));213 214  // write plist to service port215  if (plistData.get() != NULL) {216    CFIndex size = ::CFDataGetLength(plistData.get());217    const UInt8 *bytes = ::CFDataGetBytePtr(plistData.get());218    if (bytes != NULL && size > 0) {219      plist.assign((const char *)bytes, size);220      return 0; // Success221    } else {222      DNBLogError("empty application property list.");223      result = -2;224    }225  } else {226    DNBLogError("serializing task list.");227    result = -3;228  }229 230  return result;231}232