debian: Update with version 0.95.9-2 packaging.
[wmaker-crm.git] / src / osdep_bsd.c
blob992f061799ea2afa29d790f0824fd5430d6b70fa
1 /*
2 * Until FreeBSD gets their act together;
3 * http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
4 */
5 #if defined( FREEBSD )
6 # undef _XOPEN_SOURCE
7 #endif
9 #if defined( FREEBSD ) || defined( DRAGONFLYBSD )
10 # include <sys/types.h>
11 #else /* OPENBSD || NETBSD */
12 # include <sys/param.h>
13 #endif
14 #include <sys/sysctl.h>
16 #include <assert.h>
18 #if defined( OPENBSD )
19 # include <kvm.h>
20 # include <limits.h> /* _POSIX2_LINE_MAX */
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
26 #if defined( OPENBSD )
27 # include <string.h>
28 #endif
30 #include <unistd.h>
32 #include <WINGs/WUtil.h>
34 #include "wconfig.h"
35 #include "osdep.h"
38 * copy argc and argv for an existing process identified by `pid'
39 * into suitable storage given in ***argv and *argc.
41 * subsequent calls use the same static area for argv and argc.
43 * returns 0 for failure, in which case argc := 0 and argv := NULL
44 * returns 1 for success
47 * NetBSD, FreeBSD and DragonFlyBSD supply the necessary information via
48 * sysctl(3). The result is a plain simple flat octet stream and its length.
49 * The octet stream represents argv, with members separated by a null character.
50 * The argv array returned by GetCommandForPid() consists of pointers into this
51 * stream (which is stored in a static array, `args'). Net and Free/DFly only
52 * differ slightly in the MIB vector given to sysctl(3). Free and DFly are
53 * identical.
55 * OpenBSD supplies the necessary informationvia kvm(3) in the form of a real
56 * argv array. This array is flattened to be in the same way as Net/Free/DFly
57 * returns the arguments in the first place. This is done in order for the
58 * storage (`args') to easily be made static, which means some memory bytes
59 * are sacrificed to save hoops of memory management.
61 Bool GetCommandForPid(int pid, char ***argv, int *argc)
64 * it just returns failure if the sysctl calls fail; since there's
65 * apparently no harm done to the caller because of this, it seems
66 * more user-friendly than to bomb out.
68 int j, mib[4];
69 unsigned int i;
70 size_t count;
71 static char *args = NULL;
72 static int argmax = 0;
73 #if defined( OPENBSD )
74 char kvmerr[_POSIX2_LINE_MAX]; /* for kvm*() error reporting */
75 int procs; /* kvm_getprocs() */
76 kvm_t *kd;
77 struct kinfo_proc *kp;
78 char **nargv; /* kvm_getarg() */
79 #endif
81 *argv = NULL;
82 *argc = 0;
84 /* the system-wide limit */
85 if (argmax == 0) { /* it hopefully doesn't change at runtime *g* */
86 mib[0] = CTL_KERN;
87 mib[1] = KERN_ARGMAX;
88 mib[2] = 0;
89 mib[3] = 0;
91 count = sizeof(argmax);
92 if (sysctl(mib, 2, &argmax, &count, NULL, 0) == -1)
93 return False;
96 /* if argmax is still 0, something went very seriously wrong */
97 assert( argmax > 0);
99 /* space for args; no need to free before returning even on errors */
100 if (args == NULL)
101 args = (char *)wmalloc(argmax);
103 #if defined( OPENBSD )
104 /* kvm descriptor */
105 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, kvmerr);
106 if (kd == NULL)
107 return False;
109 procs = 0;
110 /* the process we are interested in */
111 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*kp), &procs);
112 if (kp == NULL || procs == 0)
113 /* if kvm_getprocs() bombs out or does not find the process */
114 return False;
116 /* get its argv */
117 nargv = kvm_getargv(kd, kp, 0);
118 if (nargv == NULL)
119 return False;
121 /* flatten nargv into args */
122 count = 0;
123 memset(args, 0, argmax);
125 * must have this much free space in `args' in order for the current
126 * iteration not to overflow it: we are at `count', and will append
127 * the next (*argc) arg and a nul (+1)
128 * technically, overflow (or truncation, which isn't handled) can not
129 * happen (should not, at least).
131 #define ARGSPACE ( count + strlen(nargv[ (*argc) ] ) + 1 )
132 while (nargv[*argc] && ARGSPACE < argmax ) {
133 memcpy(args + count, nargv[*argc], strlen(nargv[*argc]));
134 count += strlen(nargv[*argc]) + 1;
135 (*argc)++;
137 #undef ARGSPACE
138 /* by now *argc is correct as a byproduct */
140 kvm_close(kd);
141 #else /* FREEBSD || NETBSD || DRAGONFLYBSD */
143 mib[0] = CTL_KERN;
144 #if defined( NETBSD )
145 mib[1] = KERN_PROC_ARGS;
146 mib[2] = pid;
147 mib[3] = KERN_PROC_ARGV;
148 #elif defined( FREEBSD ) || defined( DRAGONFLYBSD )
149 mib[1] = KERN_PROC;
150 mib[2] = KERN_PROC_ARGS;
151 mib[3] = pid;
152 #endif
154 count = argmax;
155 /* canary */
156 *args = 0;
157 if (sysctl(mib, 4, args, &count, NULL, 0) == -1 || *args == 0)
158 return False;
160 /* args is a flattened series of null-terminated strings */
161 for (i = 0; i < count; i++)
162 if (args[i] == '\0')
163 (*argc)++;
164 #endif
166 *argv = (char **)wmalloc(sizeof(char *) * (*argc + 1 /* term. null ptr */));
167 (*argv)[0] = args;
169 /* go through args, set argv[$next] to the beginning of each string */
170 for (i = 0, j = 1; i < count; i++) {
171 if (args[i] != '\0')
172 continue;
173 if (i < count - 1)
174 (*argv)[j++] = &args[i + 1];
175 if (j == *argc)
176 break;
179 /* the list of arguments must be terminated by a null pointer */
180 (*argv)[j] = NULL;
181 return True;