⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 procfs.c

📁 Sanos Operating System Kernel ----------------------------- Sanos is an OS kernel for use in PC base
💻 C
字号:
//
// procfs.c
//
// Kernel Information Filesystem
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <os/krnl.h>

struct proc_inode *proc_list_head;
struct proc_inode *proc_list_tail;
ino_t next_procino = PROC_ROOT_INODE + 1;

int procfs_open(struct file *filp, char *name);
int procfs_close(struct file *filp);

int procfs_read(struct file *filp, void *data, size_t size);

loff_t procfs_tell(struct file *filp);
loff_t procfs_lseek(struct file *filp, loff_t offset, int origin);

int procfs_fstat(struct file *filp, struct stat *buffer);
int procfs_stat(struct fs *fs, char *name, struct stat *buffer);

int procfs_opendir(struct file *filp, char *name);
int procfs_readdir(struct file *filp, struct dirent *dirp, int count);

struct fsops procfsops =
{
  FSOP_OPEN | FSOP_CLOSE | FSOP_READ | FSOP_TELL | FSOP_LSEEK | FSOP_STAT | FSOP_FSTAT | FSOP_OPENDIR | FSOP_READDIR,

  NULL,
  NULL,

  NULL,
  NULL,
  NULL,

  NULL,

  procfs_open,
  procfs_close,
  NULL,

  procfs_read,
  NULL,
  NULL,

  procfs_tell,
  procfs_lseek,
  NULL,

  NULL,
  NULL,

  procfs_fstat,
  procfs_stat,

  NULL,
  NULL,

  NULL,
  NULL,
  NULL,

  procfs_opendir,
  procfs_readdir
};

static struct proc_inode *find_proc(char *name)
{
  struct proc_inode *inode = proc_list_head;
  int namelen = strlen(name);

  while (inode)
  {
    if (fnmatch(name, namelen, inode->name, inode->namelen)) return inode;
    inode = inode->next;
  }

  return NULL;
}

static void free_proc_file(struct proc_file *pf)
{
  struct proc_blk *blk;
  struct proc_blk *next;

  if (!pf) return;
  blk = pf->blkhead;
  while (blk)
  {
    next = blk->next;
    kfree(blk);
    blk = next;
  }

  kfree(pf);
}

void init_procfs()
{
  register_filesystem("procfs", &procfsops);
}

int register_proc_inode(char *name, proc_t proc, void *arg)
{
  struct proc_inode *inode;

  inode = (struct proc_inode *) kmalloc(sizeof(struct proc_inode));
  if (!inode) return -ENOMEM;

  inode->ino = next_procino++;
  inode->name = name;
  inode->namelen = strlen(name);
  inode->proc = proc;
  inode->arg = arg;
  inode->size = 0;

  if (proc_list_tail)
  {
    proc_list_tail->next = inode;
    proc_list_tail = inode;
  }
  else
    proc_list_head = proc_list_tail = inode;

  return 0;
}

int proc_write(struct proc_file *pf, void *buffer, size_t size)
{
  char *ptr = (char *) buffer;
  size_t left = size;
  struct proc_blk *blk;
  size_t count;

  while (left > 0)
  {
    if (!pf->blktail || pf->blktail->size == PROC_BLKSIZE)
    {
      blk = (struct proc_blk *) kmalloc(sizeof(struct proc_blk));
      if (!blk) return -ENOMEM;

      blk->next = NULL;
      blk->size = 0;

      if (pf->blktail)
      {
	pf->blktail->next = blk;
	pf->blktail = blk;
      }
      else
	pf->blkhead = pf->blktail = blk;
    }
    else
      blk = pf->blktail;

    count = blk->size + left > PROC_BLKSIZE ? (size_t) (PROC_BLKSIZE - blk->size) : left;

    memcpy(blk->data + blk->size, ptr, count);
    blk->size += count;
    ptr += count;
    left -= count;
    pf->size += count;
  }

  return size;
}

int pprintf(struct proc_file *pf, const char *fmt, ...)
{
  va_list args;
  char buffer[1024];
  int len;

  va_start(args, fmt);
  len = vsprintf(buffer, fmt, args);
  va_end(args);
    
  return proc_write(pf, buffer, len);
}

int procfs_open(struct file *filp, char *name)
{
  struct proc_inode *inode;
  struct proc_file *pf;
  int rc;

  if (*name == PS1 || *name == PS2) name++;
  inode = find_proc(name);
  if (!inode) return -ENOENT;

  pf = (struct proc_file *) kmalloc(sizeof(struct proc_file));
  if (!pf) return -ENOMEM;

  pf->inode = inode;
  pf->blkhead = pf->blktail = NULL;
  pf->size = 0;

  rc = inode->proc(pf, inode->arg);
  if (rc < 0)
  {
    free_proc_file(pf);
    return rc;
  }

  inode->size = pf->size;
  filp->data = pf;
  return 0;
}

