1/*
2 * Copyright (c) 2006, 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/cdefs.h>
25#include <unistd.h>
26#include <errno.h>
27#include <string.h>
28#include <strings.h>
29#include <sys/errno.h>
30#include <sys/msgbuf.h>
31#include <sys/resource.h>
32#include <sys/process_policy.h>
33#include <mach/message.h>
34
35#include "libproc_internal.h"
36
37int __proc_info(int callnum, int pid, int flavor, uint64_t arg, void * buffer, int buffersize);
38__private_extern__ int proc_setthreadname(void * buffer, int buffersize);
39int __process_policy(int scope, int action, int policy, int policy_subtype, proc_policy_attribute_t * attrp, pid_t target_pid, uint64_t target_threadid);
40int proc_rlimit_control(pid_t pid, int flavor, void *arg);
41
42int
43proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
44{
45	int retval;
46
47	if ((type >= PROC_ALL_PIDS) || (type <= PROC_PPID_ONLY)) {
48		if ((retval = __proc_info(PROC_INFO_CALL_LISTPIDS, type, typeinfo,(uint64_t)0, buffer, buffersize)) == -1)
49			return(0);
50	} else {
51		errno = EINVAL;
52		retval = 0;
53	}
54	return(retval);
55}
56
57
58int
59proc_listallpids(void * buffer, int buffersize)
60{
61	int numpids;
62	numpids = proc_listpids(PROC_ALL_PIDS, (uint32_t)0, buffer, buffersize);
63
64	if (numpids == -1)
65		return(-1);
66	else
67		return(numpids/sizeof(int));
68}
69
70int
71proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize)
72{
73	int numpids;
74	numpids = proc_listpids(PROC_PGRP_ONLY, (uint32_t)pgrpid, buffer, buffersize);
75	if (numpids == -1)
76		return(-1);
77	else
78		return(numpids/sizeof(int));
79}
80
81int
82proc_listchildpids(pid_t ppid, void * buffer, int buffersize)
83{
84	int numpids;
85	numpids = proc_listpids(PROC_PPID_ONLY, (uint32_t)ppid, buffer, buffersize);
86	if (numpids == -1)
87		return(-1);
88	else
89		return(numpids/sizeof(int));
90}
91
92
93int
94proc_pidinfo(int pid, int flavor, uint64_t arg,  void *buffer, int buffersize)
95{
96	int retval;
97
98	if ((retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor,  arg,  buffer, buffersize)) == -1)
99		return(0);
100
101	return(retval);
102}
103
104
105int
106proc_pidoriginatorinfo(int flavor, void *buffer, int buffersize)
107{
108	int retval;
109
110	if ((retval = __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO, getpid(), flavor,  0,  buffer, buffersize)) == -1)
111		return(0);
112
113	return(retval);
114}
115
116int
117proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer)
118{
119	return (__proc_info(PROC_INFO_CALL_PIDRUSAGE, pid, flavor, 0, buffer, 0));
120}
121
122int
123proc_setthread_cpupercent(uint8_t percentage, uint32_t ms_refill)
124{
125	uint32_t arg = 0;
126
127	/* Pack percentage and refill into a 32-bit number to match existing kernel implementation */
128	if ((percentage >= 100) || (ms_refill & ~0xffffffU)) {
129		errno = EINVAL;
130		return -1;
131	}
132
133	arg = ((ms_refill << 8) | percentage);
134
135	return (proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS, (void *)(uintptr_t)arg));
136}
137
138int
139proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)
140{
141	int retval;
142
143	if ((retval = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid,  flavor, (uint64_t)fd, buffer, buffersize)) == -1)
144		return(0);
145
146	return (retval);
147}
148
149
150int
151proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize)
152{
153	int retval;
154
155	if ((retval = __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO, pid, flavor, (uint64_t)fileport, buffer, buffersize)) == -1)
156		return (0);
157	return (retval);
158}
159
160
161int
162proc_name(int pid, void * buffer, uint32_t buffersize)
163{
164	int retval = 0, len;
165	struct proc_bsdinfo pbsd;
166
167
168	if (buffersize < sizeof(pbsd.pbi_name)) {
169		errno = ENOMEM;
170		return(0);
171	}
172
173	retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
174	if (retval != 0) {
175		if (pbsd.pbi_name[0]) {
176			bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
177		} else {
178			bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
179		}
180		len = (int)strlen(buffer);
181		return(len);
182	}
183	return(0);
184}
185
186int
187proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
188{
189	int retval = 0, len;
190	struct proc_regionwithpathinfo reginfo;
191
192	if (buffersize < MAXPATHLEN) {
193		errno = ENOMEM;
194		return(0);
195	}
196
197	retval = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, (uint64_t)address, &reginfo, sizeof(struct proc_regionwithpathinfo));
198	if (retval != -1) {
199		len = (int)strlen(&reginfo.prp_vip.vip_path[0]);
200		if (len != 0) {
201			if (len > MAXPATHLEN)
202				len = MAXPATHLEN;
203			bcopy(&reginfo.prp_vip.vip_path[0], buffer, len);
204			return(len);
205		}
206		return(0);
207	}
208	return(0);
209
210}
211
212int
213proc_kmsgbuf(void * buffer, uint32_t  buffersize)
214{
215	int retval;
216
217	if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0,  0, (uint64_t)0, buffer, buffersize)) == -1)
218		return(0);
219	return (retval);
220}
221
222int
223proc_pidpath(int pid, void * buffer, uint32_t  buffersize)
224{
225	int retval, len;
226
227	if (buffersize < PROC_PIDPATHINFO_SIZE) {
228		errno = ENOMEM;
229		return(0);
230	}
231	if (buffersize >  PROC_PIDPATHINFO_MAXSIZE) {
232		errno = EOVERFLOW;
233		return(0);
234	}
235
236	retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO,  (uint64_t)0,  buffer, buffersize);
237	if (retval != -1) {
238		len = (int)strlen(buffer);
239		return(len);
240	}
241	return (0);
242}
243
244
245int
246proc_libversion(int *major, int * minor)
247{
248
249	if (major != NULL)
250		*major = 1;
251	if (minor != NULL)
252		*minor = 1;
253	return(0);
254}
255
256int
257proc_setpcontrol(const int control)
258{
259	int retval ;
260
261	if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE)
262		return(EINVAL);
263
264	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1)
265		return(errno);
266
267	return(0);
268}
269
270
271__private_extern__ int
272proc_setthreadname(void * buffer, int buffersize)
273{
274	int retval;
275
276        retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
277
278	if (retval == -1)
279                return(errno);
280	else
281		return(0);
282}
283
284int
285proc_track_dirty(pid_t pid, uint32_t flags)
286{
287	if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
288		return errno;
289	}
290
291	return 0;
292}
293
294int
295proc_set_dirty(pid_t pid, bool dirty)
296{
297	if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
298		return errno;
299	}
300
301	return 0;
302}
303
304int
305proc_get_dirty(pid_t pid, uint32_t *flags)
306{
307	int retval;
308
309	if (!flags) {
310		return EINVAL;
311	}
312
313	retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
314	if (retval == -1) {
315		return errno;
316	}
317
318	*flags = retval;
319
320	return 0;
321}
322
323int
324proc_clear_dirty(pid_t pid, uint32_t flags)
325{
326	if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
327		return errno;
328	}
329
330	return 0;
331}
332
333int
334proc_terminate(pid_t pid, int *sig)
335{
336	int retval;
337
338	if (!sig) {
339		return EINVAL;
340	}
341
342	retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
343	if (retval == -1) {
344		return errno;
345	}
346
347	*sig = retval;
348
349	return 0;
350}
351
352int
353proc_set_cpumon_params(pid_t pid, int percentage, int interval)
354{
355	proc_policy_cpuusage_attr_t attr;
356
357	attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
358	attr.ppattr_cpu_percentage = percentage;
359	attr.ppattr_cpu_attr_interval = (uint64_t)interval;
360	attr.ppattr_cpu_attr_deadline = 0;
361
362	return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
363		PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
364}
365
366int
367proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
368{
369	proc_policy_cpuusage_attr_t attr;
370	int ret;
371
372	ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
373		PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
374
375	if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
376		*percentage = attr.ppattr_cpu_percentage;
377		*interval = (int)attr.ppattr_cpu_attr_interval;
378	} else {
379		*percentage = 0;
380		*interval = 0;
381	}
382
383	return (ret);
384}
385
386int
387proc_set_cpumon_defaults(pid_t pid)
388{
389	proc_policy_cpuusage_attr_t attr;
390
391	attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
392	attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
393	attr.ppattr_cpu_attr_interval = 0;
394	attr.ppattr_cpu_attr_deadline = 0;
395
396	return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
397		PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
398}
399
400int
401proc_disable_cpumon(pid_t pid)
402{
403	proc_policy_cpuusage_attr_t attr;
404
405	attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
406	attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
407	attr.ppattr_cpu_attr_interval = 0;
408	attr.ppattr_cpu_attr_deadline = 0;
409
410	return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
411		PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
412}
413
414
415/*
416 * Turn on the CPU usage monitor using the supplied parameters, and make
417 * violations of the monitor fatal.
418 *
419 * Returns:  0 on success;
420 *	    -1 on failure and sets errno
421 */
422int
423proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
424{
425	int current_percentage = 0;
426	int current_interval = 0;   /* intervals are in seconds */
427	int ret = 0;
428
429	if ((percentage <= 0)  || (interval <= 0)) {
430		errno = EINVAL;
431		return (-1);
432	}
433
434	/*
435	 * Do a simple query to see if CPU monitoring is
436	 * already active.  If either the percentage or the
437	 * interval is nonzero, then CPU monitoring is
438	 * already in use for this process.
439	 */
440	(void)proc_get_cpumon_params(pid, &current_percentage, &current_interval);
441	if (current_percentage || current_interval)
442	{
443		/*
444		 * The CPU monitor appears to be active.
445		 * We choose not to disturb those settings.
446		 */
447		errno = EBUSY;
448		return (-1);
449	}
450
451	if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
452		/* Failed to activate the CPU monitor */
453		return (ret);
454	}
455
456	if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, CPUMON_MAKE_FATAL)) != 0) {
457		/* Failed to set termination, back out the CPU monitor settings. */
458		(void)proc_disable_cpumon(pid);
459	}
460
461	return (ret);
462}
463
464int
465proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
466{
467	struct proc_rlimit_control_wakeupmon params;
468
469	params.wm_flags = WAKEMON_ENABLE;
470	params.wm_rate = rate_hz;
471
472	return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
473}
474
475#ifndef WAKEMON_GET_PARAMS
476#define WAKEMON_GET_PARAMS 0x4
477#define WAKEMON_SET_DEFAULTS 0x8
478#endif
479
480int
481proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
482{
483	struct proc_rlimit_control_wakeupmon params;
484	int error;
485
486	params.wm_flags = WAKEMON_GET_PARAMS;
487
488	if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params)) != 0) {
489		return (error);
490	}
491
492	*rate_hz = params.wm_rate;
493	*flags = params.wm_flags;
494
495	return (0);
496}
497
498int
499proc_set_wakemon_defaults(pid_t pid)
500{
501	struct proc_rlimit_control_wakeupmon params;
502
503	params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
504	params.wm_rate = -1;
505
506	return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
507}
508
509int
510proc_disable_wakemon(pid_t pid)
511{
512	struct proc_rlimit_control_wakeupmon params;
513
514	params.wm_flags = WAKEMON_DISABLE;
515	params.wm_rate = -1;
516
517	return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
518}
519
520
521
522
523/* Donate importance to adaptive processes from this process */
524int
525proc_donate_importance_boost()
526{
527	int rval;
528
529	rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
530							PROC_POLICY_ACTION_SET,
531							PROC_POLICY_BOOST,
532							PROC_POLICY_IMP_DONATION,
533							NULL, getpid(), 0);
534
535	if (rval == 0)
536		return (0);
537	else
538		return (errno);
539}
540
541static __attribute__((noinline)) void
542proc_importance_bad_assertion(char *reason) {
543    (void)reason;
544}
545
546/*
547 * Use the address of these variables as the token.  This way, they can be
548 * printed in the debugger as useful names.
549 */
550uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
551uint64_t normal_boost_assertion_token    = 0xfbfbfbfbfbfbfbfb;
552uint64_t non_boost_assertion_token       = 0xfcfcfcfcfcfcfcfc;
553uint64_t denap_boost_assertion_token	 = 0xfdfdfdfdfdfdfdfd;
554
555/*
556 * Accept the boost on a message, or request another boost assertion
557 * if we have already accepted the implicit boost for this message.
558 *
559 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
560 *
561 * Returns EIO if the message was not a boosting message.
562 * TODO: Return a 'non-boost' token instead.
563 */
564int
565proc_importance_assertion_begin_with_msg(mach_msg_header_t  *msg,
566                                __unused mach_msg_trailer_t *trailer,
567                                         uint64_t           *assertion_token)
568{
569	int rval = 0;
570
571	if (assertion_token == NULL)
572		return (EINVAL);
573
574#define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
575#define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
576
577	/* Is this a legacy boosted message? */
578	if (LEGACYBOOSTED(msg)) {
579
580		/*
581		 * Have we accepted the implicit boost for this message yet?
582		 * If we haven't accepted it yet, no need to call into kernel.
583		 */
584		if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
585			msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
586			*assertion_token = (uint64_t) &important_boost_assertion_token;
587			return (0);
588		}
589
590		/* Request an additional boost count */
591		rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
592								PROC_POLICY_ACTION_HOLD,
593								PROC_POLICY_BOOST,
594								PROC_POLICY_IMP_IMPORTANT,
595								NULL, getpid(), 0);
596		if (rval == 0) {
597			*assertion_token = (uint64_t) &important_boost_assertion_token;
598			return (0);
599		} else if (errno == EOVERFLOW) {
600			proc_importance_bad_assertion("Attempted to take assertion while not boosted");
601			return (errno);
602		} else {
603			return (errno);
604		}
605	}
606
607	return (EIO);
608}
609
610
611/*
612 * Drop a boost assertion.
613 * Returns EOVERFLOW on boost assertion underflow.
614 */
615int
616proc_importance_assertion_complete(uint64_t assertion_token)
617{
618	int rval = 0;
619
620	if (assertion_token == 0)
621		return (0);
622
623	if (assertion_token == (uint64_t) &important_boost_assertion_token) {
624		rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
625								PROC_POLICY_ACTION_DROP,
626								PROC_POLICY_BOOST,
627								PROC_POLICY_IMP_IMPORTANT,
628								NULL, getpid(), 0);
629		if (rval == 0) {
630			return (0);
631		} else if (errno == EOVERFLOW) {
632			proc_importance_bad_assertion("Attempted to drop too many assertions");
633			return (errno);
634		} else {
635			return (errno);
636		}
637	} else {
638		proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
639		return (EIO);
640	}
641}
642
643/*
644 * Accept the De-Nap boost on a message, or request another boost assertion
645 * if we have already accepted the implicit boost for this message.
646 *
647 * Interface is deprecated before it really got started - just as synonym
648 * for proc_importance_assertion_begin_with_msg() now.
649 */
650int
651proc_denap_assertion_begin_with_msg(mach_msg_header_t  *msg,
652				    uint64_t           *assertion_token)
653{
654#pragma clang diagnostic push
655#pragma clang diagnostic ignored "-Wdeprecated-declarations"
656	return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
657#pragma clang diagnostic pop
658}
659
660
661/*
662 * Drop a denap boost assertion.
663 *
664 * Interface is deprecated before it really got started - just a synonym
665 * for proc_importance_assertion_complete() now.
666 */
667int
668proc_denap_assertion_complete(uint64_t assertion_token)
669{
670	return proc_importance_assertion_complete(assertion_token);
671}
672
673
674int
675proc_clear_vmpressure(pid_t pid)
676{
677	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_STARVATION, PROC_POLICY_RS_VIRTUALMEM, NULL, pid, (uint64_t)0) != -1)
678		return(0);
679	else
680		return(errno);
681}
682
683/* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
684int
685proc_set_owner_vmpressure(void)
686{
687	int retval;
688
689	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1)
690		return(errno);
691
692	return(0);
693}
694
695/* mark yourself to delay idle sleep on disk IO */
696int
697proc_set_delayidlesleep(void)
698{
699	int retval;
700
701	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1)
702		return(errno);
703
704	return(0);
705}
706
707/* Reset yourself to delay idle sleep on disk IO, if already set */
708int
709proc_clear_delayidlesleep(void)
710{
711	int retval;
712
713	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1)
714		return(errno);
715
716	return(0);
717}
718
719/* disable the launch time backgroudn policy and restore the process to default group */
720int
721proc_disable_apptype(pid_t pid, int apptype)
722{
723	switch (apptype) {
724		case PROC_POLICY_OSX_APPTYPE_TAL:
725		case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
726			break;
727		default:
728			return(EINVAL);
729	}
730
731	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1)
732		return(0);
733	else
734		return(errno);
735
736}
737
738/* re-enable the launch time background policy if it had been disabled. */
739int
740proc_enable_apptype(pid_t pid, int apptype)
741{
742	switch (apptype) {
743		case PROC_POLICY_OSX_APPTYPE_TAL:
744		case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
745			break;
746		default:
747			return(EINVAL);
748
749	}
750
751	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1)
752		return(0);
753	else
754		return(errno);
755
756}
757
758#if !TARGET_IPHONE_SIMULATOR
759
760int
761proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
762{
763	return 0;
764}
765
766#endif /* !TARGET_IPHONE_SIMULATOR */
767
768
769
770
771