wmaker: Cleaned dangerous function prototype usage
[wmaker-crm.git] / src / osdep_bsd.c
blobe92a7c8f0d512535d1a36c4e92df48918f409b72
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 "funcs.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[4] = 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 if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, kvmerr)) == NULL)
106 return False;
108 procs = 0;
109 /* the process we are interested in */
110 if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*kp), &procs)) == NULL || procs == 0)
111 /* if kvm_getprocs() bombs out or does not find the process */
112 return False;
114 /* get its argv */
115 if ((nargv = kvm_getargv(kd, kp, 0)) == NULL)
116 return False;
118 /* flatten nargv into args */
119 count = 0;
120 memset(args, 0, argmax);
122 * must have this much free space in `args' in order for the current
123 * iteration not to overflow it: we are at `count', and will append
124 * the next (*argc) arg and a nul (+1)
125 * technically, overflow (or truncation, which isn't handled) can not
126 * happen (should not, at least).
128 #define ARGSPACE ( count + strlen(nargv[ (*argc) ] ) + 1 )
129 while (nargv[*argc] && ARGSPACE < argmax ) {
130 memcpy(args + count, nargv[*argc], strlen(nargv[*argc]));
131 count += strlen(nargv[*argc]) + 1;
132 (*argc)++;
134 #undef ARGSPACE
135 /* by now *argc is correct as a byproduct */
137 kvm_close(kd);
138 #else /* FREEBSD || NETBSD || DRAGONFLYBSD */
140 mib[0] = CTL_KERN;
141 #if defined( NETBSD )
142 mib[1] = KERN_PROC_ARGS;
143 mib[2] = pid;
144 mib[3] = KERN_PROC_ARGV;
145 #elif defined( FREEBSD ) || defined( DRAGONFLYBSD )
146 mib[1] = KERN_PROC;
147 mib[2] = KERN_PROC_ARGS;
148 mib[3] = pid;
149 #endif
151 count = argmax;
152 /* canary */
153 *args = 0;
154 if (sysctl(mib, 4, args, &count, NULL, 0) == -1 || *args == 0)
155 return False;
157 /* args is a flattened series of null-terminated strings */
158 for (i = 0; i < count; i++)
159 if (args[i] == '\0')
160 (*argc)++;
161 #endif
163 *argv = (char **)wmalloc(sizeof(char *) * (*argc + 1 /* term. null ptr */));
164 (*argv)[0] = args;
166 /* go through args, set argv[$next] to the beginning of each string */
167 for (i = 0, j = 1; i < count; i++) {
168 if (args[i] != '\0')
169 continue;
170 if (i < count - 1)
171 (*argv)[j++] = &args[i + 1];
172 if (j == *argc)
173 break;
176 /* the list of arguments must be terminated by a null pointer */
177 (*argv)[j] = NULL;
178 return True;