int procfs_close(struct file *filp)
{
  if (!(filp->flags & F_DIR))
  {
    struct proc_file *pf = filp->data;
    free_proc_file(pf);
  }

  return 0;
}

int procfs_read(struct file *filp, void *data, size_t size)
{
  struct proc_file *pf = filp->data;
  struct proc_blk *blk;
  size_t start = 0;
  char *ptr = (char *) data;
  int left = size;
  int count;
  int offset;

  if (filp->flags & F_DIR) return -EINVAL;
  if (!size) return 0;

  blk = pf->blkhead;
  while (blk && start + blk->size <= filp->pos)
  {
    start += blk->size;
    blk = blk->next;
  }

  if (blk)
  {
    offset = filp->pos - start;

    if (offset < 0 || offset >= PROC_BLKSIZE)
    {
      kprintf("invalid proc blk offset %d\n", offset);
      dbg_break();
    }

    if (left < blk->size - offset)
      count = left;
    else
      count = blk->size - offset;

    memcpy(ptr, blk->data + offset, count);
    ptr += count;
    left -= count;
    blk = blk->next;
  }

  while (left > 0 && blk)
  {
    if (left < blk->size)
      count = left;
    else
      count = blk->size;

    memcpy(ptr, blk->data, count);
    ptr += count;
    left -= count;
    blk = blk->next;
  }

  filp->pos += size - left;
  return size - left;
}

loff_t procfs_tell(struct file *filp)
{
  return filp->pos;
}

loff_t procfs_lseek(struct file *filp, loff_t offset, int origin)
{
  struct proc_file *pf = filp->data;

  if (filp->flags & F_DIR) return -EINVAL;

  switch (origin)
  {
    case SEEK_END:
      offset += pf->size;
      break;

    case SEEK_CUR:
      offset += filp->pos;
  }

  if (offset < 0 || offset > pf->size) return -EINVAL;

  filp->pos = offset;
  return offset;
}

int procfs_fstat(struct file *filp, struct stat *buffer)
{
  struct proc_file *pf = filp->data;

  if (filp->flags & F_DIR)
  {
    if (buffer)
    {
      buffer->mode = FS_DIRECTORY;
      buffer->ino = PROC_ROOT_INODE;
      buffer->nlink = 1;
      buffer->devno = NODEV;
      buffer->atime = buffer->mtime = buffer->ctime = get_time();
      buffer->size = 0;
    }

    return 0;
  }

  if (buffer)
  {
    buffer->mode = 0;
    buffer->mode |= FS_BLKDEV;

    buffer->ino = pf->inode->ino;
    buffer->nlink = 1;
    buffer->devno = NODEV;

    buffer->atime = buffer->mtime = buffer->ctime = get_time();
    buffer->size = pf->size;
  }

  return pf->size;
}

int procfs_stat(struct fs *fs, char *name, struct stat *buffer)
{
  struct proc_inode *inode;

  if (*name == PS1 || *name == PS2) name++;

  if (!*name)
  {
    if (buffer)
    {
      buffer->mode = FS_DIRECTORY;
      buffer->ino = PROC_ROOT_INODE;
      buffer->nlink = 1;
      buffer->devno = NODEV;
      buffer->atime = buffer->mtime = buffer->ctime = get_time();
      buffer->size = 0;
    }

    return 0;
  }

  inode = find_proc(name);
  if (!inode) return -ENOENT;

  if (buffer)
  {
    buffer->mode = 0;
    buffer->mode |= FS_BLKDEV;

    buffer->ino = inode->ino;
    buffer->nlink = 1;
    buffer->devno = NODEV;

    buffer->atime = buffer->mtime = buffer->ctime = get_time();
    buffer->size = inode->size;
  }

  return inode->size;
}

int procfs_opendir(struct file *filp, char *name)
{
  if (*name == PS1 || *name == PS2) name++;
  if (*name) return -ENOENT;

  filp->data = proc_list_head;
  return 0;
}

int procfs_readdir(struct file *filp, struct dirent *dirp, int count)
{
  struct proc_inode *inode = filp->data;

  if (!inode) return 0;

  dirp->ino = inode->ino;
  dirp->namelen = inode->namelen;
  dirp->reclen = sizeof(struct dirent) + dirp->namelen + 1;
  memcpy(dirp->name, inode->name, inode->namelen + 1);

  filp->pos++;
  filp->data = inode->next;
  return 1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -