Bug Summary

File:obj-scan-build/procfs/../../procfs/rootdir.c
Location:line 313, column 7
Description:The left operand of '/' is a garbage value

Annotated Source Code

1/* Hurd /proc filesystem, permanent files of the root directory.
2 Copyright (C) 2010,13,14 Free Software Foundation, Inc.
3
4 This file is part of the GNU Hurd.
5
6 The GNU Hurd is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2, or (at
9 your option) any later version.
10
11 The GNU Hurd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include <mach/gnumach.h>
21#include <mach/vm_param.h>
22#include <mach/vm_statistics.h>
23#include <mach/vm_cache_statistics.h>
24#include <mach/default_pager.h>
25#include <mach_debug/mach_debug_types.h>
26#include <hurd/paths.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <sys/time.h>
31#include <sys/utsname.h>
32#include <sys/stat.h>
33#include <argz.h>
34#include <ps.h>
35#include <glob.h>
36#include "procfs.h"
37#include "procfs_dir.h"
38#include "main.h"
39
40#include "mach_debug_U.h"
41
42/* This implements a directory node with the static files in /proc.
43 NB: the libps functions for host information return static storage;
44 using them would require locking and as a consequence it would be
45 more complicated, not simpler. */
46
47
48/* Helper functions */
49
50/* We get the boot time by using that of the kernel process. */
51static error_t
52get_boottime (struct ps_context *pc, struct timeval *tv)
53{
54 struct proc_stat *ps;
55 error_t err;
56
57 err = _proc_stat_create (opt_kernel_pid, pc, &ps);
58 if (err)
59 return err;
60
61 err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC0x00040);
62 if (err || !(proc_stat_flags (ps)((ps)->flags) & PSTAT_TASK_BASIC0x00040))
63 err = EIO((0x10 << 26) | ((5) & 0x3fff));
64
65 if (! err)
66 {
67 task_basic_info_t tbi = proc_stat_task_basic_info (ps)((ps)->task_basic_info);
68 tv->tv_sec = tbi->creation_time.seconds;
69 tv->tv_usec = tbi->creation_time.microseconds;
70 }
71
72 _proc_stat_free (ps);
73 return err;
74}
75
76/* We get the idle time by querying the kernel's idle thread. */
77static error_t
78get_idletime (struct ps_context *pc, struct timeval *tv)
79{
80 struct proc_stat *ps, *pst;
81 thread_basic_info_t tbi;
82 error_t err;
83 int i;
84
85 err = _proc_stat_create (opt_kernel_pid, pc, &ps);
86 if (err)
87 return err;
88
89 pst = NULL((void*)0), tbi = NULL((void*)0);
90
91 err = proc_stat_set_flags (ps, PSTAT_NUM_THREADS0x00100);
92 if (err || !(proc_stat_flags (ps)((ps)->flags) & PSTAT_NUM_THREADS0x00100))
93 {
94 err = EIO((0x10 << 26) | ((5) & 0x3fff));
95 goto out;
96 }
97
98 /* Look for the idle thread */
99 for (i=0; !tbi || !(tbi->flags & TH_FLAGS_IDLE0x2); i++)
100 {
101 if (pst)
102 _proc_stat_free (pst);
103
104 pst = NULL((void*)0), tbi = NULL((void*)0);
105 if (i >= proc_stat_num_threads (ps)((ps)->num_threads))
106 {
107 err = ESRCH((0x10 << 26) | ((3) & 0x3fff));
108 goto out;
109 }
110
111 err = proc_stat_thread_create (ps, i, &pst);
112 if (err)
113 continue;
114
115 err = proc_stat_set_flags (pst, PSTAT_THREAD_BASIC0x00200);
116 if (err || ! (proc_stat_flags (pst)((pst)->flags) & PSTAT_THREAD_BASIC0x00200))
117 continue;
118
119 tbi = proc_stat_thread_basic_info (pst)((pst)->thread_basic_info);
120 }
121
122 /* We found it! */
123 tv->tv_sec = tbi->system_time.seconds;
124 tv->tv_usec = tbi->system_time.microseconds;
125 err = 0;
126
127out:
128 if (pst) _proc_stat_free (pst);
129 _proc_stat_free (ps);
130 return err;
131}
132
133static error_t
134get_swapinfo (default_pager_info_t *info)
135{
136 mach_port_t defpager;
137 error_t err;
138
139 defpager = file_name_lookup (_SERVERS_DEFPAGER"/servers/" "default-pager", O_READ0x0001, 0);
140 if (defpager == MACH_PORT_NULL((mach_port_t) 0))
8
Assuming 'defpager' is equal to 0
9
Taking true branch
141 return errno(*__errno_location ());
142
143 err = default_pager_info (defpager, info);
144 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), defpager);
145
146 return err;
147}
148
149
150/* Content generators */
151
152static error_t
153rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len)
154{
155 struct utsname uts;
156 int r;
157
158 r = uname (&uts);
159 if (r < 0)
160 return errno(*__errno_location ());
161
162 *contents_len = asprintf (contents,
163 "Linux version 2.6.1 (%s %s %s %s)\n",
164 uts.sysname, uts.release, uts.version, uts.machine);
165
166 return 0;
167}
168
169static error_t
170rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len)
171{
172 struct timeval time, boottime, idletime;
173 double up_secs, idle_secs;
174 error_t err;
175
176 err = gettimeofday (&time, NULL((void*)0));
177 if (err < 0)
178 return errno(*__errno_location ());
179
180 err = get_boottime (hook, &boottime);
181 if (err)
182 return err;
183
184 err = get_idletime (hook, &idletime);
185 if (err)
186 return err;
187
188 timersub (&time, &boottime, &time)do { (&time)->tv_sec = (&time)->tv_sec - (&
boottime)->tv_sec; (&time)->tv_usec = (&time)->
tv_usec - (&boottime)->tv_usec; if ((&time)->tv_usec
< 0) { --(&time)->tv_sec; (&time)->tv_usec +=
1000000; } } while (0)
;
189 up_secs = (time.tv_sec * 1000000. + time.tv_usec) / 1000000.;
190 idle_secs = (idletime.tv_sec * 1000000. + idletime.tv_usec) / 1000000.;
191
192 /* The second field is the total idle time. As far as I know we don't
193 keep track of it. However, procps uses it to compute "USER_HZ", and
194 proc(5) specifies that it should be equal to USER_HZ times the idle value
195 in ticks from /proc/stat. So we assume a completely idle system both here
196 and there to make that work. */
197 *contents_len = asprintf (contents, "%.2lf %.2lf\n", up_secs, idle_secs);
198
199 return 0;
200}
201
202static error_t
203rootdir_gc_stat (void *hook, char **contents, ssize_t *contents_len)
204{
205 struct timeval boottime, time, idletime;
206 struct vm_statistics vmstats;
207 unsigned long up_ticks, idle_ticks;
208 error_t err;
209
210 err = gettimeofday (&time, NULL((void*)0));
211 if (err < 0)
212 return errno(*__errno_location ());
213
214 err = get_boottime (hook, &boottime);
215 if (err)
216 return err;
217
218 err = get_idletime (hook, &idletime);
219 if (err)
220 return err;
221
222 err = vm_statistics (mach_task_self ()((__mach_task_self_ + 0)), &vmstats);
223 if (err)
224 return EIO((0x10 << 26) | ((5) & 0x3fff));
225
226 timersub (&time, &boottime, &time)do { (&time)->tv_sec = (&time)->tv_sec - (&
boottime)->tv_sec; (&time)->tv_usec = (&time)->
tv_usec - (&boottime)->tv_usec; if ((&time)->tv_usec
< 0) { --(&time)->tv_sec; (&time)->tv_usec +=
1000000; } } while (0)
;
227 up_ticks = opt_clk_tck * (time.tv_sec * 1000000. + time.tv_usec) / 1000000.;
228 idle_ticks = opt_clk_tck * (idletime.tv_sec * 1000000. + idletime.tv_usec) / 1000000.;
229
230 *contents_len = asprintf (contents,
231 "cpu %lu 0 0 %lu 0 0 0 0 0\n"
232 "cpu0 %lu 0 0 %lu 0 0 0 0 0\n"
233 "intr 0\n"
234 "page %d %d\n"
235 "btime %lu\n",
236 up_ticks - idle_ticks, idle_ticks,
237 up_ticks - idle_ticks, idle_ticks,
238 vmstats.pageins, vmstats.pageouts,
239 boottime.tv_sec);
240
241 return 0;
242}
243
244static error_t
245rootdir_gc_loadavg (void *hook, char **contents, ssize_t *contents_len)
246{
247 host_load_info_data_t hli;
248 mach_msg_type_number_t cnt;
249 error_t err;
250
251 cnt = HOST_LOAD_INFO_COUNT(sizeof(host_load_info_data_t)/sizeof(integer_t));
252 err = host_info (mach_host_self (), HOST_LOAD_INFO4, (host_info_t) &hli, &cnt);
253 if (err)
254 return err;
255
256 assert (cnt == HOST_LOAD_INFO_COUNT)((cnt == (sizeof(host_load_info_data_t)/sizeof(integer_t))) ?
(void) (0) : __assert_fail ("cnt == (sizeof(host_load_info_data_t)/sizeof(integer_t))"
, "../../procfs/rootdir.c", 256, __PRETTY_FUNCTION__))
;
257 *contents_len = asprintf (contents,
258 "%.2f %.2f %.2f 1/0 0\n",
259 hli.avenrun[0] / (double) LOAD_SCALE1000,
260 hli.avenrun[1] / (double) LOAD_SCALE1000,
261 hli.avenrun[2] / (double) LOAD_SCALE1000);
262
263 return 0;
264}
265
266static error_t
267rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len)
268{
269 host_basic_info_data_t hbi;
270 mach_msg_type_number_t cnt;
271 struct vm_statistics vmstats;
272 struct vm_cache_statistics cache_stats;
273 default_pager_info_t swap;
274 error_t err;
275
276 err = vm_statistics (mach_task_self ()((__mach_task_self_ + 0)), &vmstats);
277 if (err)
1
Assuming 'err' is 0
2
Taking false branch
278 return EIO((0x10 << 26) | ((5) & 0x3fff));
279
280 err = vm_cache_statistics (mach_task_self ()((__mach_task_self_ + 0)), &cache_stats);
281 if (err)
3
Assuming 'err' is 0
4
Taking false branch
282 return EIO((0x10 << 26) | ((5) & 0x3fff));
283
284 cnt = HOST_BASIC_INFO_COUNT(sizeof(host_basic_info_data_t)/sizeof(integer_t));
285 err = host_info (mach_host_self (), HOST_BASIC_INFO1, (host_info_t) &hbi, &cnt);
286 if (err)
5
Assuming 'err' is 0
6
Taking false branch
287 return err;
288
289 err = get_swapinfo (&swap);
7
Calling 'get_swapinfo'
10
Returning from 'get_swapinfo'
290 if (err)
11
Assuming 'err' is 0
12
Taking false branch
291 return err;
292
293 assert (cnt == HOST_BASIC_INFO_COUNT)((cnt == (sizeof(host_basic_info_data_t)/sizeof(integer_t))) ?
(void) (0) : __assert_fail ("cnt == (sizeof(host_basic_info_data_t)/sizeof(integer_t))"
, "../../procfs/rootdir.c", 293, __PRETTY_FUNCTION__))
;
294 *contents_len = asprintf (contents,
295 "MemTotal: %14lu kB\n"
296 "MemFree: %14lu kB\n"
297 "Buffers: %14lu kB\n"
298 "Cached: %14lu kB\n"
299 "Active: %14lu kB\n"
300 "Inactive: %14lu kB\n"
301 "Mlocked: %14lu kB\n"
302 "SwapTotal:%14lu kB\n"
303 "SwapFree: %14lu kB\n"
304 ,
305 (long unsigned) hbi.memory_size / 1024,
306 (long unsigned) vmstats.free_count * PAGE_SIZE(1 << 12) / 1024,
307 0UL,
308 (long unsigned) cache_stats.cache_count * PAGE_SIZE(1 << 12) / 1024,
309 (long unsigned) vmstats.active_count * PAGE_SIZE(1 << 12) / 1024,
310 (long unsigned) vmstats.inactive_count * PAGE_SIZE(1 << 12) / 1024,
311 (long unsigned) vmstats.wire_count * PAGE_SIZE(1 << 12) / 1024,
312 (long unsigned) swap.dpi_total_space / 1024,
313 (long unsigned) swap.dpi_free_space / 1024);
13
The left operand of '/' is a garbage value
314
315 return 0;
316}
317
318static error_t
319rootdir_gc_vmstat (void *hook, char **contents, ssize_t *contents_len)
320{
321 host_basic_info_data_t hbi;
322 mach_msg_type_number_t cnt;
323 struct vm_statistics vmstats;
324 error_t err;
325
326 err = vm_statistics (mach_task_self ()((__mach_task_self_ + 0)), &vmstats);
327 if (err)
328 return EIO((0x10 << 26) | ((5) & 0x3fff));
329
330 cnt = HOST_BASIC_INFO_COUNT(sizeof(host_basic_info_data_t)/sizeof(integer_t));
331 err = host_info (mach_host_self (), HOST_BASIC_INFO1, (host_info_t) &hbi, &cnt);
332 if (err)
333 return err;
334
335 assert (cnt == HOST_BASIC_INFO_COUNT)((cnt == (sizeof(host_basic_info_data_t)/sizeof(integer_t))) ?
(void) (0) : __assert_fail ("cnt == (sizeof(host_basic_info_data_t)/sizeof(integer_t))"
, "../../procfs/rootdir.c", 335, __PRETTY_FUNCTION__))
;
336 *contents_len = asprintf (contents,
337 "nr_free_pages %lu\n"
338 "nr_inactive_anon %lu\n"
339 "nr_active_anon %lu\n"
340 "nr_inactive_file %lu\n"
341 "nr_active_file %lu\n"
342 "nr_unevictable %lu\n"
343 "nr_mlock %lu\n"
344 "pgpgin %lu\n"
345 "pgpgout %lu\n"
346 "pgfault %lu\n",
347 (long unsigned) vmstats.free_count,
348 /* FIXME: how can we distinguish the anon/file pages? Maybe we can
349 ask the default pager how many it manages? */
350 (long unsigned) vmstats.inactive_count,
351 (long unsigned) vmstats.active_count,
352 (long unsigned) 0,
353 (long unsigned) 0,
354 (long unsigned) vmstats.wire_count,
355 (long unsigned) vmstats.wire_count,
356 (long unsigned) vmstats.pageins,
357 (long unsigned) vmstats.pageouts,
358 (long unsigned) vmstats.faults);
359
360 return 0;
361}
362
363static error_t
364rootdir_gc_cmdline (void *hook, char **contents, ssize_t *contents_len)
365{
366 struct ps_context *pc = hook;
367 struct proc_stat *ps;
368 error_t err;
369
370 err = _proc_stat_create (opt_kernel_pid, pc, &ps);
371 if (err)
372 return EIO((0x10 << 26) | ((5) & 0x3fff));
373
374 err = proc_stat_set_flags (ps, PSTAT_ARGS0x02000);
375 if (err || ! (proc_stat_flags (ps)((ps)->flags) & PSTAT_ARGS0x02000))
376 {
377 err = EIO((0x10 << 26) | ((5) & 0x3fff));
378 goto out;
379 }
380
381 *contents_len = proc_stat_args_len (ps)((ps)->args_len);
382 *contents = malloc (*contents_len);
383 if (! *contents)
384 {
385 err = ENOMEM((0x10 << 26) | ((12) & 0x3fff));
386 goto out;
387 }
388
389 memcpy (*contents, proc_stat_args (ps)((ps)->args), *contents_len);
390 argz_stringify (*contents, *contents_len, ' ');
391 (*contents)[*contents_len - 1] = '\n';
392
393out:
394 _proc_stat_free (ps);
395 return err;
396}
397
398static int
399rootdir_fakeself_exists (void *dir_hook, const void *entry_hook)
400{
401 return opt_fake_self >= 0;
402}
403
404static error_t
405rootdir_gc_fakeself (void *hook, char **contents, ssize_t *contents_len)
406{
407 *contents_len = asprintf (contents, "%d", opt_fake_self);
408 return 0;
409}
410
411static struct node *rootdir_mounts_node;
412
413static error_t
414rootdir_gc_slabinfo (void *hook, char **contents, ssize_t *contents_len)
415{
416 error_t err;
417 FILE *m;
418 const char header[] =
419 "cache obj slab bufs objs bufs"
420 " total reclaimable\n"
421 "name flags size size /slab usage count"
422 " memory memory\n";
423 cache_info_array_t cache_info;
424 size_t mem_usage, mem_reclaimable, mem_total, mem_total_reclaimable;
425 mach_msg_type_number_t cache_info_count;
426 int i;
427
428 cache_info = NULL((void*)0);
429 cache_info_count = 0;
430
431 err = host_slab_info (mach_host_self(), &cache_info, &cache_info_count);
432 if (err)
433 return err;
434
435 m = open_memstream (contents, contents_len);
436 if (m == NULL((void*)0))
437 {
438 err = ENOMEM((0x10 << 26) | ((12) & 0x3fff));
439 goto out;
440 }
441
442 fprintf (m, "%s", header);
443
444 mem_total = 0;
445 mem_total_reclaimable = 0;
446
447 for (i = 0; i < cache_info_count; i++)
448 {
449 mem_usage = (cache_info[i].nr_slabs * cache_info[i].slab_size)
450 >> 10;
451 mem_total += mem_usage;
452 mem_reclaimable = (cache_info[i].flags & CACHE_FLAGS_NO_RECLAIM0x04)
453 ? 0 : (cache_info[i].nr_free_slabs
454 * cache_info[i].slab_size) >> 10;
455 mem_total_reclaimable += mem_reclaimable;
456 fprintf (m,
457 "%-21s %04x %7zu %3zuk %4lu %6lu %6lu %7zuk %10zuk\n",
458 cache_info[i].name, cache_info[i].flags,
459 cache_info[i].obj_size, cache_info[i].slab_size >> 10,
460 cache_info[i].bufs_per_slab, cache_info[i].nr_objs,
461 cache_info[i].nr_bufs, mem_usage, mem_reclaimable);
462 }
463
464 fprintf (m, "total: %zuk, reclaimable: %zuk\n",
465 mem_total, mem_total_reclaimable);
466
467 fclose (m);
468
469 out:
470 vm_deallocate (mach_task_self ()((__mach_task_self_ + 0)),
471 cache_info, cache_info_count * sizeof *cache_info);
472 return err;
473}
474
475static error_t
476rootdir_gc_filesystems (void *hook, char **contents, ssize_t *contents_len)
477{
478 error_t err = 0;
479 size_t i;
480 int glob_ret;
481 glob_t matches;
482 FILE *m;
483
484 m = open_memstream (contents, contents_len);
485 if (m == NULL((void*)0))
486 return errno(*__errno_location ());
487
488 glob_ret = glob (_HURD"/hurd/" "*fs", 0, NULL((void*)0), &matches);
489 switch (glob_ret)
490 {
491 case 0:
492 for (i = 0; i < matches.gl_pathc; i++)
493 {
494 /* Get ith entry, shave off the prefix. */
495 char *name = &matches.gl_pathv[i][sizeof _HURD"/hurd/" - 1];
496
497 /* Linux naming convention is a bit inconsistent. */
498 if (strncmp (name, "ext", 3) == 0
499 || strcmp (name, "procfs") == 0)
500 /* Drop the fs suffix. */
501 name[strlen (name) - 2] = 0;
502
503 fprintf (m, "\t%s\n", name);
504 }
505
506 globfree (&matches);
507 break;
508
509 case GLOB_NOMATCH3:
510 /* Poor fellow. */
511 break;
512
513 case GLOB_NOSPACE1:
514 err = ENOMEM((0x10 << 26) | ((12) & 0x3fff));
515 break;
516
517 default:
518 /* This should not happen. */
519 err = EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff));
520 }
521
522 fclose (m);
523 return err;
524}
525
526/* Glue logic and entries table */
527
528static struct node *
529rootdir_file_make_node (void *dir_hook, const void *entry_hook)
530{
531 /* The entry hook we use is actually a procfs_node_ops for the file to be
532 created. The hook associated to these newly created files (and passed
533 to the generators above as a consequence) is always the same global
534 ps_context, which we get from rootdir_make_node as the directory hook. */
535 return procfs_make_node (entry_hook, dir_hook);
536}
537
538static struct node *
539rootdir_symlink_make_node (void *dir_hook, const void *entry_hook)
540{
541 struct node *np = procfs_make_node (entry_hook, dir_hook);
542 if (np)
543 procfs_node_chtype (np, S_IFLNK0120000);
544 return np;
545}
546
547/* Translator linkage. */
548
549static pthread_spinlock_t rootdir_translated_node_lock =
550 PTHREAD_SPINLOCK_INITIALIZER((__pthread_spinlock_t) 0);
551
552struct procfs_translated_node_ops
553{
554 struct procfs_node_ops node_ops;
555
556 struct node **npp;
557 char *argz;
558 size_t argz_len;
559};
560
561static struct node *
562rootdir_make_translated_node (void *dir_hook, const void *entry_hook)
563{
564 const struct procfs_translated_node_ops *ops = entry_hook;
565 struct node *np, *prev;
566
567 pthread_spin_lock (&rootdir_translated_node_lock);
568 np = *ops->npp;
569 pthread_spin_unlock (&rootdir_translated_node_lock);
570
571 if (np != NULL((void*)0))
572 {
573 netfs_nref (np);
574 return np;
575 }
576
577 np = procfs_make_node (entry_hook, entry_hook);
578 if (np == NULL((void*)0))
579 return NULL((void*)0);
580
581 procfs_node_chtype (np, S_IFREG0100000 | S_IPTRANS000010000000);
582 procfs_node_chmod (np, 0444);
583
584 pthread_spin_lock (&rootdir_translated_node_lock);
585 prev = *ops->npp;
586 if (*ops->npp == NULL((void*)0))
587 *ops->npp = np;
588 pthread_spin_unlock (&rootdir_translated_node_lock);
589
590 if (prev != NULL((void*)0))
591 {
592 procfs_cleanup (np);
593 np = prev;
594 }
595
596 return np;
597}
598
599static error_t
600rootdir_translated_node_get_translator (void *hook, char **argz,
601 size_t *argz_len)
602{
603 const struct procfs_translated_node_ops *ops = hook;
604
605 *argz = malloc (ops->argz_len);
606 if (! *argz)
607 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
608
609 memcpy (*argz, ops->argz, ops->argz_len);
610 *argz_len = ops->argz_len;
611 return 0;
612}
613
614#define ROOTDIR_DEFINE_TRANSLATED_NODE(NPP, ARGZ)&(struct procfs_translated_node_ops) { .node_ops = { .get_translator
= rootdir_translated_node_get_translator, }, .npp = NPP, .argz
= (ARGZ), .argz_len = sizeof (ARGZ), }
\
615 &(struct procfs_translated_node_ops) { \
616 .node_ops = { \
617 .get_translator = rootdir_translated_node_get_translator, \
618 }, \
619 .npp = NPP, \
620 .argz = (ARGZ), \
621 .argz_len = sizeof (ARGZ), \
622 }
623
624static const struct procfs_dir_entry rootdir_entries[] = {
625 {
626 .name = "self",
627 .hook = & (struct procfs_node_ops) {
628 .get_contents = rootdir_gc_fakeself,
629 .cleanup_contents = procfs_cleanup_contents_with_free,
630 },
631 .ops = {
632 .make_node = rootdir_symlink_make_node,
633 .exists = rootdir_fakeself_exists,
634 }
635 },
636 {
637 .name = "version",
638 .hook = & (struct procfs_node_ops) {
639 .get_contents = rootdir_gc_version,
640 .cleanup_contents = procfs_cleanup_contents_with_free,
641 },
642 },
643 {
644 .name = "uptime",
645 .hook = & (struct procfs_node_ops) {
646 .get_contents = rootdir_gc_uptime,
647 .cleanup_contents = procfs_cleanup_contents_with_free,
648 },
649 },
650 {
651 .name = "stat",
652 .hook = & (struct procfs_node_ops) {
653 .get_contents = rootdir_gc_stat,
654 .cleanup_contents = procfs_cleanup_contents_with_free,
655 },
656 },
657 {
658 .name = "loadavg",
659 .hook = & (struct procfs_node_ops) {
660 .get_contents = rootdir_gc_loadavg,
661 .cleanup_contents = procfs_cleanup_contents_with_free,
662 },
663 },
664 {
665 .name = "meminfo",
666 .hook = & (struct procfs_node_ops) {
667 .get_contents = rootdir_gc_meminfo,
668 .cleanup_contents = procfs_cleanup_contents_with_free,
669 },
670 },
671 {
672 .name = "vmstat",
673 .hook = & (struct procfs_node_ops) {
674 .get_contents = rootdir_gc_vmstat,
675 .cleanup_contents = procfs_cleanup_contents_with_free,
676 },
677 },
678 {
679 .name = "cmdline",
680 .hook = & (struct procfs_node_ops) {
681 .get_contents = rootdir_gc_cmdline,
682 .cleanup_contents = procfs_cleanup_contents_with_free,
683 },
684 },
685 {
686 .name = "mounts",
687 .hook = ROOTDIR_DEFINE_TRANSLATED_NODE (&rootdir_mounts_node,&(struct procfs_translated_node_ops) { .node_ops = { .get_translator
= rootdir_translated_node_get_translator, }, .npp = &rootdir_mounts_node
, .argz = ("/hurd/" "mtab" "\0/"), .argz_len = sizeof ("/hurd/"
"mtab" "\0/"), }
688 _HURD_MTAB "\0/")&(struct procfs_translated_node_ops) { .node_ops = { .get_translator
= rootdir_translated_node_get_translator, }, .npp = &rootdir_mounts_node
, .argz = ("/hurd/" "mtab" "\0/"), .argz_len = sizeof ("/hurd/"
"mtab" "\0/"), }
,
689 .ops = {
690 .make_node = rootdir_make_translated_node,
691 }
692 },
693 {
694 .name = "slabinfo",
695 .hook = & (struct procfs_node_ops) {
696 .get_contents = rootdir_gc_slabinfo,
697 .cleanup_contents = procfs_cleanup_contents_with_free,
698 },
699 },
700 {
701 .name = "filesystems",
702 .hook = & (struct procfs_node_ops) {
703 .get_contents = rootdir_gc_filesystems,
704 .cleanup_contents = procfs_cleanup_contents_with_free,
705 },
706 },
707#ifdef PROFILE
708 /* In order to get a usable gmon.out file, we must apparently use exit(). */
709 {
710 .name = "exit",
711 .ops = {
712 .make_node = exit,
713 },
714 },
715#endif
716 {}
717};
718
719struct node
720*rootdir_make_node (struct ps_context *pc)
721{
722 static const struct procfs_dir_ops ops = {
723 .entries = rootdir_entries,
724 .entry_ops = {
725 .make_node = rootdir_file_make_node,
726 },
727 };
728 return procfs_dir_make_node (&ops, pc);
729}
730