Revert "Prevent windows from drifting on restart."
[wmaker-crm.git] / src / osdep_bsd.c
blobdbcdf9e2663281d78b728d47169b3fc5289e5a15
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"
37 * copy argc and argv for an existing process identified by `pid'
38 * into suitable storage given in ***argv and *argc.
40 * subsequent calls use the same static area for argv and argc.
42 * returns 0 for failure, in which case argc := 0 and argv := NULL
43 * returns 1 for success
46 * NetBSD, FreeBSD and DragonFlyBSD supply the necessary information via
47 * sysctl(3). The result is a plain simple flat octet stream and its length.
48 * The octet stream represents argv, with members separated by a null character.
49 * The argv array returned by GetCommandForPid() consists of pointers into this
50 * stream (which is stored in a static array, `args'). Net and Free/DFly only
51 * differ slightly in the MIB vector given to sysctl(3). Free and DFly are
52 * identical.
54 * OpenBSD supplies the necessary informationvia kvm(3) in the form of a real
55 * argv array. This array is flattened to be in the same way as Net/Free/DFly
56 * returns the arguments in the first place. This is done in order for the
57 * storage (`args') to easily be made static, which means some memory bytes
58 * are sacrificed to save hoops of memory management.
60 Bool GetCommandForPid(int pid, char ***argv, int *argc)
63 * it just returns failure if the sysctl calls fail; since there's
64 * apparently no harm done to the caller because of this, it seems
65 * more user-friendly than to bomb out.
67 int j, mib[4];
68 unsigned int i;
69 size_t count;
70 static char *args = NULL;
71 static int argmax = 0;
72 #if defined( OPENBSD )
73 char kvmerr[_POSIX2_LINE_MAX]; /* for kvm*() error reporting */
74 int procs; /* kvm_getprocs() */
75 kvm_t *kd;
76 struct kinfo_proc *kp;
77 char **nargv; /* kvm_getarg() */
78 #endif
80 *argv = NULL;
81 *argc = 0;
83 /* the system-wide limit */
84 if (argmax == 0) { /* it hopefully doesn't change at runtime *g* */
85 mib[0] = CTL_KERN;
86 mib[1] = KERN_ARGMAX;
87 mib[2] = 0;
88 mib[4] = 0;
90 count = sizeof(argmax);
91 if (sysctl(mib, 2, &argmax, &count, NULL, 0) == -1)
92 return False;
95 /* if argmax is still 0, something went very seriously wrong */
96 assert( argmax > 0);
98 /* space for args; no need to free before returning even on errors */
99 if (args == NULL)
100 args = (char *)wmalloc(argmax);
102 #if defined( OPENBSD )
103 /* kvm descriptor */
104 if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, kvmerr)) == NULL)
105 return False;
107 procs = 0;
108 /* the process we are interested in */
109 if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*kp), &procs)) == NULL || procs == 0)
110 /* if kvm_getprocs() bombs out or does not find the process */
111 return False;
113 /* get its argv */
114 if ((nargv = kvm_getargv(kd, kp, 0)) == NULL)
115 return False;
117 /* flatten nargv into args */
118 count = 0;
119 memset(args, 0, argmax);
121 * must have this much free space in `args' in order for the current
122 * iteration not to overflow it: we are at `count', and will append
123 * the next (*argc) arg and a nul (+1)
124 * technically, overflow (or truncation, which isn't handled) can not
125 * happen (should not, at least).
127 #define ARGSPACE ( count + strlen(nargv[ (*argc) ] ) + 1 )
128 while (nargv[*argc] && ARGSPACE < argmax ) {
129 memcpy(args + count, nargv[*argc], strlen(nargv[*argc]));
130 count += strlen(nargv[*argc]) + 1;
131 (*argc)++;
133 #undef ARGSPACE
134 /* by now *argc is correct as a byproduct */
136 kvm_close(kd);
137 #else /* FREEBSD || NETBSD || DRAGONFLYBSD */
139 mib[0] = CTL_KERN;
140 #if defined( NETBSD )
141 mib[1] = KERN_PROC_ARGS;
142 mib[2] = pid;
143 mib[3] = KERN_PROC_ARGV;
144 #elif defined( FREEBSD ) || defined( DRAGONFLYBSD )
145 mib[1] = KERN_PROC;
146 mib[2] = KERN_PROC_ARGS;
147 mib[3] = pid;
148 #endif
150 count = argmax;
151 /* canary */
152 *args = 0;
153 if (sysctl(mib, 4, args, &count, NULL, 0) == -1 || *args == 0)
154 return False;
156 /* args is a flattened series of null-terminated strings */
157 for (i = 0; i < count; i++)
158 if (args[i] == '\0')
159 (*argc)++;
160 #endif
162 *argv = (char **)wmalloc(sizeof(char *) * (*argc + 1 /* term. null ptr */));
163 (*argv)[0] = args;
165 /* go through args, set argv[$next] to the beginning of each string */
166 for (i = 0, j = 1; i < count; i++) {
167 if (args[i] != '\0')
168 continue;
169 if (i < count - 1)
170 (*argv)[j++] = &args[i + 1];
171 if (j == *argc)
172 break;
175 /* the list of arguments must be terminated by a null pointer */
176 (*argv)[j] = NULL;
177 return True;