@ -7,14 +7,20 @@
# include <mach/machine.h>
# include <sys/types.h>
# include <sys/sysctl.h>
# include <libgen.h>
# define VERSION "0.4.0"
# define noErr 0
# define VERSION "0.3.0"
# define DEFAULT_BUFFER_SIZE 4096
# define SYSCTL_ERROR 1
# define is_match(x) (x == 0)
enum fmt { JSON = 0 , COLUMNS } ;
enum show { ALL = 0 , ARM64 , X86_64 } ;
static int maxArgumentS ize = 0 ;
static int max_arg_s ize = 0 ;
typedef struct ProcInfo {
bool ok ;
@ -22,7 +28,6 @@ typedef struct ProcInfo {
char arch [ 10 ] ;
} procinfo ;
// arch_info() is due to the spelunking work of Patrick Wardle <https://www.patreon.com/posts/45121749>
static char * arch_info ( pid_t pid ) {
@ -55,7 +60,7 @@ static char *arch_info(pid_t pid) {
if ( noErr ! = sysctl ( mib , ( u_int ) length , & procInfo , & size , NULL , 0 ) ) return ( " arm64 " ) ; //get proc info
//'P_TRANSLATED' set? set architecture to 'Intel '
//'P_TRANSLATED' set? set architecture to 'x86_64 '
return ( ( P_TRANSLATED = = ( P_TRANSLATED & procInfo . kp_proc . p_flag ) ) ? " x86_64 " : " arm64 " ) ;
}
@ -64,15 +69,26 @@ static char *arch_info(pid_t pid) {
}
// retrieve process info
procinfo proc_info ( pid_t pid ) {
size_t size = maxArgumentS ize ;
size_t size = max_arg_s ize ;
procinfo p ;
int mib [ 3 ] = { CTL_KERN , KERN_PROCARGS2 , pid } ;
struct kinfo_proc * info ;
size_t length ;
int count ;
// get size for buffer
( void ) sysctl ( mib , 3 , NULL , & length , NULL , 0 ) ;
char * buffer = ( char * ) malloc ( 4096 ) ;
char * buffer = ( char * ) calloc ( length + 32 , sizeof ( char ) ) ; // need +32 b/c this is busted on Big Sur
if ( sysctl ( ( int [ ] ) { CTL_KERN , KERN_PROCARGS2 , pid } , 3 , buffer , & size , NULL , 0 ) = = 0 ) {
// get the info
if ( sysctl ( mib , 3 , buffer , & size , NULL , 0 ) = = 0 ) {
// copy the info
p . ok = TRUE ;
p . name = buffer ;
strncpy ( p . arch , arch_info ( pid ) , 10 ) ;
@ -86,42 +102,68 @@ procinfo proc_info(pid_t pid) {
}
void output_one ( enum fmt output_type , pid_t pid , procinfo p ) {
// output one line of process info with architecture info
void output_one ( enum fmt output_type , pid_t pid , procinfo p , bool only_basename ) {
if ( output_type = = COLUMNS ) {
printf ( " %7d %6s %s \n " , pid , p . arch , p . name + sizeof ( int ) ) ;
printf (
" %7d %6s %s \n " ,
pid ,
p . arch ,
( only_basename ? basename ( ( char * ) ( p . name + sizeof ( int ) ) ) : p . name + sizeof ( int ) )
) ;
} else if ( output_type = = JSON ) {
printf ( " { \" pid \" :%d, \" arch \" : \" %s \" , \" name \" : \" %s \" } \n " , pid , p . arch , p . name + sizeof ( int ) ) ;
printf (
" { \" pid \" :%d, \" arch \" : \" %s \" , \" name \" : \" %s \" } \n " ,
pid ,
p . arch ,
( only_basename ? basename ( ( char * ) ( p . name + sizeof ( int ) ) ) : p . name + sizeof ( int ) )
) ;
}
}
int enumerate_processes ( enum fmt output_type ) {
// walk through process list, get PID and name, then pass that on to output_one() to
// grab the architecture and do the actual output
int enumerate_processes ( enum fmt output_type , enum show to_show , bool only_basename ) {
int mib [ 3 ] = { CTL_KERN , KERN_PROC , KERN_PROC_ALL } ;
struct kinfo_proc * info ;
size_t length ;
int count ;
// get the running process list
if ( sysctl ( mib , 3 , NULL , & length , NULL , 0 ) < 0 ) return ( SYSCTL_ERROR ) ;
if ( ! ( info = malloc ( length ) ) ) return ( SYSCTL_ERROR ) ;
// make some room for results
if ( ! ( info = calloc ( length , sizeof ( char ) ) ) ) return ( SYSCTL_ERROR ) ;
// get the results
if ( sysctl ( mib , 3 , info , & length , NULL , 0 ) < 0 ) {
free ( info ) ;
return ( SYSCTL_ERROR ) ;
}
// how many results?
count = ( int ) ( length / sizeof ( struct kinfo_proc ) ) ;
// for each result
for ( int i = 0 ; i < count ; i + + ) {
pid_t pid = info [ i ] . kp_proc . p_pid ;
pid_t pid = info [ i ] . kp_proc . p_pid ; // get PID
if ( pid = = 0 ) continue ;
procinfo p = proc_info ( pid ) ;
procinfo p = proc_info ( pid ) ; // get process info
if ( p . ok ) {
output_one ( output_type , pid , p ) ;
if (
( to_show = = ALL ) | |
( ( to_show = = ARM64 ) & & is_match ( strncmp ( " arm " , p . arch , 3 ) ) ) | |
( ( to_show = = X86_64 ) & & is_match ( strncmp ( " x86 " , p . arch , 3 ) ) )
) {
output_one ( output_type , pid , p , only_basename ) ;
}
free ( p . name ) ;
}
@ -133,6 +175,8 @@ int enumerate_processes(enum fmt output_type) {
}
// call to display cmdline tool help
void help ( ) {
printf ( " archinfo %s \n " , VERSION ) ;
@ -141,9 +185,12 @@ void help() {
printf ( " archinfo outputs a list of running processes with architecture (x86_64/amd64) information \n " ) ;
printf ( " \n " ) ;
printf ( " USAGE: \n " ) ;
printf ( " archinfo [--columns|--json] [--pid #] \n " ) ;
printf ( " archinfo [--arm|--x86] [--basename] [-- columns|--json] [--pid #] \n " ) ;
printf ( " \n " ) ;
printf ( " FLAGS/OPTIONS: \n " ) ;
printf ( " --arm Only show arm64 processes (default is to show both) \n " ) ;
printf ( " --x86 Only show x86_64 processes (default is to show both) \n " ) ;
printf ( " --basename Only show basename of process executable \n " ) ;
printf ( " --columns Output process list in columns (default) \n " ) ;
printf ( " --json Output process list in ndjson \n " ) ;
printf ( " --pid # Output process architecture info for the specified process \n " ) ;
@ -153,11 +200,11 @@ void help() {
void init ( ) {
if ( maxArgumentS ize = = 0 ) {
size_t size = sizeof ( maxArgumentS ize ) ;
if ( sysctl ( ( int [ ] ) { CTL_KERN , KERN_ARGMAX } , 2 , & maxArgumentS ize , & size , NULL , 0 ) = = - 1 ) {
if ( max_arg_s ize = = 0 ) {
size_t size = sizeof ( max_arg_s ize ) ;
if ( sysctl ( ( int [ ] ) { CTL_KERN , KERN_ARGMAX } , 2 , & max_arg_s ize , & size , NULL , 0 ) = = - 1 ) {
perror ( " sysctl argument size " ) ;
maxArgumentSize = 4096 ; // Default
max_arg_size = DEFAULT_BUFFER_SIZE ;
}
}
@ -166,8 +213,10 @@ void init() {
int main ( int argc , char * * argv ) {
int c ;
enum show to_show = ALL ;
bool show_help = FALSE ;
bool do_one = FALSE ;
bool only_basename = FALSE ;
pid_t pid = - 1 ;
enum fmt output_type = COLUMNS ;
@ -177,19 +226,25 @@ int main(int argc, char** argv) {
int option_index = 0 ;
static struct option long_options [ ] = {
{ " json " , no_argument , 0 , ' j ' } ,
{ " columns " , no_argument , 0 , ' c ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ " pid " , required_argument , 0 , ' p ' } ,
{ 0 , 0 , 0 , 0 }
{ " arm " , no_argument , 0 , ' a ' } ,
{ " x86 " , no_argument , 0 , ' x ' } ,
{ " basename " , no_argument , 0 , ' b ' } ,
{ " json " , no_argument , 0 , ' j ' } ,
{ " columns " , no_argument , 0 , ' c ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ " pid " , required_argument , 0 , ' p ' } ,
{ 0 , 0 , 0 , 0 }
} ;
c = getopt_long ( argc , argv , " jchp: " , long_options , & option_index ) ;
c = getopt_long ( argc , argv , " axb jchp:" , long_options , & option_index ) ;
if ( c = = - 1 ) break ;
switch ( c ) {
case ' a ' : to_show = ARM64 ; break ;
case ' x ' : to_show = X86_64 ; break ;
case ' b ' : only_basename = TRUE ; break ;
case ' p ' : do_one = TRUE ; pid = atoi ( optarg ) ; break ;
case ' h ' : show_help = TRUE ; break ;
case ' j ' : output_type = JSON ; break ;
@ -214,7 +269,7 @@ int main(int argc, char** argv) {
if ( pid > 0 ) {
procinfo p = proc_info ( pid ) ;
if ( p . ok ) {
output_one ( output_type , pid , p ) ;
output_one ( output_type , pid , p , only_basename ) ;
free ( p . name ) ;
return ( 0 ) ;
}
@ -224,6 +279,6 @@ int main(int argc, char** argv) {
// otherwise do them all
return ( enumerate_processes ( output_type ) ) ;
return ( enumerate_processes ( output_type , to_show , only_basename ) ) ;
}