From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

/*-
* This code relies heavily on the Darwin "ps" command, which is available
* from Apple in the adv_cmds portion of the Darwin distribution. The portions
* of this code which were included from that source are:
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The portions of this code which were necessary to tie into the Perl
* Proc::ProcessTable module are:
*
* Copyright (c) 2003 and 2008, Thomas R. Wyant, III
*
* and may be reused under the same terms as Perl itself.
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_traps.h>
#include <mach/mach_types.h>
#include <mach/shared_memory_server.h>
#include <mach/task.h>
#include <mach/thread_act.h>
#include <mach/time_value.h>
#include <mach/vm_map.h>
#include <stdlib.h>
#include <sys/proc.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#ifndef KERN_PROCARGS2 /* Not defined in Jaguar (10.2);
Defined in Panther (10.3) at least
through Leopard (10.5). */
#include <kvm.h>
#endif
#include <unistd.h>
/* these are in sys/sysctl.h */
#define KI_PROC(ki) (&(ki)->ki_p->kp_proc)
#define KI_EPROC(ki) (&(ki)->ki_p->kp_eproc)
#define STATE_MAX 7
typedef struct thread_values {
struct thread_basic_info tb;
/* struct policy_infos schedinfo; */
union {
struct policy_timeshare_info tshare;
struct policy_rr_info rr;
struct policy_fifo_info fifo;
} schedinfo;
} thread_values_t;
struct usave {
struct timeval u_start;
struct rusage u_ru;
struct rusage u_cru;
char u_acflag;
char u_valid;
};
typedef struct kinfo {
struct kinfo_proc *ki_p; /* proc structure */
struct usave ki_u; /* interesting parts of user */
char *ki_args; /* exec args */
char *ki_env; /* environment */
task_port_t task;
int state;
int cpu_usage;
int curpri;
int basepri;
int swapped;
struct task_basic_info tasks_info;
struct task_thread_times_info times;
/* struct policy_infos schedinfo; */
union {
struct policy_timeshare_info tshare;
struct policy_rr_info rr;
struct policy_fifo_info fifo;
} schedinfo;
int invalid_tinfo;
#ifdef KERN_PROCARGS2 /* Defined in Panther (10.3) and up */
mach_msg_type_number_t thread_count;
#else
int thread_count;
#endif
thread_port_array_t thread_list;
thread_values_t *thval;
int invalid_thinfo;
} KINFO;
#define TIME_IN_MICROSECONDS 1
#ifdef TESTING
/* Note that FREE_BUFFERS is to be defined appropriately before
* DIE_HORRIBLY is used.
*/
#define DIE_HORRIBLY(s) {FREE_BUFFERS perror (s); exit (1);}
#else /* def TESTING */
#define DIE_HORRIBLY(s) {FREE_BUFFERS perror (s); return;}
extern void bless_into_proc(char* format, char** fields, ...);
#ifdef TIME_IN_MICROSECONDS
static char *Format = "iiiiiiiiiiiiiiijjjllslsssss";
#else /* def TIME_IN_MICROSECONDS */
static char *Format = "iiiiiiiiiiiiiiilllllslsssss";
#endif /* def TIME_IN_MICROSECONDS */
static char *Fields[] = {
"pid", /* Process ID */
# define F_PID 0
"ppid", /* Parent pid */
# define F_PPID 1
"pgrp", /* Process group leader */
# define F_PGRP 2
"uid", /* real uid */
# define F_UID 3
"gid", /* real gid */
# define F_GID 4
"euid", /* effective uid */
# define F_EID 5
"egid", /* effective gid */
# define F_EGID 6
"suid", /* saved uid */
# define F_SUID 7
"sgid", /* saved gid */
# define F_SGID 8
"priority", /* proiority */
# define F_PRIORITY 9
"size", /* virtual size (Kbytes) */
# define F_SIZE 10
"rss", /* resident set size (Kbytes) */
# define F_RSS 11
"flags", /* process flags */
# define F_FLAGS 12
"nice", /* nice for CPU usage */
# define F_NICE 13
"sess", /* session pointer */
# define F_SESS 14
"time", /* total time (system + user, centi- or microseconds, depending) */
# define F_CPTICKS 15
"stime", /* system time (centi- or micrseconds, depending) */
# define F_STIME 16
"utime", /* user time (centi- or microseconds, depending) */
# define F_UTIME 17
"start", /* Start time in seconds since epoch */
# define F_START 18
"wchan", /* Wait channel (addr of system call) */
# define F_WCHAN 19
"ttydev",
# define F_TTYDEV 20
"ttynum", /* device number for tty, or -1 */
# define F_TTYNUM 21
"pctcpu", /* Percent cpu as string representing float */
# define F_PCTCPU 22
"pctmem", /* Percent memory as string representing float */
# define F_PCTMEM 23
"state", /* current run state (e.g. sleep, wait ...) */
# define F_STATE 24
"cmndline", /* entire command line */
# define F_CMNDLINE 25
"fname", /* filename */
# define F_FNAME 26
# define F_LASTFIELD 26
};
#endif /* def TESTING */
static char *States[] = {
"", "idle", "run", "sleep", "stop", "zombie"
};