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