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