1 /* Copyright (C) 2007 Joe Marcus Clarke
2 This file is part of LibGTop 2.
3
4 LibGTop is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License,
7 or (at your option) any later version.
8
9 LibGTop is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with LibGTop; see the file COPYING. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include <config.h>
21 #include <glibtop/procwd.h>
22 #include <glibtop/error.h>
23
24 #include <glibtop_private.h>
25
26 #include <sys/types.h>
27 #include <sys/sysctl.h>
28 #include <sys/param.h>
29 #include <sys/user.h>
30 #ifdef HAVE_KINFO_GETFILE
31 #include <libutil.h>
32 #endif
33 #include <string.h>
34
35 static const unsigned long _glibtop_sysdeps_proc_wd =
36 (1 << GLIBTOP_PROC_WD_EXE) |
37 (1 << GLIBTOP_PROC_WD_ROOT) |
38 (1 << GLIBTOP_PROC_WD_NUMBER);
39
40 void
_glibtop_init_proc_wd_s(glibtop * server)41 _glibtop_init_proc_wd_s(glibtop *server)
42 {
43 server->sysdeps.proc_wd = _glibtop_sysdeps_proc_wd;
44 }
45
46 #if (__FreeBSD_version >= 800000 && __FreeBSD_version < 800019) || __FreeBSD_version < 700104
47 static GPtrArray *
parse_output(const char * output,glibtop_proc_wd * buf)48 parse_output(const char *output, glibtop_proc_wd *buf)
49 {
50 GPtrArray *dirs;
51 char **lines;
52 gboolean nextwd = FALSE;
53 gboolean nextrtd = FALSE;
54 gboolean havertd = FALSE;
55 guint i;
56 guint len;
57
58 dirs = g_ptr_array_sized_new(1);
59
60 lines = g_strsplit(output, "\n", 0);
61 len = g_strv_length(lines);
62
63 for (i = 0; i < len && lines[i]; i++) {
64 if (strlen(lines[i]) < 2)
65 continue;
66
67 if (!strcmp(lines[i], "fcwd")) {
68 nextwd = TRUE;
69 continue;
70 }
71
72 if (!strcmp(lines[i], "frtd")) {
73 nextrtd = TRUE;
74 continue;
75 }
76
77 if (!g_str_has_prefix(lines[i], "n"))
78 continue;
79
80 if (nextwd) {
81 g_ptr_array_add(dirs, g_strdup(lines[i] + 1));
82 nextwd = FALSE;
83 }
84
85 if (nextrtd && !havertd) {
86 g_strlcpy(buf->root, lines[i] + 1,
87 sizeof(buf->root));
88 buf->flags |= (1 << GLIBTOP_PROC_WD_ROOT);
89 nextrtd = FALSE;
90 havertd = TRUE;
91 }
92 }
93
94 g_strfreev(lines);
95
96 return dirs;
97 }
98 #endif
99
100 char**
glibtop_get_proc_wd_s(glibtop * server,glibtop_proc_wd * buf,pid_t pid)101 glibtop_get_proc_wd_s(glibtop *server, glibtop_proc_wd *buf, pid_t pid)
102 {
103 int exe_mib[4];
104 size_t len;
105 #if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
106 struct kinfo_file *freep, *kif;
107 GPtrArray *dirs;
108 #ifndef HAVE_KINFO_GETFILE
109 int name[4];
110 #else
111 int cnt;
112 #endif
113 int i;
114 #else
115 char *output;
116 #endif
117
118 memset (buf, 0, sizeof (glibtop_proc_wd));
119 len = 0;
120
121 exe_mib[0] = CTL_KERN;
122 exe_mib[1] = KERN_PROC;
123 exe_mib[2] = KERN_PROC_PATHNAME;
124 exe_mib[3] = pid;
125
126 if (sysctl(exe_mib, 4, NULL, &len, NULL, 0) == 0) {
127 if (len > sizeof(buf->exe))
128 len = sizeof(buf->exe);
129 if (sysctl(exe_mib, 4, buf->exe, &len, NULL, 0) == 0)
130 buf->flags |= (1 << GLIBTOP_PROC_WD_EXE);
131 }
132
133 #if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
134 #ifndef HAVE_KINFO_GETFILE
135 len = 0;
136 name[0] = CTL_KERN;
137 name[1] = KERN_PROC;
138 name[2] = KERN_PROC_FILEDESC;
139 name[3] = pid;
140
141 if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
142 return NULL;
143 freep = kif = g_malloc(len);
144 if (sysctl(name, 4, kif, &len, NULL, 0) < 0) {
145 g_free(freep);
146 return NULL;
147 }
148 #else
149 freep = kinfo_getfile(pid, &cnt);
150 #endif
151
152 dirs = g_ptr_array_sized_new(1);
153
154 #ifndef HAVE_KINFO_GETFILE
155 for (i = 0; i < len / sizeof(*kif); i++, kif++) {
156 if (kif->kf_structsize != sizeof(*kif))
157 continue;
158 #else
159 for (i = 0; i < cnt; i++) {
160 kif = &freep[i];
161 #endif
162
163 switch (kif->kf_fd) {
164 case KF_FD_TYPE_ROOT:
165 g_strlcpy(buf->root, kif->kf_path,
166 sizeof(buf->root));
167 buf->flags |= (1 << GLIBTOP_PROC_WD_ROOT);
168 break;
169 case KF_FD_TYPE_CWD:
170 g_ptr_array_add(dirs, g_strdup (kif->kf_path));
171 break;
172 }
173 }
174 g_free(freep);
175
176 buf->number = dirs->len;
177 buf->flags |= (1 << GLIBTOP_PROC_WD_NUMBER);
178
179 g_ptr_array_add(dirs, NULL);
180
181 return (char **)g_ptr_array_free(dirs, FALSE);
182 #else
183 output = execute_lsof(pid);
184 if (output != NULL) {
185 GPtrArray *dirs;
186
187 dirs = parse_output(output, buf);
188 g_free(output);
189
190 buf->number = dirs->len;
191 buf->flags |= (1 << GLIBTOP_PROC_WD_NUMBER);
192
193 g_ptr_array_add(dirs, NULL);
194
195 return (char **)g_ptr_array_free(dirs, FALSE);
196 }
197 #endif
198
199 return NULL;
200 }
201