PatchworkOS  dbbdc99
A non-POSIX operating system.
Loading...
Searching...
No Matches
procfs.c
Go to the documentation of this file.
1#include <_libstd/MAX_NAME.h>
2#include <kernel/fs/procfs.h>
3
4#include <kernel/fs/ctl.h>
5#include <kernel/fs/dentry.h>
6#include <kernel/fs/file.h>
8#include <kernel/fs/mount.h>
10#include <kernel/fs/path.h>
12#include <kernel/fs/vfs.h>
13#include <kernel/fs/vnode.h>
14#include <kernel/log/log.h>
15#include <kernel/log/panic.h>
16#include <kernel/proc/process.h>
17#include <kernel/sched/sched.h>
18#include <kernel/sched/thread.h>
19#include <kernel/sync/lock.h>
20
21#include <assert.h>
22#include <errno.h>
23#include <kernel/sync/rcu.h>
24#include <stdatomic.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/fs.h>
28#include <sys/list.h>
29
31{
32 process_t* current = process_current();
33 assert(current != NULL);
34 process_t* process = dentry->vnode->data;
35 assert(process != NULL);
36
37 namespace_t* currentNs = process_get_ns(current);
38 if (currentNs == NULL)
39 {
40 return ERR;
41 }
42 UNREF_DEFER(currentNs);
43
44 namespace_t* processNs = process_get_ns(process);
45 if (processNs == NULL)
46 {
47 return ERR;
48 }
49 UNREF_DEFER(processNs);
50
51 if (!namespace_accessible(currentNs, processNs))
52 {
53 errno = ENOENT;
54 return ERR;
55 }
56
57 return 0;
58}
59
63
64static size_t procfs_prio_read(file_t* file, void* buffer, size_t count, size_t* offset)
65{
66 process_t* process = file->vnode->data;
67
68 priority_t priority = atomic_load(&process->priority);
69
70 char prioStr[MAX_NAME];
71 uint32_t length = snprintf(prioStr, MAX_NAME, "%llu", priority);
72 return BUFFER_READ(buffer, count, offset, prioStr, length);
73}
74
75static size_t procfs_prio_write(file_t* file, const void* buffer, size_t count, size_t* offset)
76{
78
79 process_t* process = file->vnode->data;
80
81 char prioStr[MAX_NAME];
82 if (count >= MAX_NAME)
83 {
84 errno = EINVAL;
85 return ERR;
86 }
87
88 memcpy(prioStr, buffer, count);
89 prioStr[count] = '\0';
90
91 long long int prio = atoll(prioStr);
92 if (prio < 0)
93 {
94 errno = EINVAL;
95 return ERR;
96 }
97 if (prio > PRIORITY_MAX_USER)
98 {
99 errno = EACCES;
100 return ERR;
101 }
102
103 atomic_store(&process->priority, prio);
104 return count;
105}
106
109 .write = procfs_prio_write,
110};
111
112static size_t procfs_cwd_read(file_t* file, void* buffer, size_t count, size_t* offset)
113{
114 process_t* process = file->vnode->data;
115
116 namespace_t* ns = process_get_ns(process);
117 if (ns == NULL)
118 {
119 return ERR;
120 }
121 UNREF_DEFER(ns);
122
123 path_t cwd = cwd_get(&process->cwd, ns);
124 PATH_DEFER(&cwd);
125
126 pathname_t cwdName;
127 if (path_to_name(&cwd, &cwdName) == ERR)
128 {
129 return ERR;
130 }
131
132 size_t length = strlen(cwdName.string);
133 return BUFFER_READ(buffer, count, offset, cwdName.string, length);
134}
135
136static size_t procfs_cwd_write(file_t* file, const void* buffer, size_t count, size_t* offset)
137{
138 UNUSED(offset);
139
140 process_t* process = file->vnode->data;
141
142 char cwdStr[MAX_PATH];
143 if (count >= MAX_PATH)
144 {
145 errno = EINVAL;
146 return ERR;
147 }
148
149 memcpy(cwdStr, buffer, count);
150 cwdStr[count] = '\0';
151
152 pathname_t cwdPathname;
153 if (pathname_init(&cwdPathname, cwdStr) == ERR)
154 {
155 return ERR;
156 }
157
158 namespace_t* ns = process_get_ns(process);
159 if (ns == NULL)
160 {
161 return ERR;
162 }
163 UNREF_DEFER(ns);
164
165 path_t path = cwd_get(&process->cwd, ns);
166 PATH_DEFER(&path);
167
168 if (path_walk(&path, &cwdPathname, ns) == ERR)
169 {
170 return ERR;
171 }
172
173 if (!DENTRY_IS_POSITIVE(path.dentry))
174 {
175 errno = ENOENT;
176 return ERR;
177 }
178
179 if (!DENTRY_IS_DIR(path.dentry))
180 {
181 errno = ENOTDIR;
182 return ERR;
183 }
184
185 cwd_set(&process->cwd, &path);
186 return count;
187}
188
191 .write = procfs_cwd_write,
192};
193
194static size_t procfs_cmdline_read(file_t* file, void* buffer, size_t count, size_t* offset)
195{
196 process_t* process = file->vnode->data;
197
198 if (process->argv == NULL || process->argc == 0)
199 {
200 return 0;
201 }
202
203 size_t totalSize = 0;
204 for (uint64_t i = 0; i < process->argc; i++)
205 {
206 totalSize += strlen(process->argv[i]) + 1;
207 }
208
209 if (totalSize == 0)
210 {
211 return 0;
212 }
213
214 char* cmdline = malloc(totalSize);
215 if (cmdline == NULL)
216 {
217 errno = ENOMEM;
218 return ERR;
219 }
220
221 char* dest = cmdline;
222 for (uint64_t i = 0; i < process->argc; i++)
223 {
224 uint64_t len = strlen(process->argv[i]) + 1;
225 memcpy(dest, process->argv[i], len);
226 dest += len;
227 }
228
229 size_t result = BUFFER_READ(buffer, count, offset, cmdline, totalSize);
230 free(cmdline);
231 return result;
232}
233
237
238static size_t procfs_note_write(file_t* file, const void* buffer, size_t count, size_t* offset)
239{
240 UNUSED(offset);
241
242 if (count == 0)
243 {
244 return 0;
245 }
246
247 if (count >= NOTE_MAX)
248 {
249 errno = EINVAL;
250 return ERR;
251 }
252
253 process_t* process = file->vnode->data;
254
256
257 thread_t* thread = process_rcu_first_thread(process);
258 if (thread == NULL)
259 {
260 errno = EINVAL;
261 return ERR;
262 }
263
264 char string[NOTE_MAX] = {0};
265 memcpy_s(string, NOTE_MAX, buffer, count);
266 if (thread_send_note(thread, string) == ERR)
267 {
268 return ERR;
269 }
270
271 return count;
272}
273
276};
277
278static size_t procfs_notegroup_write(file_t* file, const void* buffer, size_t count, size_t* offset)
279{
280 UNUSED(offset);
281
282 if (count == 0)
283 {
284 return 0;
285 }
286
287 if (count >= NOTE_MAX)
288 {
289 errno = EINVAL;
290 return ERR;
291 }
292 process_t* process = file->vnode->data;
293
294 char string[NOTE_MAX] = {0};
295 memcpy_s(string, NOTE_MAX, buffer, count);
296 if (group_send_note(&process->group, string) == ERR)
297 {
298 return ERR;
299 }
300
301 return count;
302}
303
307
309{
310 process_t* process = file->vnode->data;
311
312 group_t* group = group_get(&process->group);
313 if (group == NULL)
314 {
315 return ERR;
316 }
317
318 file->data = group;
319 return 0;
320}
321
322static void procfs_group_close(file_t* file)
323{
324 group_t* group = file->data;
325 if (group == NULL)
326 {
327 return;
328 }
329
330 UNREF(group);
331 file->data = NULL;
332}
333
336 .close = procfs_group_close,
337};
338
339static size_t procfs_pid_read(file_t* file, void* buffer, size_t count, size_t* offset)
340{
341 process_t* process = file->vnode->data;
342
343 char pidStr[MAX_NAME];
344 uint32_t length = snprintf(pidStr, MAX_NAME, "%llu", process->id);
345 return BUFFER_READ(buffer, count, offset, pidStr, length);
346}
347
350};
351
352static size_t procfs_wait_read(file_t* file, void* buffer, size_t count, size_t* offset)
353{
354 process_t* process = file->vnode->data;
355
356 if (WAIT_BLOCK(&process->dyingQueue, atomic_load(&process->flags) & PROCESS_DYING) == ERR)
357 {
358 return ERR;
359 }
360
361 lock_acquire(&process->status.lock);
362 size_t result = BUFFER_READ(buffer, count, offset, process->status.buffer, strlen(process->status.buffer));
363 lock_release(&process->status.lock);
364 return result;
365}
366
368{
369 process_t* process = file->vnode->data;
370 if (atomic_load(&process->flags) & PROCESS_DYING)
371 {
372 *revents |= POLLIN;
373 return &process->dyingQueue;
374 }
375
376 return &process->dyingQueue;
377}
378
381 .poll = procfs_wait_poll,
382};
383
384static size_t procfs_perf_read(file_t* file, void* buffer, size_t count, size_t* offset)
385{
386 process_t* process = file->vnode->data;
387 size_t userPages = space_user_page_count(&process->space);
388
390
391 size_t threadCount = process_rcu_thread_count(process);
392
393 clock_t userClocks = atomic_load(&process->perf.userClocks);
394 clock_t kernelClocks = atomic_load(&process->perf.kernelClocks);
395 clock_t startTime = process->perf.startTime;
396
397 char statStr[MAX_PATH];
398 int length = snprintf(statStr, sizeof(statStr),
399 "user_clocks %llu\nkernel_sched_clocks %llu\nstart_clocks %llu\nuser_pages %llu\nthread_count %llu", userClocks,
400 kernelClocks, startTime, userPages, threadCount);
401 if (length < 0)
402 {
403 errno = EIO;
404 return ERR;
405 }
406
407 return BUFFER_READ(buffer, count, offset, statStr, (size_t)length);
408}
409
412};
413
415{
416 process_t* process = file->vnode->data;
417
418 namespace_t* ns = process_get_ns(process);
419 if (ns == NULL)
420 {
421 return ERR;
422 }
423
424 file->data = ns;
425 return 0;
426}
427
428static void procfs_ns_close(file_t* file)
429{
430 if (file->data == NULL)
431 {
432 return;
433 }
434
435 UNREF(file->data);
436 file->data = NULL;
437}
438
441 .close = procfs_ns_close,
442};
443
444static uint64_t procfs_ctl_close(file_t* file, uint64_t argc, const char** argv)
445{
446 if (argc != 2 && argc != 3)
447 {
448 errno = EINVAL;
449 return ERR;
450 }
451
452 process_t* process = file->vnode->data;
453
454 if (argc == 2)
455 {
456 fd_t fd;
457 if (sscanf(argv[1], "%lld", &fd) != 1)
458 {
459 errno = EINVAL;
460 return ERR;
461 }
462
463 if (file_table_close(&process->fileTable, fd) == ERR)
464 {
465 return ERR;
466 }
467 }
468 else
469 {
470 fd_t minFd;
471 if (sscanf(argv[1], "%lld", &minFd) != 1)
472 {
473 errno = EINVAL;
474 return ERR;
475 }
476
477 fd_t maxFd;
478 if (sscanf(argv[2], "%lld", &maxFd) != 1)
479 {
480 errno = EINVAL;
481 return ERR;
482 }
483
484 if (file_table_close_range(&process->fileTable, minFd, maxFd) == ERR)
485 {
486 return ERR;
487 }
488 }
489
490 return 0;
491}
492
493static uint64_t procfs_ctl_dup2(file_t* file, uint64_t argc, const char** argv)
494{
495 if (argc != 3)
496 {
497 errno = EINVAL;
498 return ERR;
499 }
500
501 process_t* process = file->vnode->data;
502
503 fd_t oldFd;
504 if (sscanf(argv[1], "%lld", &oldFd) != 1)
505 {
506 errno = EINVAL;
507 return ERR;
508 }
509
510 fd_t newFd;
511 if (sscanf(argv[2], "%lld", &newFd) != 1)
512 {
513 errno = EINVAL;
514 return ERR;
515 }
516
517 if (file_table_dup2(&process->fileTable, oldFd, newFd) == ERR)
518 {
519 return ERR;
520 }
521
522 return 0;
523}
524
525static uint64_t procfs_ctl_bind(file_t* file, uint64_t argc, const char** argv)
526{
527 if (argc != 3)
528 {
529 errno = EINVAL;
530 return ERR;
531 }
532
533 process_t* process = file->vnode->data;
534 process_t* writing = process_current();
535
536 pathname_t targetName;
537 if (pathname_init(&targetName, argv[1]) == ERR)
538 {
539 return ERR;
540 }
541
542 namespace_t* processNs = process_get_ns(process);
543 if (processNs == NULL)
544 {
545 return ERR;
546 }
547 UNREF_DEFER(processNs);
548
549 path_t target = cwd_get(&process->cwd, processNs);
550 PATH_DEFER(&target);
551
552 if (path_walk(&target, &targetName, processNs) == ERR)
553 {
554 return ERR;
555 }
556
557 pathname_t sourceName;
558 if (pathname_init(&sourceName, argv[2]) == ERR)
559 {
560 return ERR;
561 }
562
563 namespace_t* writingNs = process_get_ns(writing);
564 if (writingNs == NULL)
565 {
566 return ERR;
567 }
568 UNREF_DEFER(writingNs);
569
570 path_t source = cwd_get(&writing->cwd, writingNs);
572
573 if (path_walk(&source, &sourceName, writingNs) == ERR)
574 {
575 return ERR;
576 }
577
578 mount_t* mount = namespace_bind(processNs, &target, &source, targetName.mode);
579 if (mount == NULL)
580 {
581 return ERR;
582 }
583 UNREF(mount);
584 return 0;
585}
586
587static uint64_t procfs_ctl_mount(file_t* file, uint64_t argc, const char** argv)
588{
589 if (argc != 3 && argc != 4)
590 {
591 errno = EINVAL;
592 return ERR;
593 }
594
595 process_t* writing = process_current();
596 process_t* process = file->vnode->data;
597
598 pathname_t mountname;
599 if (pathname_init(&mountname, argv[1]) == ERR)
600 {
601 return ERR;
602 }
603
604 namespace_t* ns = process_get_ns(process);
605 if (ns == NULL)
606 {
607 return ERR;
608 }
609 UNREF_DEFER(ns);
610
611 path_t mountpath = cwd_get(&process->cwd, ns);
612 PATH_DEFER(&mountpath);
613
614 if (path_walk(&mountpath, &mountname, ns) == ERR)
615 {
616 return ERR;
617 }
618
619 filesystem_t* fs = filesystem_get_by_path(argv[2], writing);
620 if (fs == NULL)
621 {
622 return ERR;
623 }
624
625 const char* options = (argc == 4) ? argv[3] : NULL;
626 mount_t* mount = namespace_mount(ns, &mountpath, fs, options, mountname.mode, NULL);
627 if (mount == NULL)
628 {
629 return ERR;
630 }
631 UNREF(mount);
632 return 0;
633}
634
635static uint64_t procfs_ctl_touch(file_t* file, uint64_t argc, const char** argv)
636{
637 if (argc != 2)
638 {
639 errno = EINVAL;
640 return ERR;
641 }
642
643 process_t* process = file->vnode->data;
644
645 pathname_t pathname;
646 if (pathname_init(&pathname, argv[1]) == ERR)
647 {
648 return ERR;
649 }
650
651 file_t* touch = vfs_open(&pathname, process);
652 if (touch == NULL)
653 {
654 return ERR;
655 }
656 UNREF(touch);
657 return 0;
658}
659
660static uint64_t procfs_ctl_start(file_t* file, uint64_t argc, const char** argv)
661{
662 UNUSED(argv);
663
664 if (argc != 1)
665 {
666 errno = EINVAL;
667 return ERR;
668 }
669
670 process_t* process = file->vnode->data;
671
672 atomic_fetch_and(&process->flags, ~PROCESS_SUSPENDED);
674
675 return 0;
676}
677
678static uint64_t procfs_ctl_kill(file_t* file, uint64_t argc, const char** argv)
679{
680 UNUSED(argv);
681
682 process_t* process = file->vnode->data;
683
684 if (argc == 2)
685 {
686 process_kill(process, argv[1]);
687 return 0;
688 }
689
690 process_kill(process, "killed");
691
692 return 0;
693}
694
695static uint64_t procfs_ctl_setns(file_t* file, uint64_t argc, const char** argv)
696{
697 if (argc != 2)
698 {
699 errno = EINVAL;
700 return ERR;
701 }
702
703 process_t* process = file->vnode->data;
704
705 fd_t fd;
706 if (sscanf(argv[1], "%llu", &fd) != 1)
707 {
708 errno = EINVAL;
709 return ERR;
710 }
711
712 file_t* nsFile = file_table_get(&process->fileTable, fd);
713 if (nsFile == NULL)
714 {
715 return ERR;
716 }
717 UNREF_DEFER(nsFile);
718
719 if (nsFile->ops != &nsOps)
720 {
721 errno = EINVAL;
722 return ERR;
723 }
724
725 namespace_t* ns = nsFile->data;
726 if (ns == NULL)
727 {
728 errno = EINVAL;
729 return ERR;
730 }
731
732 process_set_ns(process, ns);
733 return 0;
734}
735
736static uint64_t procfs_ctl_setgroup(file_t* file, uint64_t argc, const char** argv)
737{
738 if (argc != 2)
739 {
740 errno = EINVAL;
741 return ERR;
742 }
743
744 process_t* process = file->vnode->data;
745
746 fd_t fd;
747 if (sscanf(argv[1], "%llu", &fd) != 1)
748 {
749 errno = EINVAL;
750 return ERR;
751 }
752
753 file_t* groupFile = file_table_get(&process->fileTable, fd);
754 if (groupFile == NULL)
755 {
756 return ERR;
757 }
758 UNREF_DEFER(groupFile);
759
760 if (groupFile->ops != &groupOps)
761 {
762 errno = EINVAL;
763 return ERR;
764 }
765
766 group_t* target = groupFile->data;
767 if (target == NULL)
768 {
769 errno = EINVAL;
770 return ERR;
771 }
772
773 group_add(target, &process->group);
774 return 0;
775}
776
778 {
779 {"close", procfs_ctl_close, 2, 3},
780 {"dup2", procfs_ctl_dup2, 3, 3},
781 {"bind", procfs_ctl_bind, 3, 3},
782 {"mount", procfs_ctl_mount, 3, 4},
783 {"touch", procfs_ctl_touch, 2, 2},
784 {"start", procfs_ctl_start, 1, 1},
785 {"kill", procfs_ctl_kill, 1, 2},
786 {"setns", procfs_ctl_setns, 2, 2},
787 {"setgroup", procfs_ctl_setgroup, 2, 2},
788 {0},
789 })
790
791static size_t procfs_env_read(file_t* file, void* buffer, size_t count, size_t* offset)
792{
793 process_t* process = file->vnode->data;
794
795 const char* value = env_get(&process->env, file->path.dentry->name);
796 if (value == NULL)
797 {
798 return 0;
799 }
800
801 size_t length = strlen(value);
802 return BUFFER_READ(buffer, count, offset, value, length);
803}
804
805static size_t procfs_env_write(file_t* file, const void* buffer, size_t count, size_t* offset)
806{
807 UNUSED(offset);
808
809 process_t* process = file->vnode->data;
810
811 char value[MAX_NAME];
812 if (count >= MAX_NAME)
813 {
814 errno = EINVAL;
815 return ERR;
816 }
817
818 memcpy(value, buffer, count);
819 value[count] = '\0';
820
821 if (env_set(&process->env, file->path.dentry->name, value) == ERR)
822 {
823 return ERR;
824 }
825
826 return count;
827}
828
830 .read = procfs_env_read,
831 .write = procfs_env_write,
832};
833
835{
836 UNUSED(target);
837
838 process_t* process = dir->data;
839 assert(process != NULL);
840
841 if (env_get(&process->env, target->name) == NULL)
842 {
843 return 0;
844 }
845
847 if (vnode == NULL)
848 {
849 return ERR;
850 }
851 UNREF_DEFER(vnode);
852 vnode->data = process; // No reference
853
854 dentry_make_positive(target, vnode);
855
856 return 0;
857}
858
860{
861 if (mode & MODE_DIRECTORY)
862 {
863 errno = EINVAL;
864 return ERR;
865 }
866
867 process_t* process = dir->data;
868 assert(process != NULL);
869
870 if (env_set(&process->env, target->name, "") == ERR)
871 {
872 return ERR;
873 }
874
876 if (vnode == NULL)
877 {
878 return ERR;
879 }
880 UNREF_DEFER(vnode);
881 vnode->data = process; // No reference
882
883 dentry_make_positive(target, vnode);
884 return 0;
885}
886
888{
889 process_t* process = dir->data;
890 assert(process != NULL);
891
892 if (env_unset(&process->env, target->name) == ERR)
893 {
894 return ERR;
895 }
896
897 return 0;
898}
899
902 .create = procfs_env_create,
903 .remove = procfs_env_remove,
904};
905
907{
908 if (!dentry_iterate_dots(dentry, ctx))
909 {
910 return 0;
911 }
912
913 process_t* process = dentry->vnode->data;
914 assert(process != NULL);
915
916 MUTEX_SCOPE(&process->env.mutex);
917
918 for (size_t i = 0; i < process->env.count; i++)
919 {
920 if (ctx->index++ < ctx->pos)
921 {
922 continue;
923 }
924
925 if (!ctx->emit(ctx, process->env.vars[i].key, VREG))
926 {
927 return 0;
928 }
929 }
930
931 return 0;
932}
933
938
940{
941 UNUSED(vnode);
942
943 process_t* process = process_current();
944 int ret = snprintf(buffer, count, "%llu", process->id);
945 if (ret < 0 || ret >= (int)count)
946 {
947 return ERR;
948 }
949
950 return ret;
951}
952
956
957typedef struct
958{
959 const char* name;
965
966static const procfs_entry_t pidEntries[] = {
967 {
968 .name = "prio",
969 .type = VREG,
970 .fileOps = &prioOps,
971 .dentryOps = &hideDentryOps,
972 },
973 {
974 .name = "cwd",
975 .type = VREG,
976 .fileOps = &cwdOps,
977 .dentryOps = &hideDentryOps,
978 },
979 {
980 .name = "cmdline",
981 .type = VREG,
982 .fileOps = &cmdlineOps,
983 },
984 {
985 .name = "note",
986 .type = VREG,
987 .fileOps = &noteOps,
988 .dentryOps = &hideDentryOps,
989 },
990 {
991 .name = "notegroup",
992 .type = VREG,
993 .fileOps = &notegroupOps,
994 .dentryOps = &hideDentryOps,
995 },
996 {
997 .name = "group",
998 .type = VREG,
999 .fileOps = &groupOps,
1000 .dentryOps = &hideDentryOps,
1001 },
1002 {
1003 .name = "pid",
1004 .type = VREG,
1005 .fileOps = &pidOps,
1006 },
1007 {
1008 .name = "wait",
1009 .type = VREG,
1010 .fileOps = &waitOps,
1011 },
1012 {
1013 .name = "perf",
1014 .type = VREG,
1015 .fileOps = &perfOps,
1016 },
1017 {
1018 .name = "ns",
1019 .type = VREG,
1020 .fileOps = &nsOps,
1021 .dentryOps = &hideDentryOps,
1022 },
1023 {
1024 .name = "ctl",
1025 .type = VREG,
1026 .fileOps = &ctlOps,
1027 .dentryOps = &hideDentryOps,
1028 },
1029 {
1030 .name = "env",
1031 .type = VDIR,
1032 .vnodeOps = &envVnodeOps,
1033 .dentryOps = &envDentryOps,
1034 },
1035};
1036
1038 {
1039 .name = "self",
1040 .type = VSYMLINK,
1041 .vnodeOps = &selfOps,
1042 .fileOps = NULL,
1043 },
1044};
1045
1047{
1048 process_t* process = dir->data;
1049 assert(process != NULL);
1050
1051 for (size_t i = 0; i < ARRAY_SIZE(pidEntries); i++)
1052 {
1053 if (strcmp(target->name, pidEntries[i].name) != 0)
1054 {
1055 continue;
1056 }
1057
1059 if (vnode == NULL)
1060 {
1061 return 0;
1062 }
1063 UNREF_DEFER(vnode);
1064 vnode->data = process; // No reference
1065
1066 if (pidEntries[i].dentryOps != NULL)
1067 {
1068 target->ops = pidEntries[i].dentryOps;
1069 }
1070
1071 dentry_make_positive(target, vnode);
1072 return 0;
1073 }
1074
1075 return 0;
1076}
1077
1078static void procfs_pid_cleanup(vnode_t* vnode)
1079{
1080 process_t* process = vnode->data;
1081 if (process == NULL)
1082 {
1083 return;
1084 }
1085
1086 UNREF(process);
1087 vnode->data = NULL;
1088}
1089
1091{
1092 if (!dentry_iterate_dots(dentry, ctx))
1093 {
1094 return 0;
1095 }
1096
1097 process_t* current = process_current();
1098 process_t* process = dentry->vnode->data;
1099 assert(process != NULL);
1100
1101 for (size_t i = 0; i < ARRAY_SIZE(pidEntries); i++)
1102 {
1104 {
1105 namespace_t* currentNs = process_get_ns(current);
1106 UNREF_DEFER(currentNs);
1107
1108 namespace_t* processNs = process_get_ns(process);
1109 UNREF_DEFER(processNs);
1110
1111 if (!namespace_accessible(currentNs, processNs))
1112 {
1113 continue;
1114 }
1115 }
1116
1117 if (ctx->index++ < ctx->pos)
1118 {
1119 continue;
1120 }
1121
1122 if (!ctx->emit(ctx, pidEntries[i].name, pidEntries[i].type))
1123 {
1124 return 0;
1125 }
1126 }
1127
1128 return 0;
1129}
1130
1133 .cleanup = procfs_pid_cleanup,
1134};
1135
1139
1141{
1142 for (size_t i = 0; i < ARRAY_SIZE(procEntries); i++)
1143 {
1144 if (strcmp(target->name, procEntries[i].name) != 0)
1145 {
1146 continue;
1147 }
1148
1149 vnode_t* vnode =
1151 if (vnode == NULL)
1152 {
1153 return ERR;
1154 }
1155 UNREF_DEFER(vnode);
1156
1157 dentry_make_positive(target, vnode);
1158 return 0;
1159 }
1160
1161 pid_t pid;
1162 if (sscanf(target->name, "%llu", &pid) != 1)
1163 {
1164 return 0;
1165 }
1166
1167 process_t* process = process_get(pid);
1168 if (process == NULL)
1169 {
1170 return 0;
1171 }
1172 UNREF_DEFER(process);
1173
1175 if (vnode == NULL)
1176 {
1177 return ERR;
1178 }
1179 UNREF_DEFER(vnode);
1180 vnode->data = REF(process);
1181
1182 target->ops = &pidDentryOps;
1183
1184 dentry_make_positive(target, vnode);
1185 return 0;
1186}
1187
1189{
1190 if (!dentry_iterate_dots(dentry, ctx))
1191 {
1192 return 0;
1193 }
1194
1195 for (size_t i = 0; i < ARRAY_SIZE(procEntries); i++)
1196 {
1197 if (ctx->index++ < ctx->pos)
1198 {
1199 continue;
1200 }
1201
1202 if (!ctx->emit(ctx, procEntries[i].name, procEntries[i].type))
1203 {
1204 return 0;
1205 }
1206 }
1207
1209
1210 process_t* process;
1211 PROCESS_RCU_FOR_EACH(process)
1212 {
1213 if (ctx->index++ < ctx->pos)
1214 {
1215 continue;
1216 }
1217
1218 char name[MAX_NAME];
1219 snprintf(name, sizeof(name), "%llu", process->id);
1220 if (!ctx->emit(ctx, name, VDIR))
1221 {
1222 return 0;
1223 }
1224 }
1225
1226 return 0;
1227}
1228
1232
1236
1237static dentry_t* procfs_mount(filesystem_t* fs, const char* options, void* data)
1238{
1239 UNUSED(data);
1240
1241 if (options != NULL)
1242 {
1243 errno = EINVAL;
1244 return NULL;
1245 }
1246
1247 superblock_t* superblock = superblock_new(fs, NULL, NULL);
1248 if (superblock == NULL)
1249 {
1250 return NULL;
1251 }
1252 UNREF_DEFER(superblock);
1253
1254 vnode_t* vnode = vnode_new(superblock, VDIR, &procVnodeOps, NULL);
1255 if (vnode == NULL)
1256 {
1257 return NULL;
1258 }
1259 UNREF_DEFER(vnode);
1260
1261 dentry_t* dentry = dentry_new(superblock, NULL, NULL);
1262 if (dentry == NULL)
1263 {
1264 return NULL;
1265 }
1266 dentry->ops = &procDentryOps;
1267
1268 dentry_make_positive(dentry, vnode);
1269
1270 superblock->root = dentry;
1271 return superblock->root;
1272}
1273
1275 .name = PROCFS_NAME,
1276 .mount = procfs_mount,
1277};
1278
1279void procfs_init(void)
1280{
1282 {
1283 panic(NULL, "Failed to register procfs filesystem");
1284 }
1285}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static dentry_ops_t dentryOps
Definition devfs.c:27
static fd_t data
Definition dwm.c:21
static dentry_t * dir
Definition fb.c:16
static clock_source_t source
Structure to describe the HPET to the sys time subsystem.
Definition hpet.c:193
#define CTL_STANDARD_OPS_DEFINE(name,...)
Helper macro to define a standard ctl file operations structure.
Definition ctl.h:54
void cwd_set(cwd_t *cwd, const path_t *newPath)
Set the current working directory.
Definition cwd.c:39
path_t cwd_get(cwd_t *cwd, namespace_t *ns)
Get the current working directory.
Definition cwd.c:19
#define DENTRY_IS_DIR(dentry)
Check if the vnode associated with a dentry is a directory.
Definition dentry.h:83
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:134
void dentry_make_positive(dentry_t *dentry, vnode_t *vnode)
Make a dentry positive by associating it with an vnode.
Definition dentry.c:289
bool dentry_iterate_dots(dentry_t *dentry, dir_ctx_t *ctx)
Helper function to iterate over the special entries "." and "..".
Definition dentry.c:304
#define DENTRY_IS_POSITIVE(dentry)
Check if a dentry is positive.
Definition dentry.h:67
fd_t file_table_dup2(file_table_t *table, fd_t oldFd, fd_t newFd)
Duplicate a file descriptor to a specific file descriptor.
Definition file_table.c:214
uint64_t file_table_close(file_table_t *table, fd_t fd)
Free a file descriptor.
Definition file_table.c:74
file_t * file_table_get(file_table_t *table, fd_t fd)
Get a file from its file descriptor.
Definition file_table.c:33
uint64_t file_table_close_range(file_table_t *table, fd_t min, fd_t max)
Free a range of file descriptors.
Definition file_table.c:136
filesystem_t * filesystem_get_by_path(const char *path, process_t *process)
Gets a filesystem by path.
Definition filesystem.c:284
uint64_t filesystem_register(filesystem_t *fs)
Registers a filesystem.
Definition filesystem.c:233
mount_t * namespace_bind(namespace_t *ns, path_t *target, path_t *source, mode_t mode)
Bind a source path to a target path in a namespace.
Definition namespace.c:427
mount_t * namespace_mount(namespace_t *ns, path_t *target, filesystem_t *fs, const char *options, mode_t mode, void *data)
Mount a filesystem in a namespace.
Definition namespace.c:387
bool namespace_accessible(namespace_t *ns, namespace_t *other)
Check if mounts in a namespace can be propagated to another namespace.
Definition namespace.c:341
mode_t
Path flags and permissions.
Definition path.h:79
#define PATH_DEFER(path)
Defer path put.
Definition path.h:106
uint64_t path_walk(path_t *path, const pathname_t *pathname, namespace_t *ns)
Walk a pathname to a path.
Definition path.c:593
uint64_t pathname_init(pathname_t *pathname, const char *string)
Initialize a pathname.
Definition path.c:116
uint64_t path_to_name(const path_t *path, pathname_t *pathname)
Convert a path to a pathname.
Definition path.c:715
@ MODE_DIRECTORY
Definition path.h:90
void procfs_init(void)
Register the procfs filesystem.
Definition procfs.c:1279
#define PROCFS_NAME
Process filesystem name.
Definition procfs.h:205
superblock_t * superblock_new(filesystem_t *fs, const superblock_ops_t *ops, const dentry_ops_t *dentryOps)
Create a new superblock.
Definition superblock.c:33
vnode_t * vnode_new(superblock_t *superblock, vtype_t type, const vnode_ops_t *ops, const file_ops_t *fileOps)
Create a new vnode.
Definition vnode.c:51
#define NOTE_MAX
Maximum size of a notes buffer.
Definition note.h:99
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:292
uint64_t space_user_page_count(space_t *space)
Get the number of user pages allocated in the address space.
Definition space.c:657
const char * env_get(env_t *env, const char *key)
Get the value of an environment variable.
Definition env.c:47
uint64_t env_set(env_t *env, const char *key, const char *value)
Set the value of an environment variable.
Definition env.c:67
uint64_t env_unset(env_t *env, const char *key)
Unset an environment variable.
Definition env.c:127
group_t * group_get(group_member_t *member)
Retrieve the group of a group member.
Definition group.c:79
uint64_t group_send_note(group_member_t *member, const char *note)
Sends a note to all processes in the group of the specified member.
Definition group.c:142
void group_add(group_t *group, group_member_t *member)
Joins a process to a specific group.
Definition group.c:98
#define PROCESS_RCU_FOR_EACH(process)
Macro to iterate over all processes.
Definition process.h:241
void process_kill(process_t *process, const char *status)
Kills a process, pushing it to the reaper.
Definition process.c:240
void process_set_ns(process_t *process, namespace_t *ns)
Sets the namespace of a process.
Definition process.c:227
static uint64_t process_rcu_thread_count(process_t *process)
Gets the amount of threads in a process.
Definition process.h:219
static thread_t * process_rcu_first_thread(process_t *process)
Gets the first thread of a process.
Definition process.h:206
static process_t * process_current(void)
Retrieves the process of the currently running thread.
Definition process.h:131
namespace_t * process_get_ns(process_t *process)
Gets the namespace of a process.
Definition process.c:206
process_t * process_get(pid_t id)
Gets a process by its ID.
Definition process.c:192
@ PROCESS_DYING
Definition process.h:40
@ PROCESS_SUSPENDED
Definition process.h:41
uint64_t thread_send_note(thread_t *thread, const char *string)
Send a note to a thread.
Definition thread.c:176
uint64_t wait_unblock(wait_queue_t *queue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:307
#define WAIT_ALL
Used to indicate that the wait should unblock all waiting threads.
Definition wait.h:43
#define WAIT_BLOCK(queue, condition)
Blocks until the condition is true, will test the condition on every wakeup.
Definition wait.h:51
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
#define RCU_READ_SCOPE()
RCU read-side critical section for the current scope.
Definition rcu.h:94
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:122
#define REF(ptr)
Increment reference count.
Definition ref.h:82
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
file_t * vfs_open(const pathname_t *pathname, process_t *process)
Open a file.
Definition vfs.c:156
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:209
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOMEM
Out of memory.
Definition errno.h:92
#define EIO
I/O error.
Definition errno.h:57
#define ENOTDIR
Not a directory.
Definition errno.h:132
#define errno
Error number variable.
Definition errno.h:27
#define EACCES
Permission denied.
Definition errno.h:97
#define EOK
No error.
Definition errno.h:32
#define ARRAY_SIZE(x)
Get the number of elements in a static array.
Definition defs.h:111
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
vtype_t
Vnode type enum.
Definition fs.h:342
uint64_t mount(const char *mountpoint, const char *fs, const char *options)
System call for mounting a filesystem.
Definition mount.c:5
poll_events_t
Poll events type.
Definition fs.h:286
@ VSYMLINK
Is a symbolic link.
Definition fs.h:345
@ VREG
Is a regular file.
Definition fs.h:343
@ VDIR
Is a directory.
Definition fs.h:344
@ POLLIN
File descriptor is ready to read.
Definition fs.h:288
#define PRIORITY_MAX_USER
The maximum priority user space is allowed to specify, inclusive.
Definition proc.h:44
uint8_t priority_t
Priority type.
Definition proc.h:41
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ fd_t
File descriptor type.
Definition fd_t.h:10
__UINT64_TYPE__ pid_t
Process Identifier.
Definition pid_t.h:11
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static uint64_t offset
Definition screen.c:19
static clock_t startTime
Definition clock.c:5
errno_t memcpy_s(void *_RESTRICT s1, rsize_t s1max, const void *_RESTRICT s2, rsize_t n)
Definition memcpy_s.c:9
static size_t procfs_wait_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition procfs.c:352
static const procfs_entry_t pidEntries[]
Definition procfs.c:966
static filesystem_t procfs
Definition procfs.c:1274
static uint64_t procfs_env_lookup(vnode_t *dir, dentry_t *target)
Definition procfs.c:834
static uint64_t procfs_ns_open(file_t *file)
Definition procfs.c:414
static uint64_t procfs_ctl_bind(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:525
static uint64_t procfs_ctl_start(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:660
static void procfs_ns_close(file_t *file)
Definition procfs.c:428
static uint64_t procfs_ctl_setgroup(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:736
static size_t procfs_prio_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition procfs.c:64
static uint64_t procfs_ctl_touch(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:635
static vnode_ops_t pidVnodeOps
Definition procfs.c:1131
static uint64_t procfs_ctl_setns(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:695
static uint64_t procfs_lookup(vnode_t *dir, dentry_t *target)
Definition procfs.c:1140
static procfs_entry_t procEntries[]
Definition procfs.c:1037
static uint64_t procfs_ctl_mount(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:587
static size_t procfs_pid_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition procfs.c:339
static dentry_t * procfs_mount(filesystem_t *fs, const char *options, void *data)
Definition procfs.c:1237
static file_ops_t noteOps
Definition procfs.c:274
static uint64_t procfs_ctl_dup2(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:493
static file_ops_t nsOps
Definition procfs.c:439
static file_ops_t prioOps
Definition procfs.c:107
static file_ops_t notegroupOps
Definition procfs.c:304
static file_ops_t envVarOps
Definition procfs.c:829
static dentry_ops_t envDentryOps
Definition procfs.c:934
static uint64_t procfs_self_readlink(vnode_t *vnode, char *buffer, uint64_t count)
Definition procfs.c:939
static uint64_t procfs_ctl_close(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:444
static uint64_t procfs_revalidate_hide(dentry_t *dentry)
Definition procfs.c:30
static uint64_t procfs_env_remove(vnode_t *dir, dentry_t *target)
Definition procfs.c:887
static wait_queue_t * procfs_wait_poll(file_t *file, poll_events_t *revents)
Definition procfs.c:367
static void procfs_group_close(file_t *file)
Definition procfs.c:322
static uint64_t procfs_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Definition procfs.c:1188
static uint64_t procfs_pid_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Definition procfs.c:1090
static size_t procfs_cwd_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition procfs.c:112
static void procfs_pid_cleanup(vnode_t *vnode)
Definition procfs.c:1078
static size_t procfs_env_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition procfs.c:805
static vnode_ops_t envVnodeOps
Definition procfs.c:900
static uint64_t procfs_env_create(vnode_t *dir, dentry_t *target, mode_t mode)
Definition procfs.c:859
static dentry_ops_t hideDentryOps
Definition procfs.c:60
static size_t procfs_note_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition procfs.c:238
static file_ops_t perfOps
Definition procfs.c:410
static size_t procfs_perf_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition procfs.c:384
static uint64_t procfs_ctl_kill(file_t *file, uint64_t argc, const char **argv)
Definition procfs.c:678
static file_ops_t cwdOps
Definition procfs.c:189
static file_ops_t pidOps
Definition procfs.c:348
static size_t procfs_cmdline_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition procfs.c:194
static dentry_ops_t procDentryOps
Definition procfs.c:1233
static file_ops_t groupOps
Definition procfs.c:334
static file_ops_t waitOps
Definition procfs.c:379
static size_t procfs_prio_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition procfs.c:75
static dentry_ops_t pidDentryOps
Definition procfs.c:1136
static uint64_t procfs_group_open(file_t *file)
Definition procfs.c:308
static uint64_t procfs_pid_lookup(vnode_t *dir, dentry_t *target)
Definition procfs.c:1046
static uint64_t procfs_env_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Definition procfs.c:906
static vnode_ops_t selfOps
Definition procfs.c:953
static size_t procfs_notegroup_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition procfs.c:278
static size_t procfs_cwd_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition procfs.c:136
static file_ops_t cmdlineOps
Definition procfs.c:234
static vnode_ops_t procVnodeOps
Definition procfs.c:1229
static atomic_long count
Definition main.c:11
#define atomic_store(object, desired)
Definition stdatomic.h:289
#define atomic_load(object)
Definition stdatomic.h:288
#define atomic_fetch_and(object, operand)
Definition stdatomic.h:284
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int sscanf(const char *_RESTRICT s, const char *_RESTRICT format,...)
Definition sscanf.c:4
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC long long int atoll(const char *nptr)
Definition atoll.c:8
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:61
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
_PUBLIC int strcmp(const char *s1, const char *s2)
Definition strcmp.c:3
Dentry operations structure.
Definition dentry.h:122
uint64_t(* revalidate)(dentry_t *dentry)
Called when the dentry is looked up or retrieved from cache.
Definition dentry.h:130
uint64_t(* iterate)(dentry_t *dentry, dir_ctx_t *ctx)
Iterate over the entries in a directory dentry.
Definition dentry.h:138
Directory entry structure.
Definition dentry.h:155
char name[MAX_NAME]
The name of the dentry, immutable after creation.
Definition dentry.h:158
const dentry_ops_t * ops
Definition dentry.h:164
void * data
Definition dentry.h:165
vnode_t * vnode
Will be NULL if the dentry is negative, once positive it will never be modified.
Definition dentry.h:159
superblock_t * superblock
Definition dentry.h:163
Directory context used to iterate over directory entries.
Definition dentry.h:97
size_t index
An index that the filesystem can use for its own purposes.
Definition dentry.h:114
size_t pos
The current position in the directory, can be used to skip entries.
Definition dentry.h:112
bool(* emit)(dir_ctx_t *ctx, const char *name, vtype_t type)
Emit function.
Definition dentry.h:111
mutex_t mutex
Definition env.h:36
env_var_t * vars
Definition env.h:34
size_t count
Definition env.h:35
char * key
Definition env.h:22
File operations structure.
Definition file.h:54
size_t(* read)(file_t *file, void *buffer, size_t count, size_t *offset)
Definition file.h:58
size_t(* write)(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition file.h:59
uint64_t(* open)(file_t *file)
Definition file.h:55
File structure.
Definition file.h:39
void * data
Definition file.h:46
const file_ops_t * ops
Definition file.h:45
vnode_t * vnode
Definition file.h:43
path_t path
Definition file.h:44
Filesystem structure, represents a filesystem type, e.g. fat32, tmpfs, devfs, etc.
Definition filesystem.h:53
const char * name
Definition filesystem.h:58
Process group structure.
Definition group.h:46
Mount structure.
Definition mount.h:48
Namespace structure.
Definition namespace.h:57
Path structure.
Definition path.h:127
dentry_t * dentry
Definition path.h:129
Pathname structure.
Definition path.h:139
char string[MAX_PATH]
Definition path.h:140
mode_t mode
Definition path.h:141
clock_t startTime
The time when the process was started.
Definition perf.h:53
char buffer[PROCESS_STATUS_MAX]
Definition process.h:67
Process structure.
Definition process.h:76
file_table_t fileTable
Definition process.h:88
group_member_t group
Definition process.h:100
uint64_t argc
Definition process.h:99
env_t env
Definition process.h:97
char ** argv
Definition process.h:98
wait_queue_t suspendQueue
Definition process.h:93
perf_process_ctx_t perf
Definition process.h:90
space_t space
Definition process.h:84
process_status_t status
Definition process.h:83
pid_t id
Definition process.h:81
cwd_t cwd
Definition process.h:87
wait_queue_t dyingQueue
Definition process.h:94
Definition procfs.c:958
vtype_t type
Definition procfs.c:960
const char * name
Definition procfs.c:959
const file_ops_t * fileOps
Definition procfs.c:962
const vnode_ops_t * vnodeOps
Definition procfs.c:961
const dentry_ops_t * dentryOps
Definition procfs.c:963
Superblock structure.
Definition superblock.h:33
dentry_t * root
Root dentry of the filesystem, should not take a reference.
Definition superblock.h:40
Thread of execution structure.
Definition thread.h:61
vnode operations structure.
Definition vnode.h:69
uint64_t(* lookup)(vnode_t *dir, dentry_t *target)
Look up a dentry in a directory vnode.
Definition vnode.h:80
uint64_t(* readlink)(vnode_t *vnode, char *buffer, uint64_t size)
Retrieve the path of the symbolic link.
Definition vnode.h:115
vnode structure.
Definition vnode.h:48
void * data
Filesystem defined data.
Definition vnode.h:52
The primitive that threads block on.
Definition wait.h:185