Browse Source

single pid + leak checks

tags/0.3.0 0.3.0
boB Rudis 3 years ago
parent
commit
659982d33a
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 13
      Makefile
  2. 4
      NEWS.md
  3. 170
      archinfo.c

13
Makefile

@ -6,6 +6,11 @@ archinfo:
$(CC) archinfo.c -o arm_app -target arm64-apple-macos11 $(CC) archinfo.c -o arm_app -target arm64-apple-macos11
lipo -create -output archinfo x86_app arm_app && rm x86_app arm_app lipo -create -output archinfo x86_app arm_app && rm x86_app arm_app
leaks: archinfo
leaks --readonlyContent -atExit -- ./archinfo | grep LEAK: || true
leaks --readonlyContent -atExit -- ./archinfo --json | grep LEAK: || true
leaks --readonlyContent -atExit -- ./archinfo --json | grep LEAK: || true
sign: archinfo sign: archinfo
codesign --force --verify --verbose --sign ${IDENTITY} archinfo codesign --force --verify --verbose --sign ${IDENTITY} archinfo
@ -13,5 +18,9 @@ clean:
rm -f archinfo rm -f archinfo
test: archinfo test: archinfo
@./archinfo | grep -q tccd && echo "Columns: PASSED" || "Columns: FAILED" @./archinfo | grep -q tccd && echo "Columns: PASSED (list)" || echo "Columns: FAILED (list)"
@./archinfo --json | grep -q 'tccd"}' && echo " JSON: PASSED" || " JSON: FAILED" @./archinfo --columns | grep -q tccd && echo "Columns: PASSED (list, explicit)" || echo "Columns: FAILED (list, explicit)"
@./archinfo --json | grep -q 'tccd"}' && echo " JSON: PASSED (list)" || echo " JSON: FAILED (list)"
@(./archinfo --pid `pgrep keyboardservicesd` | grep -q '64') && echo "Columns: PASSED (single)" || echo "Columns: FAILED (single)"
@(./archinfo --columns --pid `pgrep keyboardservicesd` | grep -q '"}') && echo "Columns: PASSED (single, explicit)" || echo "Columns: FAILED (single, explicit)"
@(./archinfo --json --pid `pgrep keyboardservicesd` | grep -q '"}') && echo " JSON: PASSED (single)" || echo " JSON: FAILED (single)"

4
NEWS.md

@ -1,3 +1,7 @@
# 0.3.0 • 2021-03-14
- added option for retrieving process info for a single pid
- added more tests
- added leak check Makefile option
# 0.2.0 • 2021-03-14 # 0.2.0 • 2021-03-14
- removed Xcode dependency - removed Xcode dependency
- added codesigning option - added codesigning option

170
archinfo.c

