1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9 #define __RT_IPC_SOURCE__
10
11 #include "proc.h"
12 #include "procfs.h"
13
14 #include <rthw.h>
15 #include <rtdbg.h>
16
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #include "lwp_internal.h"
21 #include <dfs_dentry.h>
22 #include "lwp_internal.h"
23
24 #if defined(RT_USING_SMART)
25
26 #include "lwp.h"
27 #include "lwp_pid.h"
28 #include <lwp_user_mm.h>
29
30 struct pid_dentry
31 {
32 const char *name;
33 mode_t mode;
34 const struct dfs_file_ops *fops;
35 const struct proc_ops *ops;
36 const struct dfs_seq_ops *seq_ops;
37 int (*single_show)(struct dfs_seq_file *seq, void *data);
38 void *data;
39 };
40
stat_transform(int __stat)41 static char stat_transform(int __stat)
42 {
43 switch (__stat)
44 {
45 case RT_THREAD_RUNNING:
46 return 'R';
47 default:
48 return 'T';
49 }
50 }
51
stat_single_show(struct dfs_seq_file * seq,void * data)52 static int stat_single_show(struct dfs_seq_file *seq, void *data)
53 {
54 struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
55 rt_list_t *list;
56 int mask = 0;
57 rt_thread_t thread;
58 rt_uint64_t user_time_lwp = 0;
59 rt_uint64_t system_time_lwp = 0;
60 int lwp_oncpu = RT_CPUS_NR;
61 int lwp_oncpu_ok = 0;
62 struct rt_lwp *lwp = RT_NULL;
63 char** argv = RT_NULL;
64 char *filename = RT_NULL;
65 char *dot = RT_NULL;
66
67 lwp_pid_lock_take();
68
69 lwp = lwp_from_pid_locked(dentry->pid);
70 argv = lwp_get_command_line_args(lwp);
71
72 if (lwp)
73 {
74 dfs_seq_printf(seq,"%d ",dentry->pid);
75 if (argv)
76 {
77 filename = strrchr(argv[0], '/');
78 dot = strchr(argv[0], '.');
79
80 if (filename != NULL)
81 {
82 filename++;
83 }
84 else
85 {
86 filename = argv[0];
87 }
88
89 if (dot != NULL)
90 {
91 *dot = '\0';
92 }
93
94 if (filename != NULL)
95 {
96 dfs_seq_printf(seq,"(%s) ", filename);
97 }
98 else
99 {
100 dfs_seq_printf(seq,"(%s) ", argv[0]);
101 }
102
103 lwp_free_command_line_args(argv);
104 }
105 else
106 {
107 dfs_seq_printf(seq,"(%s) ", "");
108 }
109
110 if (lwp->terminated)
111 {
112 dfs_seq_printf(seq,"%c ",'Z');
113 }
114 else
115 {
116 list = lwp->t_grp.next;
117 while (list != &lwp->t_grp)
118 {
119 thread = rt_list_entry(list, struct rt_thread, sibling);
120 user_time_lwp = user_time_lwp + thread->user_time;
121 system_time_lwp = system_time_lwp + thread->system_time;
122
123 #if RT_CPUS_NR > 1
124 #define ONCPU(thread) RT_SCHED_CTX(thread).oncpu
125 #else
126 #define ONCPU(thread) 0
127 #endif
128 if (lwp_oncpu_ok == 0)
129 {
130 lwp_oncpu = ONCPU(thread);
131 lwp_oncpu_ok = 1;
132 }
133 if (stat_transform(RT_SCHED_CTX(thread).stat) == 'R')
134 {
135 lwp_oncpu = ONCPU(thread);
136 mask = 1;
137 }
138 list = list->next;
139 }
140
141 if (mask == 1)
142 {
143 dfs_seq_printf(seq,"%c ",'R');
144 }
145 else
146 {
147 dfs_seq_printf(seq,"%c ",'S');
148 }
149 }
150 lwp_pid_lock_release();
151
152 if (lwp->parent != NULL)
153 dfs_seq_printf(seq,"%d ",lwp->parent->pid);
154 else
155 dfs_seq_printf(seq,"0 ");
156
157 dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 ");
158 dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime
159 dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime
160 dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 ");
161 dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ
162 dfs_seq_printf(seq, "1422 18446744073709551615 ");
163 dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 ");
164 dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU
165 dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0");
166 dfs_seq_printf(seq,"\n");
167 }
168 else
169 {
170 lwp_pid_lock_release();
171 }
172
173 return 0;
174 }
175
cmdline_single_show(struct dfs_seq_file * seq,void * data)176 static int cmdline_single_show(struct dfs_seq_file *seq, void *data)
177 {
178 struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
179 struct rt_lwp *lwp;
180 char** argv;
181
182 lwp_pid_lock_take();
183 lwp = lwp_from_pid_locked(dentry->pid);
184 argv = lwp_get_command_line_args(lwp);
185 lwp_pid_lock_release();
186
187 if (argv)
188 {
189 for (int i = 0; argv[i] != NULL; i++)
190 {
191 dfs_seq_printf(seq, "%s ", argv[i]);
192 }
193 dfs_seq_puts(seq, "\n");
194
195 lwp_free_command_line_args(argv);
196 }
197 else
198 {
199 dfs_seq_puts(seq, "error\n");
200 }
201
202 return 0;
203 }
204
proc_pid_fd_lookup(struct proc_dentry * parent,const char * name)205 struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name)
206 {
207 struct proc_dentry *dentry = RT_NULL;
208 char num[DIRENT_NAME_MAX];
209 struct rt_lwp *lwp;
210 struct dfs_fdtable *table;
211
212 lwp_pid_lock_take();
213 lwp = lwp_from_pid_locked(parent->pid);
214 table = lwp ? &lwp->fdt : RT_NULL;
215 lwp_pid_lock_release();
216
217 if (!table)
218 {
219 return RT_NULL;
220 }
221
222 dfs_file_lock();
223 for (int i = 0; i < table->maxfd; i++)
224 {
225 struct dfs_file *file = table->fds[i];
226 if (file)
227 {
228 rt_snprintf(num, DIRENT_NAME_MAX, "%d", i);
229 if (rt_strcmp(num, name) == 0)
230 {
231 dentry = rt_calloc(1, sizeof(struct proc_dentry));
232 if (dentry)
233 {
234 dentry->mode = (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH));
235 dentry->ref_count = 1;
236 dentry->name = rt_strdup(name);
237 dentry->data = (void *)dfs_dentry_full_path(file->dentry);
238
239 if (dentry->data == RT_NULL)
240 {
241 //todo add vnode->data
242 if (file->vnode->type == FT_SOCKET)
243 dentry->data = (void *)rt_strdup("socket");
244 else if (file->vnode->type == FT_USER)
245 dentry->data = (void *)rt_strdup("user");
246 else if (file->vnode->type == FT_DEVICE)
247 dentry->data = (void *)rt_strdup("device");
248 else
249 dentry->data = (void *)rt_strdup("unknown");
250 }
251
252 dentry->pid = parent->pid;
253 break;
254 }
255 }
256 }
257 }
258 dfs_file_unlock();
259
260 return dentry;
261 }
262
proc_pid_fd_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)263 int proc_pid_fd_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
264 {
265 int ret = 0, index = 0;
266 struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
267 struct rt_lwp *lwp;
268 struct dfs_fdtable *table;
269
270 lwp_pid_lock_take();
271 lwp = lwp_from_pid_locked(entry->pid);
272 LWP_LOCK(lwp);
273 table = lwp ? &lwp->fdt : RT_NULL;
274
275 if (!table->fds)
276 {
277 LWP_UNLOCK(lwp);
278 lwp_pid_lock_release();
279 return 0;
280 }
281
282 count = (count / sizeof(struct dirent));
283 if (count == 0)
284 {
285 LWP_UNLOCK(lwp);
286 lwp_pid_lock_release();
287 return -EINVAL;
288 }
289
290 dfs_file_lock();
291 for (int i = 0; i < table->maxfd; i++)
292 {
293 struct dfs_file *df = table->fds[i];
294 if (df)
295 {
296 if (index >= file->fpos)
297 {
298 struct dirent *d = dirp + index - file->fpos;
299
300 d->d_type = DT_SYMLINK;
301 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
302 rt_snprintf(d->d_name, DIRENT_NAME_MAX, "%d", i);
303 d->d_namlen = rt_strlen(d->d_name);
304
305 ret++;
306 }
307
308 index++;
309 if (index - file->fpos >= count)
310 {
311 break;
312 }
313 }
314 }
315 dfs_file_unlock();
316 LWP_UNLOCK(lwp);
317 lwp_pid_lock_release();
318
319 if (ret > 0)
320 {
321 file->fpos = index;
322 ret = ret * sizeof(struct dirent);
323 }
324
325 return ret;
326 }
327
328 static const struct proc_ops proc_pid_fd_ops = {
329 .lookup = proc_pid_fd_lookup,
330 };
331
332 static const struct dfs_file_ops proc_pid_fd_fops = {
333 .getdents = proc_pid_fd_getdents,
334 };
335
proc_pid_exe_readlink(struct proc_dentry * dentry,char * buf,int len)336 int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len)
337 {
338 struct rt_lwp *lwp;
339
340 lwp = lwp_self();
341 len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null");
342
343 return len;
344 }
345
346 static const struct proc_ops proc_pid_exe_ops = {
347 .readlink = proc_pid_exe_readlink,
348 };
349
proc_pid_cwd_readlink(struct proc_dentry * dentry,char * buf,int len)350 int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len)
351 {
352 struct rt_lwp *lwp;
353
354 lwp = lwp_self();
355 len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null");
356
357 return len;
358 }
359
360 static const struct proc_ops proc_pid_cwd_ops = {
361 .readlink = proc_pid_cwd_readlink,
362 };
363
364 static struct pid_dentry pid_dentry_base[] = {
365 {"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0},
366 {"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0},
367 {"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0},
368 {"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0},
369 {"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"},
370 {"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0},
371 };
372
proc_pid(int pid)373 int proc_pid(int pid)
374 {
375 char pid_str[64] = {0};
376 struct proc_dentry *dentry;
377
378 rt_snprintf(pid_str, 64, "%d", pid);
379 pid_str[63] = 0;
380
381 dentry = proc_mkdir(pid_str, 0);
382 if (dentry)
383 {
384 struct proc_dentry *ent;
385
386 dentry->pid = pid;
387 for (int j = 0; j < sizeof(pid_dentry_base) / sizeof(struct pid_dentry); j++)
388 {
389 if (S_ISDIR(pid_dentry_base[j].mode))
390 {
391 ent = proc_mkdir_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
392 pid_dentry_base[j].fops, pid_dentry_base[j].data);
393 }
394 else if (S_ISLNK(pid_dentry_base[j].mode))
395 {
396 if (pid_dentry_base[j].data == RT_NULL)
397 {
398 pid_dentry_base[j].data = "NULL";
399 }
400
401 ent = proc_symlink(pid_dentry_base[j].name, dentry, pid_dentry_base[j].data);
402 }
403 else
404 {
405 ent = proc_create_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
406 pid_dentry_base[j].fops, pid_dentry_base[j].data);
407 }
408
409 if (ent)
410 {
411 if (pid_dentry_base[j].ops)
412 {
413 ent->ops = pid_dentry_base[j].ops;
414 }
415
416 if (pid_dentry_base[j].seq_ops)
417 {
418 ent->seq_ops = pid_dentry_base[j].seq_ops;
419 }
420
421 if (pid_dentry_base[j].single_show)
422 {
423 ent->single_show = pid_dentry_base[j].single_show;
424 }
425
426 proc_release(ent);
427 }
428 }
429 proc_release(dentry);
430 }
431
432 return 0;
433 }
434
msh_proc_pid(int argc,char ** argv)435 int msh_proc_pid(int argc, char **argv)
436 {
437 if (argc > 1)
438 {
439 for (int i = 1; i <= argc - 1; i++)
440 {
441 proc_pid(atoi(argv[i]));
442 }
443 }
444
445 return 0;
446 }
447 MSH_CMD_EXPORT_ALIAS(msh_proc_pid, proc_pid, proc pid);
448
449 #endif
450