Get other process' argv in OS X using C - c

I want to get other process' argv like ps.
I'm using Mac OS X 10.4.11 running on Intel or PowerPC.
First, I read code of ps and man kvm, then I wrote some C code.
#include <kvm.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include <paths.h>
int
main(void) {
char errbuf[1024];
kvm_t *kd = kvm_openfiles(_PATH_DEVNULL, NULL, _PATH_DEVNULL, O_RDONLY, errbuf);
int num_procs;
if (!kd) { fprintf(stderr, "kvm_openfiles failed : %s\n", errbuf); return 0; }
struct kinfo_proc *proc_table = kvm_getprocs(kd, KERN_PROC_ALL, 0, &num_procs);
for (int i = 0; i < num_procs; i++) {
struct kinfo_proc *pproc = &proc_table[i];
char **proc_argv = kvm_getargv(kd, pproc, 0);
printf("%p\n", proc_argv);
}
kvm_close(kd);
return 0;
}
When ran on PowerPC, kvm_getargv() always returned NULL. When ran
on Intel, kvm_openfiles() failed with error /dev/mem: No such file
or directory.
Of cource, I know about permission.
Second, I tried sysctl.
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#define pid_of(pproc) pproc->kp_proc.p_pid
int
main(void) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
int buffer_size;
sysctl(mib, 4, NULL, &buffer_size, NULL, 0);
struct kinfo_proc *result = malloc(buffer_size);
sysctl(mib, 4, result, &buffer_size, NULL, 0);
int num_procs = buffer_size / sizeof(struct kinfo_proc);
for (int i = 0; i < num_procs; i++) {
struct kinfo_proc *pproc = result + i;
int mib[3] = { CTL_KERN, KERN_PROCARGS, pid_of(pproc) }; // KERN_PROC_ARGS is not defined
char *proc_argv;
int argv_len;
sysctl(mib, 3, NULL, &argv_len, NULL, 0);
proc_argv = malloc(sizeof(char) * argv_len);
sysctl(mib, 3, proc_argv, &argv_len, NULL, 0);
fwrite(proc_argv, sizeof(char), argv_len, stdout);
printf("\n");
free(proc_argv);
}
return 0;
}
By fwrite, I got argv[0] but argv[1..] are not (environment variables
are printed out.)
There is no more way to do it?

In 10.6, KERN_PROCARGS2 is available: https://gist.github.com/770696
This way is used from ps, procfs on MacFUSE, etc.

I've actually been needing the same thing for a Python library I'm writing, and in my searching I came across another Python lib (PSI) that implements this in C code. It's part of the python module code for listing processes and includes listing the arguments for each process as well. You could take a look at the source code for that for a working example:
darwin_process.c - scroll down to set_exe() for the relevant code
Note: the site is really slow so you'll have to be a bit patient while it loads.

Related

Different results when running inside a docker container

I am trying to run some code based on this libaio sample:
https://oxnz.github.io/2016/10/13/linux-aio/#example-1
I added the O_DIRECT flag according to libaio's documentation.
It seems to work inside my ubuntu 16.04 desktop machine (hello is written to /tmp/test).
However, when I compile and run the same sample inside a docker container nothing is written to the file. when running inside gdb I can see that an event is read by io_getevents and the result is set to -22 (EINVAL).
Any ideas?
This is my modified code
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <libaio.h>
int main() {
io_context_t ctx;
struct iocb iocb;
struct iocb * iocbs[1];
struct io_event events[1];
struct timespec timeout;
int fd;
fd = open("/tmp/test", O_WRONLY | O_CREAT | O_DIRECT) ;
if (fd < 0) err(1, "open");
memset(&ctx, 0, sizeof(ctx));
if (io_setup(10, &ctx) != 0) err(1, "io_setup");
const char *msg = "hello";
io_prep_pwrite(&iocb, fd, (void *)msg, strlen(msg), 0);
iocb.data = (void *)msg;
iocbs[0] = &iocb;
if (io_submit(ctx, 1, iocbs) != 1) {
io_destroy(ctx);
err(1, "io_submit");
}
while (1) {
timeout.tv_sec = 0;
timeout.tv_nsec = 500000000;
int ret = io_getevents(ctx, 0, 1, events, &timeout);
printf("ret=%d\n", ret);
if (ret == 1) {
close(fd);
break;
}
printf("not done yet\n");
sleep(1);
}
io_destroy(ctx);
return 0;
}
The filesystem inside the container is likely to be different to that of the host's filesystem (on modern setups is likely to be overlayfs but on older systems it could be aufs). For O_DIRECT on an open to work a device/filesystem has to at least "support" it (note the scare quotes) and it's likely your container's filesystem does not.

illegal instruction on exp_expectl with AIX 64 bit

