1 /* ProcFS - tree.c - by Alen Stojanov and David van Moolenbroek */
5 struct proc proc
[NR_PROCS
+ NR_TASKS
];
6 struct mproc mproc
[NR_PROCS
];
7 struct fproc fproc
[NR_PROCS
];
9 static int nr_pid_entries
;
11 /*===========================================================================*
13 *===========================================================================*/
14 static int slot_in_use(int slot
)
16 /* Return whether the given slot is in use by a process.
19 /* For kernel tasks, check only the kernel slot. Tasks do not have a
20 * PM/VFS process slot.
23 return (proc
[slot
].p_rts_flags
!= RTS_SLOT_FREE
);
25 /* For regular processes, check only the PM slot. Do not check the
26 * kernel slot, because that would skip zombie processes. The PID check
27 * should be redundant, but if it fails, procfs could crash.
29 return ((mproc
[slot
- NR_TASKS
].mp_flags
& IN_USE
) &&
30 mproc
[slot
- NR_TASKS
].mp_pid
!= 0);
33 /*===========================================================================*
35 *===========================================================================*/
36 static int check_owner(struct inode
*node
, int slot
)
38 /* Check if the owner user and group ID of the inode are still in sync
39 * the current effective user and group ID of the given process.
41 struct inode_stat stat
;
43 if (slot
< NR_TASKS
) return TRUE
;
45 get_inode_stat(node
, &stat
);
47 return (stat
.uid
== mproc
[slot
- NR_TASKS
].mp_effuid
&&
48 stat
.gid
== mproc
[slot
- NR_TASKS
].mp_effgid
);
51 /*===========================================================================*
53 *===========================================================================*/
54 static void make_stat(struct inode_stat
*stat
, int slot
, int index
)
56 /* Fill in an inode_stat structure for the given process slot and
57 * per-pid file index (or NO_INDEX for the process subdirectory root).
60 if (index
== NO_INDEX
)
61 stat
->mode
= DIR_ALL_MODE
;
63 stat
->mode
= pid_files
[index
].mode
;
65 if (slot
< NR_TASKS
) {
66 stat
->uid
= SUPER_USER
;
67 stat
->gid
= SUPER_USER
;
69 stat
->uid
= mproc
[slot
- NR_TASKS
].mp_effuid
;
70 stat
->gid
= mproc
[slot
- NR_TASKS
].mp_effgid
;
77 /*===========================================================================*
79 *===========================================================================*/
80 static int dir_is_pid(struct inode
*node
)
82 /* Return whether the given node is a PID directory.
85 return (get_parent_inode(node
) == get_root_inode() &&
86 get_inode_index(node
) != NO_INDEX
);
89 /*===========================================================================*
91 *===========================================================================*/
92 static int update_proc_table(void)
94 /* Get the process table from the kernel.
95 * Check the magic number in the table entries.
99 if ((r
= sys_getproctab(proc
)) != OK
) return r
;
101 for (slot
= 0; slot
< NR_PROCS
+ NR_TASKS
; slot
++) {
102 if (proc
[slot
].p_magic
!= PMAGIC
) {
103 printf("PROCFS: system version mismatch!\n");
112 /*===========================================================================*
113 * update_mproc_table *
114 *===========================================================================*/
115 static int update_mproc_table(void)
117 /* Get the process table from PM.
118 * Check the magic number in the table entries.
122 r
= getsysinfo(PM_PROC_NR
, SI_PROC_TAB
, mproc
, sizeof(mproc
));
123 if (r
!= OK
) return r
;
125 for (slot
= 0; slot
< NR_PROCS
; slot
++) {
126 if (mproc
[slot
].mp_magic
!= MP_MAGIC
) {
127 printf("PROCFS: PM version mismatch!\n");
136 /*===========================================================================*
137 * update_fproc_table *
138 *===========================================================================*/
139 static int update_fproc_table(void)
141 /* Get the process table from VFS.
144 return getsysinfo(VFS_PROC_NR
, SI_PROC_TAB
, fproc
, sizeof(fproc
));
147 /*===========================================================================*
149 *===========================================================================*/
150 static int update_tables(void)
152 /* Get the process tables from the kernel, PM, and VFS.
156 if ((r
= update_proc_table()) != OK
) return r
;
158 if ((r
= update_mproc_table()) != OK
) return r
;
160 if ((r
= update_fproc_table()) != OK
) return r
;
165 /*===========================================================================*
167 *===========================================================================*/
170 /* Initialize this module, before VTreeFS is started. As part of the
171 * process, check if we're not compiled against a kernel different from
172 * the one that is running at the moment.
176 if ((r
= update_tables()) != OK
)
179 /* Get the maximum number of entries that we may add to each PID's
180 * directory. We could just default to a large value, but why not get
183 for (i
= 0; pid_files
[i
].name
!= NULL
; i
++);
190 /*===========================================================================*
192 *===========================================================================*/
193 static void out_of_inodes(void)
195 /* Out of inodes - the NR_INODES value is set too low. We can not do
196 * much, but we might be able to continue with degraded functionality,
197 * so do not panic. If the NR_INODES value is not below the *crucial*
198 * minimum, the symptom of this case will be an incomplete listing of
199 * the main proc directory.
201 static int warned
= FALSE
;
203 if (warned
== FALSE
) {
204 printf("PROCFS: out of inodes!\n");
210 /*===========================================================================*
211 * construct_pid_dirs *
212 *===========================================================================*/
213 static void construct_pid_dirs(void)
215 /* Regenerate the set of PID directories in the root directory of the
216 * file system. Add new directories and delete old directories as
217 * appropriate; leave unchanged those that should remain the same.
219 * We have to make two passes. Otherwise, we would trigger a vtreefs
220 * assert when we add an entry for a PID before deleting the previous
221 * entry for that PID. While rare, such rapid PID reuse does occur in
224 struct inode
*root
, *node
;
225 struct inode_stat stat
;
226 char name
[PNAME_MAX
+1];
230 root
= get_root_inode();
232 /* First pass: delete old entries. */
233 for (i
= 0; i
< NR_PROCS
+ NR_TASKS
; i
++) {
234 /* Do we already have an inode associated with this slot? */
235 node
= get_inode_by_index(root
, i
);
239 /* If the process slot is not in use, delete the associated
242 if (!slot_in_use(i
)) {
248 /* Otherwise, get the process ID. */
250 pid
= (pid_t
) (i
- NR_TASKS
);
252 pid
= mproc
[i
- NR_TASKS
].mp_pid
;
254 /* If there is an old entry, see if the pid matches the current
255 * entry, and the owner is still the same. Otherwise, delete
256 * the old entry first. We reconstruct the entire subtree even
257 * if only the owner changed, for security reasons: if a
258 * process could keep open a file or directory across the owner
259 * change, it might be able to access information it shouldn't.
261 if (pid
!= (pid_t
) get_inode_cbdata(node
) ||
262 !check_owner(node
, i
))
266 /* Second pass: add new entries. */
267 for (i
= 0; i
< NR_PROCS
+ NR_TASKS
; i
++) {
268 /* If the process slot is not in use, skip this slot. */
272 /* If we have an inode associated with this slot, we have
273 * already checked it to be up-to-date above.
275 if (get_inode_by_index(root
, i
) != NULL
)
278 /* Get the process ID. */
280 pid
= (pid_t
) (i
- NR_TASKS
);
282 pid
= mproc
[i
- NR_TASKS
].mp_pid
;
284 /* Add the entry for the process slot. */
285 snprintf(name
, PNAME_MAX
+ 1, "%d", pid
);
287 make_stat(&stat
, i
, NO_INDEX
);
289 node
= add_inode(root
, name
, i
, &stat
, nr_pid_entries
,
297 /*===========================================================================*
298 * make_one_pid_entry *
299 *===========================================================================*/
300 static void make_one_pid_entry(struct inode
*parent
, char *name
, int slot
)
302 /* Construct one file in a PID directory, if a file with the given name
303 * should exist at all.
306 struct inode_stat stat
;
309 /* Don't readd if it is already there. */
310 node
= get_inode_by_name(parent
, name
);
314 /* Only add the file if it is a known, registered name. */
315 for (i
= 0; pid_files
[i
].name
!= NULL
; i
++) {
316 if (!strcmp(name
, pid_files
[i
].name
)) {
317 make_stat(&stat
, slot
, i
);
319 node
= add_inode(parent
, name
, i
, &stat
,
320 (index_t
) 0, (cbdata_t
) 0);
330 /*===========================================================================*
331 * make_all_pid_entries *
332 *===========================================================================*/
333 static void make_all_pid_entries(struct inode
*parent
, int slot
)
335 /* Construct all files in a PID directory.
338 struct inode_stat stat
;
341 for (i
= 0; pid_files
[i
].name
!= NULL
; i
++) {
342 node
= get_inode_by_index(parent
, i
);
346 make_stat(&stat
, slot
, i
);
348 node
= add_inode(parent
, pid_files
[i
].name
, i
, &stat
,
349 (index_t
) 0, (cbdata_t
) 0);
356 /*===========================================================================*
357 * construct_pid_entries *
358 *===========================================================================*/
359 static void construct_pid_entries(struct inode
*parent
, char *name
)
361 /* Construct one requested file entry, or all file entries, in a PID
366 slot
= get_inode_index(parent
);
367 assert(slot
>= 0 && slot
< NR_TASKS
+ NR_PROCS
);
369 /* If this process is already gone, delete the directory now. */
370 if (!slot_in_use(slot
)) {
371 delete_inode(parent
);
376 /* If a specific file name is being looked up, see if we have to add
377 * an inode for that file. If the directory contents are being
378 * retrieved, add all files that have not yet been added.
381 make_one_pid_entry(parent
, name
, slot
);
383 make_all_pid_entries(parent
, slot
);
386 /*===========================================================================*
388 *===========================================================================*/
389 static void pid_read(struct inode
*node
)
391 /* Data is requested from one of the files in a PID directory. Call the
392 * function that is responsible for generating the data for that file.
394 struct inode
*parent
;
397 /* Get the slot number of the process. Note that this currently will
398 * not work for files not in the top-level pid subdirectory.
400 parent
= get_parent_inode(node
);
402 slot
= get_inode_index(parent
);
404 /* Get this file's index number. */
405 index
= get_inode_index(node
);
407 /* Call the handler procedure for the file. */
408 ((void (*) (int)) pid_files
[index
].data
)(slot
);
411 /*===========================================================================*
413 *===========================================================================*/
414 static int pid_link(struct inode
*UNUSED(node
), char *ptr
, int max
)
416 /* The contents of a symbolic link in a PID directory are requested.
417 * This function is a placeholder for future use.
421 strlcpy(ptr
, "", max
);
426 /*===========================================================================*
428 *===========================================================================*/
429 int lookup_hook(struct inode
*parent
, char *name
,
430 cbdata_t
UNUSED(cbdata
))
432 /* Path name resolution hook, for a specific parent and name pair.
433 * If needed, update our own view of the system first; after that,
434 * determine whether we need to (re)generate certain files.
436 static clock_t last_update
= 0;
440 /* Update lazily for lookups, as this gets too expensive otherwise.
441 * Alternative: pull in only PM's table?
443 if ((r
= getuptime(&now
)) != OK
)
444 panic(__FILE__
, "unable to get uptime", r
);
446 if (last_update
!= now
) {
452 /* If the parent is the root directory, we must now reconstruct all
453 * entries, because some of them might have been garbage collected.
454 * We must update the entire tree at once; if we update individual
455 * entries, we risk name collisions.
457 if (parent
== get_root_inode()) {
458 construct_pid_dirs();
460 /* If the parent is a process directory, we may need to (re)construct
461 * the entry being looked up.
463 else if (dir_is_pid(parent
)) {
464 /* We might now have deleted our current containing directory;
465 * construct_pid_entries() will take care of this case.
467 construct_pid_entries(parent
, name
);
473 /*===========================================================================*
475 *===========================================================================*/
476 int getdents_hook(struct inode
*node
, cbdata_t
UNUSED(cbdata
))
478 /* Directory entry retrieval hook, for potentially all files in a
479 * directory. Make sure that all files that are supposed to be
480 * returned, are actually part of the virtual tree.
483 if (node
== get_root_inode()) {
486 construct_pid_dirs();
487 } else if (dir_is_pid(node
)) {
488 construct_pid_entries(node
, NULL
/*name*/);
494 /*===========================================================================*
496 *===========================================================================*/
497 int read_hook(struct inode
*node
, off_t off
, char **ptr
,
498 size_t *len
, cbdata_t cbdata
)
500 /* Regular file read hook. Call the appropriate callback function to
501 * generate and return the data.
506 /* Populate the buffer with the proper content. */
507 if (get_inode_index(node
) != NO_INDEX
) {
510 ((void (*) (void)) cbdata
)();
518 /*===========================================================================*
520 *===========================================================================*/
521 int rdlink_hook(struct inode
*node
, char *ptr
, size_t max
,
522 cbdata_t
UNUSED(cbdata
))
524 /* Symbolic link resolution hook. Not used yet.
526 struct inode
*parent
;
528 /* Get the parent inode. */
529 parent
= get_parent_inode(node
);
531 /* If the parent inode is a pid directory, call the pid handler.
533 if (parent
!= NULL
&& dir_is_pid(parent
))
534 pid_link(node
, ptr
, max
);