1/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18 * IN THE SOFTWARE.
19 */
20
21#include "uv.h"
22#include "internal.h"
23
24#include <dlfcn.h>
25#include <errno.h>
26#include <pthread.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include <TargetConditionals.h>
31
32#if !TARGET_OS_IPHONE
33#include "darwin-stub.h"
34#endif
35
36
37static int uv__pthread_setname_np(const char* name) {
38  char namebuf[64];  /* MAXTHREADNAMESIZE */
39  int err;
40
41  strncpy(namebuf, name, sizeof(namebuf) - 1);
42  namebuf[sizeof(namebuf) - 1] = '\0';
43
44  err = pthread_setname_np(namebuf);
45  if (err)
46    return UV__ERR(err);
47
48  return 0;
49}
50
51
52int uv__set_process_title(const char* title) {
53#if TARGET_OS_IPHONE
54  return uv__pthread_setname_np(title);
55#else
56  CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
57                                            const char*,
58                                            CFStringEncoding);
59  CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
60  void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
61  void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
62  CFTypeRef (*pLSGetCurrentApplicationASN)(void);
63  OSStatus (*pLSSetApplicationInformationItem)(int,
64                                               CFTypeRef,
65                                               CFStringRef,
66                                               CFStringRef,
67                                               CFDictionaryRef*);
68  void* application_services_handle;
69  void* core_foundation_handle;
70  CFBundleRef launch_services_bundle;
71  CFStringRef* display_name_key;
72  CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
73  CFBundleRef (*pCFBundleGetMainBundle)(void);
74  CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
75  void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
76                                                                void*);
77  CFTypeRef asn;
78  int err;
79
80  err = UV_ENOENT;
81  application_services_handle = dlopen("/System/Library/Frameworks/"
82                                       "ApplicationServices.framework/"
83                                       "Versions/A/ApplicationServices",
84                                       RTLD_LAZY | RTLD_LOCAL);
85  core_foundation_handle = dlopen("/System/Library/Frameworks/"
86                                  "CoreFoundation.framework/"
87                                  "Versions/A/CoreFoundation",
88                                  RTLD_LAZY | RTLD_LOCAL);
89
90  if (application_services_handle == NULL || core_foundation_handle == NULL)
91    goto out;
92
93  *(void **)(&pCFStringCreateWithCString) =
94      dlsym(core_foundation_handle, "CFStringCreateWithCString");
95  *(void **)(&pCFBundleGetBundleWithIdentifier) =
96      dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
97  *(void **)(&pCFBundleGetDataPointerForName) =
98      dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
99  *(void **)(&pCFBundleGetFunctionPointerForName) =
100      dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
101
102  if (pCFStringCreateWithCString == NULL ||
103      pCFBundleGetBundleWithIdentifier == NULL ||
104      pCFBundleGetDataPointerForName == NULL ||
105      pCFBundleGetFunctionPointerForName == NULL) {
106    goto out;
107  }
108
109#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
110
111  launch_services_bundle =
112      pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
113
114  if (launch_services_bundle == NULL)
115    goto out;
116
117  *(void **)(&pLSGetCurrentApplicationASN) =
118      pCFBundleGetFunctionPointerForName(launch_services_bundle,
119                                         S("_LSGetCurrentApplicationASN"));
120
121  if (pLSGetCurrentApplicationASN == NULL)
122    goto out;
123
124  *(void **)(&pLSSetApplicationInformationItem) =
125      pCFBundleGetFunctionPointerForName(launch_services_bundle,
126                                         S("_LSSetApplicationInformationItem"));
127
128  if (pLSSetApplicationInformationItem == NULL)
129    goto out;
130
131  display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
132                                                    S("_kLSDisplayNameKey"));
133
134  if (display_name_key == NULL || *display_name_key == NULL)
135    goto out;
136
137  *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
138                                     "CFBundleGetInfoDictionary");
139  *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
140                                 "CFBundleGetMainBundle");
141  if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
142    goto out;
143
144  *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
145      launch_services_bundle,
146      S("_LSApplicationCheckIn"));
147
148  if (pLSApplicationCheckIn == NULL)
149    goto out;
150
151  *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
152      pCFBundleGetFunctionPointerForName(
153          launch_services_bundle,
154          S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
155
156  if (pLSSetApplicationLaunchServicesServerConnectionStatus == NULL)
157    goto out;
158
159  pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
160
161  /* Check into process manager?! */
162  pLSApplicationCheckIn(-2,
163                        pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
164
165  asn = pLSGetCurrentApplicationASN();
166
167  err = UV_EBUSY;
168  if (asn == NULL)
169    goto out;
170
171  err = UV_EINVAL;
172  if (pLSSetApplicationInformationItem(-2,  /* Magic value. */
173                                       asn,
174                                       *display_name_key,
175                                       S(title),
176                                       NULL) != noErr) {
177    goto out;
178  }
179
180  uv__pthread_setname_np(title);  /* Don't care if it fails. */
181  err = 0;
182
183out:
184  if (core_foundation_handle != NULL)
185    dlclose(core_foundation_handle);
186
187  if (application_services_handle != NULL)
188    dlclose(application_services_handle);
189
190  return err;
191#endif  /* !TARGET_OS_IPHONE */
192}
193