11
11
#include <string.h>
12
12
#include <sys/stat.h>
13
13
#include <unistd.h>
14
+ #include <dirent.h>
14
15
15
16
#include "globals.h"
16
17
#include "meminfo.h"
17
18
#include "msg.h"
18
19
#include "proc_pid.h"
20
+ #include "utils.h"
19
21
20
22
/* Parse the contents of /proc/meminfo (in buf), return value of "name"
21
23
* (example: "MemTotal:")
@@ -269,6 +271,101 @@ int get_uid(int pid)
269
271
return (int )st .st_uid ;
270
272
}
271
273
274
+ static int get_process_statm (char * buf , size_t buf_size , int pid )
275
+ {
276
+ char path [PATH_LEN ] = { 0 };
277
+ snprintf (path , sizeof (path ), "%s/%d/statm" , procdir_path , pid );
278
+
279
+ FILE * f = fopen (path , "r" );
280
+ if (!f ) {
281
+ debug ("%s: failed to open file '%s': %s\n" , __func__ , path , strerror (errno ));
282
+ return - EINVAL ;
283
+ }
284
+
285
+ char * res = fgets (buf , (int )buf_size , f );
286
+ fclose (f );
287
+ if (!res ) {
288
+ debug ("%s: failed to read statm info for pid=%d\n" , __func__ , pid );
289
+ return - EINVAL ;
290
+ }
291
+
292
+ return 0 ;
293
+ }
294
+
295
+ static void dump_all_process_meminfo (int __attribute__((format (printf , 1 , 2 ))) (* out_func )(const char * fmt , ...))
296
+ {
297
+ DIR * procdir = opendir (procdir_path );
298
+ if (procdir == NULL ) {
299
+ fatal (5 , "%s: could not open /proc: %s" , __func__ , strerror (errno ));
300
+ }
301
+
302
+ static size_t page_size ;
303
+ if (page_size == 0 ) {
304
+ page_size = (size_t )sysconf (_SC_PAGESIZE );
305
+ if (page_size <= 0 ) {
306
+ fatal (1 , "could not read page size\n" );
307
+ }
308
+ }
309
+
310
+ char * statm = calloc (1 , page_size );
311
+ if (!statm ) {
312
+ debug ("%s: failed to allocate memory\n" , __func__ );
313
+ return ;
314
+ }
315
+
316
+ out_func ("===========================\n" );
317
+ out_func ("Dump all processes statm info. More details: Documentation/filesystems/proc.txt\n" );
318
+ out_func ("%%proc (%%pid): %%size %%resident %%shared %%trs %%trs %%drs %%dt\n" );
319
+
320
+ while (1 ) {
321
+ errno = 0 ;
322
+ struct dirent * d = readdir (procdir );
323
+ if (d == NULL ) {
324
+ if (errno != 0 )
325
+ warn ("%s: readdir error: %s\n" , __func__ , strerror (errno ));
326
+ break ;
327
+ }
328
+
329
+ // proc contains lots of directories not related to processes,
330
+ // skip them
331
+ if (!isnumeric (d -> d_name ))
332
+ continue ;
333
+
334
+ errno = 0 ;
335
+ int pid = (int )strtol (d -> d_name , NULL , 10 );
336
+ if (errno != 0 ) {
337
+ warn ("%s: strtol() failed: %s\n" , __func__ , strerror (errno ));
338
+ continue ;
339
+ }
340
+
341
+ // Skip kthreads
342
+ pid_stat_t stat ;
343
+ if (!parse_proc_pid_stat (& stat , pid ))
344
+ continue ;
345
+
346
+ if (stat .rss <= 0 )
347
+ continue ;
348
+
349
+ int ret = get_process_statm (statm , page_size , pid );
350
+ if (ret < 0 )
351
+ continue ;
352
+
353
+ char name [PATH_LEN ] = { 0 };
354
+ ret = get_comm (pid , name , sizeof (name ));
355
+ if (ret < 0 ) {
356
+ debug ("pid %d: error reading process name: %s\n" , pid , strerror (- ret ));
357
+ continue ;
358
+ }
359
+
360
+ out_func ("%s (%d): %s" , name , pid , statm );
361
+ }
362
+
363
+ free (statm );
364
+ closedir (procdir );
365
+
366
+ out_func ("===========================\n" );
367
+ }
368
+
272
369
/* Print a status line like
273
370
* mem avail: 5259 MiB (67 %), swap free: 0 MiB (0 %)"
274
371
* as an informational message to stdout (default), or
@@ -283,4 +380,6 @@ void print_mem_stats(int __attribute__((format(printf, 1, 2))) (*out_func)(const
283
380
m .SwapFreeKiB / 1024 ,
284
381
m .SwapTotalKiB / 1024 ,
285
382
m .SwapFreePercent );
383
+
384
+ dump_all_process_meminfo (out_func );
286
385
}
0 commit comments