Please take a look at this simple utility program. It works fine with AIX when compiled to 32 bit using libexpect5.42 provided by the operating system.
However, when linking with a 64 bit of libexpect which we manually compiled, we are getting an illegal instruction error on the call to exp_expectl(). Any ideas are welcomed.
#include <stdio.h>
#include <stdlib.h>
#include <expect.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int
main (int argc, char** argv, char** arge)
{
int returnValue = 0;
int iFd = 0;
int res = 0;
exp_loguser = 1;
exp_timeout = 5;
exp_is_debugging = 0;
printf("spawning process without argument\n");
iFd = exp_spawnl ("ls", "ls",(char*)0 );
printf ("spawned\n");
printf ("iFd = %d\n", iFd);
if (iFd < 0)
{
printf ("Return %d\n",iFd);
}
else
{
res = exp_expectl (iFd, exp_glob,"ls", 0, exp_end);
printf ("Return %d \n",res);
}
return iFd;
}

MAC address from interface on OS X (C)

This might be a stupid question and I apologize if it's already been addressed here, but I've searched quite a bit without much luck. I'm trying to get my interface's hardware address in C and I'm using OS X (x86-64). I know how to get it with ifconfig, but I want my program to get it automatically for any computer, well, at least OS X computers. I found another thread that posted this link which pretty much does what I want (with some modifications), but I can't make the iokit functions link in ld (my compiler is gcc). I tried adding the flags -lIOKit and -framework IOKit to the gcc command line, but I still get the same link errors. Here's a link to my code: header and source.
This little program will work without changes on OSX.
Code : (credits to Alecs King from freebsd list)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int mib[6], len;
char *buf;
unsigned char *ptr;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
if (argc != 2) {
fprintf(stderr, "Usage: getmac <interface>\n");
return 1;
}
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
if ((mib[5] = if_nametoindex(argv[1])) == 0) {
perror("if_nametoindex error");
exit(2);
}
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
perror("sysctl 1 error");
exit(3);
}
if ((buf = malloc(len)) == NULL) {
perror("malloc error");
exit(4);
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
perror("sysctl 2 error");
exit(5);
}
ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *ptr, *(ptr+1), *(ptr+2),
*(ptr+3), *(ptr+4), *(ptr+5));
return 0;
}
You should, however, change int len; to size_t len;

How to use kernel libcrc32c (or same functions) in userspace programmes?

I want to do some CRC check in my own userspace programme. And I find that the kernel crypto lib is already in the system, and come with SSE4.2 support.
I tried to directly #include <linux/crc32c.h> and run gcc with -I/usr/src/linux/include/. However, it doesnot work.
Any way to use some kind of libcrc32c ?
You can use kernel crypto CRC32c (and other hash/cipher functions) from user-space via socket family AF_ALG on Linux:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <sys/param.h>
#include <string.h>
#include <strings.h>
int
main (int argc, char **argv) {
int sds[2] = { -1, -1 };
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "hash",
.salg_name = "crc32c"
};
if ((sds[0] = socket(AF_ALG, SOCK_SEQPACKET, 0)) == -1 )
return -1;
if( bind(sds[0], (struct sockaddr *) &sa, sizeof(sa)) != 0 )
return -1;
if( (sds[1] = accept(sds[0], NULL, 0)) == -1 )
return -1;
char *s = "hello";
size_t n = strlen(s);
if (send(sds[1], s, n, MSG_MORE) != n)
return -1;
int crc32c = 0x00000000;
if(read(sds[1], &crc32c, 4) != 4)
return -1;
printf("%08X\n", crc32c);
return 0;
}
If you're hashing files or socket data you can speed it up using zero-copy approach to avoid kernel -> user-space buffer copy with sendfile and/or splice.
Happy coding.

Bus error in C Program on Unix machine

