3 #include <sys/sysctl.h>
6 #include <sys/pledge.h>
19 // TODO: envv: not idx, but envar name
21 #define MY_KERN_PROC KERN_PROC_KTHREAD
26 int(*read)(struct kinfo_proc *, char *, size_t, off_t);
30 int(*read)(struct kinfo_file *, char *, size_t, off_t);
57 parse_path(const char *path, struct path *p)
62 memset(p, 0, sizeof (*p));
64 if (strcmp(path, "/") == 0) {
67 } else if (sscanf(path, "/%d%n", &p->pid, &num) == 1) {
70 if (*suffix == '\0') {
73 } else if (strncmp(suffix, "/argv", 5) == 0) {
76 p->type = PATH_PID_ARGV;
78 } else if (sscanf(suffix, "/%d%n", &p->num, &num) == 1) {
79 p->type = PATH_PID_ARGV_NUM;
84 } else if (strncmp(suffix, "/envv", 5) == 0) {
87 p->type = PATH_PID_ENVV;
89 } else if (strchr(suffix + 1, '/') == NULL) {
90 p->type = PATH_PID_ENVV_NAME;
96 } else if (strncmp(suffix, "/fd", 3) == 0) {
99 p->type = PATH_PID_FD;
101 } else if (sscanf(suffix, "/%d%n", &p->fd, &num) == 1) {
104 p->type = PATH_PID_FD_NUM;
122 fs_readdir(const char *path, void *data, fuse_fill_dir_t filler,
123 off_t off, struct fuse_file_info *ffi)
129 printf("readdir(%s, off=%u);\n", path, (unsigned int)off);
131 if (strcmp(path, "/") == 0) {
132 struct kinfo_proc *kp;
135 kp = kvm_getprocs(kd, MY_KERN_PROC, 0, sizeof(*kp), &nentries);
137 warnx("readdir(/): %s", kvm_geterr(kd));
141 filler(data, ".", NULL, 0);
142 filler(data, "..", NULL, 0);
143 for (int i = 0; i < nentries; ++i) {
145 snprintf (str, sizeof(str), "%d", kp[i].p_pid);
146 filler(data, str, NULL, 0);
149 } else if (sscanf(path, "/%d%n", &pid, &num) == 1) {
150 const char *suffix = path + num;
151 struct kinfo_proc *kp;
155 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*kp), &nentries);
156 if (kp == NULL || nentries == 0) {
157 warnx("readdir(%s): %s", path, kvm_geterr(kd));
159 } else if (nentries > 1) {
160 warnx("readdir(%s): Too many results", path);
164 if (strcmp(suffix, "") == 0) {
165 filler(data, ".", NULL, 0);
166 filler(data, "..", NULL, 0);
167 filler(data, "parent", NULL, 0);
168 filler(data, "argv", NULL, 0);
169 filler(data, "envv", NULL, 0);
170 filler(data, "fd", NULL, 0);
171 for (const struct myfile *f = files; f->name != NULL; ++f)
172 filler(data, f->name + 1, NULL, 0);
174 } else if (strcmp(suffix, "/argv") == 0) {
175 char **argv = kvm_getargv(kd, kp, 0);
178 warnx("readdir(%s): %s", path, kvm_geterr(kd));
182 filler(data, ".", NULL, 0);
183 filler(data, "..", NULL, 0);
184 for (size_t i = 0; argv[i] != NULL; ++i) {
188 n = snprintf(buffer, sizeof (buffer), "%zu", i);
189 assert(n < (int)sizeof (buffer));
191 filler(data, buffer, NULL, 0);
194 } else if (strcmp(suffix, "/envv") == 0) {
195 char **envv = kvm_getenvv(kd, kp, 0);
198 warnx("readdir(%s): %s", path, kvm_geterr(kd));
202 filler(data, ".", NULL, 0);
203 filler(data, "..", NULL, 0);
204 for (size_t i = 0; envv[i] != NULL; ++i) {
208 n = snprintf(buffer, sizeof (buffer), "%zu", i);
209 assert(n < (int)sizeof (buffer));
211 filler(data, buffer, NULL, 0);
214 } else if (strcmp(suffix, "/fd") == 0) {
215 struct kinfo_file *files;
217 files = kvm_getfiles (kd, KERN_FILE_BYPID, pid, sizeof (*files), &nentries);
220 warnx("readdir(%s): %s", path, kvm_geterr(kd));
224 filler(data, ".", NULL, 0);
225 filler(data, "..", NULL, 0);
227 printf("nentries = %d\n", nentries);
229 for (int i = 0; i < nentries; ++i) {
231 snprintf(buffer, sizeof (buffer), "%d", i);
232 filler(data, buffer, NULL, 0);
236 } else if (sscanf(suffix, "/fd/%u%n", &idx, &num) == 1) {
237 struct kinfo_file *files;
240 files = kvm_getfiles(kd, KERN_FILE_BYPID, pid, sizeof (*files), &nentries);
242 warnx("readdir(%s): %s", path, kvm_geterr(kd));
246 if (idx >= (unsigned int)nentries)
249 if (strcmp(suffix, "") == 0) {
250 filler(data, ".", NULL, 0);
251 filler(data, "..", NULL, 0);
252 for (const struct myfdfile *f = fd_files; f->name != NULL; ++f) {
253 filler(data, f->name + 1, NULL, 0);
257 for (const struct myfdfile *f = fd_files; f->name != NULL; ++f) {
258 if (strcmp(suffix, f->name) == 0)
264 for (const struct myfile *f = files; f->name != NULL; ++f) {
265 if (strcmp(suffix, f->name) == 0)
281 struct fuse_file_info *ffi
287 printf("read(%s);\n", path);
289 if (strcmp(path, "/") == 0) {
291 } else if (sscanf(path, "/%d%n", &pid, &num) == 1) {
292 const char *suffix = path + num;
293 struct kinfo_proc *kp;
297 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof (*kp), &nentries);
298 if (kp == NULL || nentries == 0) {
299 warnx("read(%s): %s", path, kvm_geterr(kd));
301 } else if (nentries > 1) {
302 warnx("read(%s): Too many results", path);
306 if (strcmp(suffix, "") == 0) {
308 } else if (strcmp(suffix, "/argv") == 0) {
310 } else if (sscanf(suffix, "/argv/%u%n", &idx, &num) == 1) {
313 if (suffix[num] != '\0')
316 argv = kvm_getargv(kd, kp, 0);
318 warnx("read(%s): %s", path, kvm_geterr(kd));
322 for (nentries = 0; argv[nentries] != NULL; ++nentries);
324 if (idx > (unsigned int)nentries)
327 return copy_str(argv[idx], strlen(argv[idx]), buf, off, size);
328 } else if (strcmp(suffix, "/envv") == 0) {
330 } else if (sscanf(suffix, "/envv/%u%n", &idx, &num) == 1) {
333 if (suffix[num] != '\0')
336 envv = kvm_getenvv(kd, kp, 0);
338 warnx("read(%s): %s", path, kvm_geterr(kd));
342 for (nentries = 0; envv[nentries] != NULL; ++nentries);
344 if (idx > (unsigned int)nentries)
347 return copy_str(envv[idx], strlen(envv[idx]), buf, off, size);
348 } else if (sscanf(suffix, "/fd/%u%n", &idx, &num) == 1) {
349 struct kinfo_file *files;
352 files = kvm_getfiles(kd, KERN_FILE_BYPID, pid, sizeof (*files), &nentries);
354 warnx("read(%s): %s", path, kvm_geterr(kd));
358 if (idx >= (unsigned int)nentries)
361 if (strcmp(suffix, "") == 0) {
364 for (const struct myfdfile *f = fd_files; f->name != NULL; ++f) {
365 if (strcmp(suffix, f->name) == 0)
366 return f->read(&files[idx], buf, size, off);
371 for (const struct myfile *f = files; f->name != NULL; ++f) {
372 if (strcmp(suffix, f->name) == 0)
373 return f->read(kp, buf, size, off);
383 fs_open(const char *path, struct fuse_file_info *ffi)
389 printf("open(%s);\n", path);
391 if (strcmp(path, "/") == 0) {
393 } else if (sscanf(path, "/%d%n", &pid, &num) == 1) {
394 const char *suffix = path + num;
395 struct kinfo_proc *kp;
400 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof (*kp), &nentries);
401 if (kp == NULL || nentries == 0) {
402 warnx("open(%s): %s", path, kvm_geterr(kd));
404 } else if (nentries > 1) {
405 warnx("open(%s): Too many results", path);
409 if (strcmp(suffix, "/argv") == 0) {
411 } else if (sscanf(suffix, "/argv/%u%n", &idx, &num) == 1) {
412 if (suffix[num] != '\0')
415 } else if (strcmp(suffix, "/envv") == 0) {
417 } else if (sscanf(suffix, "/envv/%u%n", &idx, &num) == 1) {
418 if (suffix[num] != '\0')
421 } else if (sscanf(suffix, "/fd/%u%n", &idx, &num) == 1) {
423 if (strcmp(suffix, "") == 0) {
427 for (const struct myfdfile *f = fd_files; f->name != NULL; ++f) {
428 if (strcmp(suffix, f->name) == 0) {
434 printf("Invalid fd suffix: '%s'\n", suffix);
441 for (const struct myfile *f = files; f->name != NULL; ++f) {
442 if (strcmp(suffix, f->name) == 0) {
448 printf("Invalid suffix: '%s'\n", suffix);
459 fs_getattr(const char *path, struct stat *st)
463 printf("getattr(%s);\n", path);
465 st->st_blksize = 512;
467 if (strcmp(path, "/") == 0) {
468 st->st_mode = S_IFDIR | 0755;
472 } else if (sscanf(path, "/%d%n", &pid, &num) == 1) {
473 const char *suffix = path + num;
474 struct kinfo_proc *kp;
478 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof (*kp), &nentries);
479 if (kp == NULL || nentries == 0) {
480 warnx("getattr(%s): %s", path, kvm_geterr(kd));
482 } else if (nentries > 1) {
483 warnx("getattr(%s): Too many results", path);
487 if (strcmp(suffix, "") == 0) {
488 st->st_mode = S_IFDIR | 0755;
492 } else if (strcmp(suffix, "/parent") == 0) {
493 st->st_mode = S_IFLNK | 0755;
495 st->st_size = snprintf(NULL, 0, "%d", kp->p_ppid);
497 } else if (strcmp(suffix, "/argv") == 0) {
498 st->st_mode = S_IFDIR | 0755;
502 } else if (sscanf(suffix, "/argv/%u%n", &idx, &num) == 1) {
505 if (suffix[num] != '\0')
508 argv = kvm_getargv(kd, kp, 0);
510 warnx("getattr(%s): %s", path, kvm_geterr(kd));
514 for (nentries = 0; argv[nentries] != NULL; ++nentries);
515 if (idx >= (unsigned int)nentries)
518 st->st_mode = S_IFREG | 0644;
520 st->st_size = strlen(argv[idx]);
522 } else if (strcmp(suffix, "/envv") == 0) {
523 st->st_mode = S_IFDIR | 0755;
527 } else if (sscanf(suffix, "/envv/%u%n", &idx, &num) == 1) {
530 if (suffix[num] != '\0')
533 envv = kvm_getenvv(kd, kp, 0);
535 warnx("getattr(%s): %s", path, kvm_geterr(kd));
539 for (nentries = 0; envv[nentries] != NULL; ++nentries);
540 if (idx >= (unsigned int)nentries)
543 st->st_mode = S_IFREG | 0644;
545 st->st_size = strlen(envv[idx]);
547 } else if (strcmp(suffix, "/fd") == 0) {
548 st->st_mode = S_IFDIR | 0755;
552 } else if (sscanf(suffix, "/fd/%u%n", &idx, &num) == 1) {
553 struct kinfo_file *files;
556 files = kvm_getfiles(kd, KERN_FILE_BYPID, pid, sizeof (*files), &nentries);
558 warnx("getattr(%s): %s", path, kvm_geterr(kd));
562 if (strcmp(suffix, "") == 0) {
563 st->st_mode = S_IFDIR | 0755;
568 for (const struct myfdfile *f = fd_files; f->name != NULL; ++f) {
569 if (strcmp(suffix, f->name) == 0) {
570 st->st_mode = S_IFREG | 0644;
579 for (const struct myfile *f = files; f->name != NULL; ++f) {
580 if (strcmp(suffix, f->name) == 0) {
581 st->st_mode = S_IFREG;
595 fs_readlink(const char *path, char *buf, size_t size)
599 if (sscanf(path, "/%d%n", &pid, &num) == 1) {
600 const char *suffix = path + num;
601 struct kinfo_proc *kp;
604 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof (*kp), &nentries);
605 if (kp == NULL || nentries == 0) {
606 warnx("readlink(%s): %s", path, kvm_geterr(kd));
608 } else if (nentries > 1) {
609 warnx("readlink(%s): Too many results", path);
613 if (strcmp(suffix, "/parent") == 0) {
614 snprintf(buf, size, "../%d", kp->p_ppid);
624 struct fuse_operations fsops = {
625 .readdir = fs_readdir,
628 .getattr = fs_getattr,
629 .readlink = fs_readlink,
633 main(int argc, char **argv)
635 char errbuf[_POSIX2_LINE_MAX];
636 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
638 errx(1, "%s", errbuf);
640 return (fuse_main(argc, argv, &fsops, NULL));