@ -1,15 +1,28 @@
#include <unistd.h>
#include <getopt.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
#include <mach/machine.h> #include <mach/machine.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#define noErr 0 #define noErr 0
#define VERSION "0.2.0" #define VERSION "0.3.0"
#define SYSCTL_ERROR 1
enum fmt { JSON=0, COLUMNS }; enum fmt { JSON=0, COLUMNS };
static int maxArgumentSize = 0;
typedef struct ProcInfo {
bool ok;
char *name;
char arch[10];
} procinfo;
// arch_info() is due to the spelunking work of Patrick Wardle <https://www.patreon.com/posts/45121749> // arch_info() is due to the spelunking work of Patrick Wardle <https://www.patreon.com/posts/45121749>
static char *arch_info(pid_t pid) { static char *arch_info(pid_t pid) {
@ -51,37 +64,50 @@ static char *arch_info(pid_t pid) {
} }
// The below is modified code from: <https://gist.github.com/s4y/1173880/9ea0ed9b8a55c23f10ecb67ce288e09f08d9d1e5> procinfo proc_info(pid_t pid) {
// and is Copyright (c) 2020 DeepTech, Inc. (MIT License).
// size_t size = maxArgumentSize;
// The code below the standard way to do this and I originally only copied it due to some Objective-C components. procinfo p;
// While those components are no longer in use, the ACK stays b/c I'm thankful I didn't have to write Objective-C
// for the initial version :-)
int enumerate_processes(enum fmt output_type) { char* buffer = (char *)malloc(4096);
static int maxArgumentSize = 0; if (sysctl((int[]){ CTL_KERN, KERN_PROCARGS2, pid }, 3, buffer, &size, NULL, 0) == 0) {
if (maxArgumentSize == 0) { p.ok = TRUE;
size_t size = sizeof(maxArgumentSize); p.name = buffer;
if (sysctl((int[]) { CTL_KERN, KERN_ARGMAX }, 2, &maxArgumentSize, &size, NULL, 0) == -1) { strncpy(p.arch, arch_info(pid), 10);
perror("sysctl argument size");
maxArgumentSize = 4096; // Default } else {
} free(buffer);
p.ok = FALSE;
} }
return(p);
}
void output_one(enum fmt output_type, pid_t pid, procinfo p) {
if (output_type == COLUMNS) {
printf("%7d %6s %s\n", pid, p.arch, p.name+sizeof(int));
} else if (output_type == JSON) {
printf("{\"pid\":%d,\"arch\":\"%s\",\"name\":\"%s\"}\n", pid, p.arch, p.name+sizeof(int));
}
}
int enumerate_processes(enum fmt output_type) {
int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
struct kinfo_proc *info; struct kinfo_proc *info;
size_t length; size_t length;
int count; int count;
if (sysctl(mib, 3, NULL, &length, NULL, 0) < 0) return(1); if (sysctl(mib, 3, NULL, &length, NULL, 0) < 0) return(SYSCTL_ERROR);
if (!(info = malloc(length))) return(1); if (!(info = malloc(length))) return(SYSCTL_ERROR);
if (sysctl(mib, 3, info, &length, NULL, 0) < 0) { if (sysctl(mib, 3, info, &length, NULL, 0) < 0) {
free(info); free(info);
return(1); return(SYSCTL_ERROR);
} }
count = (int)(length / sizeof(struct kinfo_proc)); count = (int)(length / sizeof(struct kinfo_proc));
@ -92,20 +118,13 @@ int enumerate_processes(enum fmt output_type) {
if (pid == 0) continue; if (pid == 0) continue;
size_t size = maxArgumentSize; procinfo p = proc_info(pid);
char* buffer = (char *)malloc(length);
if (sysctl((int[]){ CTL_KERN, KERN_PROCARGS2, pid }, 3, buffer, &size, NULL, 0) == 0) { if (p.ok) {
if (output_type == COLUMNS) { output_one(output_type, pid, p);
printf("%7d %6s %s\n", pid, arch_info(pid), buffer+sizeof(int)); free(p.name);
} else if (output_type == JSON) {
printf("{\"pid\":%d,\"arch\":\"%s\",\"name\":\"%s\"}\n", pid, arch_info(pid), buffer+sizeof(int));
}
} }
free(buffer);
} }
free(info); free(info);
@ -119,31 +138,92 @@ void help() {
printf("archinfo %s\n", VERSION); printf("archinfo %s\n", VERSION);
printf("boB Rudis <bob@rud.is>\n"); printf("boB Rudis <bob@rud.is>\n");
printf("\n"); printf("\n");
printf("archinfo outputs a list of running processes with the architecture (x86_64/amd64)\n"); printf("archinfo outputs a list of running processes with architecture (x86_64/amd64) information\n");
printf("\n"); printf("\n");
printf("USAGE:\n"); printf("USAGE:\n");
printf(" archinfo [FLAG]\n"); printf(" archinfo [--columns|--json] [--pid #]\n");
printf("\n"); printf("\n");
printf("FLAG:\n"); printf("FLAGS/OPTIONS:\n");
printf(" --columns Output process list in columns (default)\n");
printf(" --json Output process list in ndjson\n"); printf(" --json Output process list in ndjson\n");
printf(" --columns Output process list in columns\n"); printf(" --pid # Output process architecture info for the specified process\n");
printf(" --help Display this help text\n"); printf(" --help Display this help text\n");
} }
void init() {
if (maxArgumentSize == 0) {
size_t size = sizeof(maxArgumentSize);
if (sysctl((int[]) { CTL_KERN, KERN_ARGMAX }, 2, &maxArgumentSize, &size, NULL, 0) == -1) {
perror("sysctl argument size");
maxArgumentSize = 4096; // Default
}
}
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc >= 2) { int c;
if (strcmp("--json", argv[1]) == 0) { bool show_help = FALSE;
return(enumerate_processes(JSON)); bool do_one = FALSE;
} else if (strcmp("--columns", argv[1]) == 0) { pid_t pid = -1;
return(enumerate_processes(COLUMNS)); enum fmt output_type = COLUMNS;
} else if (strcmp("--help", argv[1]) == 0) {
help(); while(true) {
return(0);
int this_option_optind = optind ? optind : 1;
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 }
};
c = getopt_long(argc, argv, "jchp:", long_options, &option_index);
if (c == -1) break;
switch(c) {
case 'p': do_one = TRUE; pid = atoi(optarg); break;
case 'h': show_help = TRUE; break;
case 'j': output_type = JSON; break;
case 'c': output_type = COLUMNS; break;
} }
} else {
return(enumerate_processes(COLUMNS)); }
init();
// only show help if --help is in the arg list
if (show_help) {
help();
return(0);
} }
// only do one process if --pid is in the arg list
if (do_one) {
if (pid > 0) {
procinfo p = proc_info(pid);
if (p.ok) {
output_one(output_type, pid, p);
free(p.name);
return(0);
}
}
return(SYSCTL_ERROR);
}
// otherwise do them all
return(enumerate_processes(output_type));
} }

Loading…
Cancel
Save