I'm fairly unexperienced with C and am running into a "Bus error" that I cannot understand the cause of. I had never heard of gdb but came across it on this forum and tried using it on my problem program and got the following output:
% gdb Proc1 GNU gdb 5.0
...
This GDB was
configured as
"sparc-sun-solaris2.8"...
(no
debugging symbols found)...
(gdb) run
Starting program:
/home/0/vlcek/CSE660/Lab3/Proc1
(no
debugging symbols found)...
(no
debugging symbols found)...
(no
debugging symbols found)...
Program
received signal SIGSEGV, Segmentation
fault. 0x10a64 in main ()
I have no idea what this means, is that saying there's an error in line 10 in my code? If so, line 10 in my code is merely "int main()" so I'm not sure the issue there... When I try running the program all it says is "Bus error" so I'm not sure where to go from here. I even tried putting a printf right after main and it doesn't print the string, only gives me a Bus error.
Below is my code:
// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ssem.h"
#include "sshm.h"
// Code of Proc1
int main()
{int i, internal_reg;
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444;
/* here create and initialize all semaphores */
int sem1 = sem_create(key1, 1);
if (sem1 < 0) {
perror("sem failed");
}
int sem2 = sem_create(key2, 1);
if (sem2 < 0) {
perror("sem failed");
}
int sem3 = sem_create(key3, 1);
if (sem3 < 0) {
perror("sem failed");
}
int sem4 = sem_create(key4, 1);
if (sem4 < 0) {
perror("sem failed");
}
/* here created: shared memory array Account of size 3 */
int *Account;
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int));
if (shmid < 0) {
perror("shm failed");
}
Account[0]=10000;
Account[1]=10000;
Account[2]=10000;
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/
for (i = 0; i < 1000; i++)
{
sem_signal(sem1);
sem_signal(sem1);
sem_signal(sem1);
internal_reg = Account[0];
internal_reg = internal_reg - 200;
Account[0] = internal_reg;
/* same thing, except we're adding $100 to Account1 now... */
internal_reg = Account[1];
internal_reg = internal_reg + 200;
Account[1] = internal_reg;
if (i % 100 == 0 && i != 0) {
printf("Account 0: $%i\n", Account[0]);
printf("Account 1: $%i\n", Account[1]);
}
if (i == 300 || i == 600) {
sleep(1);
}
sem_wait(sem2);
sem_wait(sem3);
sem_wait(sem4);
}
/* Here add a code that prints contents of each account
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/
}
/*in the code above include some wait and signal operations on semaphores. Do no
t over-synchronize. */
Here is the documentation for ssem and sshm:
/*
* ssem.c
*
* Version 1.0.0
* Date : 10 Jan 2002
*
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "ssem.h"
#define PERMS 0600
static struct sembuf op_lock[1] = {
0, -1, 0
};
static struct sembuf op_unlock[1] = {
0, 1, IPC_NOWAIT
};
int sem_create(int key,int initval)
{
int semid,i;
semid = semget((key_t)key, 1, IPC_CREAT | PERMS);
for(i=0;i<initval;i++)
semop(semid,&op_unlock[0],1);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key,0,0);
return semid;
}
int sem_wait(int semid)
{
return semop(semid,&op_lock[0],1);
}
int sem_signal(int semid)
{
return semop(semid,&op_unlock[0],1);
}
int sem_rm(int semid)
{
return semctl(semid, 0, IPC_RMID, 0);
}
/*
* sshm.c
*
* Routines for Simpler shared memory operations
* Version : 1.0.0.
* Date : 10 Jan 2002
*
*/
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include "sshm.h"
#define PERMS 0600
int shm_get(int key, void **start_ptr, int size)
{
int shmid;
shmid = shmget((key_t) key, size, PERMS | IPC_CREAT);
(*start_ptr) = (void *) shmat(shmid, (char *) 0, 0);
return shmid;
}
int shm_rm(int shmid)
{
return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
}
After compiling Proc1.c with the -ggdb flag and running gdb I got the following:
Program received signal SIGSEGV,
Segmentation fault. 0x10a64 in main ()
at Proc1.c:36
36 Account[0]=10000
Why would this cause a segmentation fault?
After changing the declaration of Account to
int *Account = 0;
and adding
printf("Account == %p\n", Account);
before Account[0] = 10000;
I get the following upon running Proc1:
Account == ffffffff
Bus error
In order to get more sensible results from gdb you should compile your program with the -ggdb option. This will then include debugging information (like line numbers) into your program.
What you are currently seeing is the memory address (0x10a64) of the program counter. This will not help you very much unless you can correlate the assembly instructions you find there with a part of your C program yourself.
It looks like you are using shm_get properly. I think the library designer has made a terrible mistake in naming the function so similarly to shmget.
It's just as I thought. The Account pointer is ending up with an invalid value (aka 0xffffffff (aka (void *)(-1))) in it. The value (void *)(-1) generally indicates some sort of error, and it is explicitly mentioned in the manpage for shmat. This indicates that the shmat call inside the library failed. Here is how you can tell if it failed:
if (Account == (void *)(-1)) {
perror("shmat failed");
}
Account[0] = 10000;
// ...
Now, why it failed is an interesting mystery. Apparently the shmget call succeeded.
Personally, I think System V IPC is basically deprecated at this point and you should avoid using it if you can.
Depending on your compiler and your compiler options you might encounter an aliasing problem because your are casting the address of your Account pointer. These oldish interfaces are not in phase with modern antialiasing rules, meaning that the optimizer supposes that the value of Account wouldn't change.
Also you should get the argument for shm_get as close as possible to the expected type. Try perhaps something like the following.
void volatile* shmRet;
int shmid = shm_get(123456, (void**) &shmRet, 3*sizeof(int));
int *Account = shmRet;
I don't have the same architecture, so I don't know the exact prototype of your shm_get but usually it is also a bad idea to use fixed keys for this type of functions. There should be some function that returns you some key to use in your application.

Resources