1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*  Fluent Bit
4  *  ==========
5  *  Copyright (C) 2019-2021 The Fluent Bit Authors
6  *  Copyright (C) 2015-2018 Treasure Data Inc.
7  *
8  *  Licensed under the Apache License, Version 2.0 (the "License");
9  *  you may not use this file except in compliance with the License.
10  *  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *  Unless required by applicable law or agreed to in writing, software
15  *  distributed under the License is distributed on an "AS IS" BASIS,
16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *  See the License for the specific language governing permissions and
18  *  limitations under the License.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 
26 #include <fluent-bit/flb_input.h>
27 #include "proc.h"
28 
human_readable_size(long size)29 static char *human_readable_size(long size)
30 {
31     long u = 1024, i, len = 128;
32     char *buf;
33     static const char *__units[] = { "b", "K", "M", "G",
34                                      "T", "P", "E", "Z", "Y", NULL
35     };
36 
37     buf = flb_malloc(len);
38     if (!buf) {
39         flb_errno();
40         return NULL;
41     }
42 
43     for (i = 0; __units[i] != NULL; i++) {
44         if ((size / u) == 0) {
45             break;
46         }
47         u *= 1024;
48     }
49     if (!i) {
50         snprintf(buf, len, "%ld %s", size, __units[0]);
51     }
52     else {
53         float fsize = (float) ((double) size / (u / 1024));
54         snprintf(buf, len, "%.2f%s", fsize, __units[i]);
55     }
56 
57     return buf;
58 }
59 
60 /* Read file content into a memory buffer */
file_to_buffer(const char * path)61 static char *file_to_buffer(const char *path)
62 {
63     FILE *fp;
64     char *buffer;
65 
66     if (!(fp = fopen(path, "r"))) {
67         flb_errno();
68         return NULL;
69     }
70 
71     buffer = flb_calloc(1, PROC_STAT_BUF_SIZE);
72     if (!buffer) {
73         fclose(fp);
74         flb_errno();
75         return NULL;
76     }
77 
78     fread(buffer, PROC_STAT_BUF_SIZE, 1, fp);
79     if (ferror(fp) || !feof(fp)) {
80         flb_free(buffer);
81         fclose(fp);
82         return NULL;
83     }
84 
85     fclose(fp);
86     return buffer;
87 }
88 
89 
proc_stat(pid_t pid,int page_size)90 struct proc_task *proc_stat(pid_t pid, int page_size)
91 {
92     int ret;
93     char *p, *q;
94     char *buf;
95     char pid_path[PROC_PID_SIZE];
96     struct proc_task *t;
97 
98     t = flb_calloc(1, sizeof(struct proc_task));
99     if (!t) {
100         flb_errno();
101         return NULL;
102     }
103 
104     /* Compose path for /proc/PID/stat */
105     ret = snprintf(pid_path, PROC_PID_SIZE, "/proc/%i/stat", pid);
106     if (ret < 0) {
107         flb_free(t);
108         flb_errno();
109         return NULL;
110     }
111 
112     buf = file_to_buffer(pid_path);
113     if (!buf) {
114         flb_free(t);
115         return NULL;
116     }
117 
118     sscanf(buf, "%d", &t->pid);
119 
120     /*
121      * workaround for process with spaces in the name, so we dont screw up
122      * sscanf(3).
123      */
124     p = buf;
125     while (*p != '(') {
126         p++;
127     }
128     p++;
129 
130     /* seek from tail of file.  */
131     q = buf + (PROC_STAT_BUF_SIZE - 1);
132     while (*q != ')' && p < q) {
133         q--;
134     }
135     if (p >= q) {
136         flb_free(buf);
137         flb_free(t);
138         return NULL;
139     }
140 
141     strncpy(t->comm, p, q - p);
142     q += 2;
143 
144     /* Read pending values */
145     sscanf(q, PROC_STAT_FORMAT,
146            &t->state,
147            &t->ppid,
148            &t->pgrp,
149            &t->session,
150            &t->tty_nr,
151            &t->tpgid,
152            &t->flags,
153            &t->minflt,
154            &t->cminflt,
155            &t->majflt,
156            &t->cmajflt,
157            &t->utime,
158            &t->stime,
159            &t->cutime,
160            &t->cstime,
161            &t->priority,
162            &t->nice,
163            &t->num_threads,
164            &t->itrealvalue,
165            &t->starttime,
166            &t->vsize,
167            &t->rss);
168 
169     /* Internal conversion */
170     t->proc_rss    = (t->rss * page_size);
171     t->proc_rss_hr = human_readable_size(t->proc_rss);
172     if ( t->proc_rss_hr == NULL ) {
173         flb_free(buf);
174         flb_free(t);
175         return NULL;
176     }
177 
178     flb_free(buf);
179     return t;
180 }
181 
proc_free(struct proc_task * t)182 void proc_free(struct proc_task *t)
183 {
184     flb_free(t->proc_rss_hr);
185     flb_free(t);
186 }
187