特别鸣谢成武同学提供的代码~
//==============================================================================
1.cpu的占用律 cupinfo,可以更好的了解cpu的使用情况。
2.是变化前的,f_pos为0时才会更新psinfo内容。
//==============================================================================
这次试验没有想象中那么难
需要修改
linux-0.11/include/sys/stat.h
linux-0.11/init/main.c
linux-0.11/fs/read_write.c
linux-0.11/fs/namei.c
这几个文件
自己写一个
linux-0.11/fs/proc.c
文件
不要忘记把fs中的makefile改掉,要不然你自己新写的proc.c是不会被编译进去的。
或者你比较懒,可以到测试脚本中找makefile.c直接粘贴过来也行。
修改的部分试验指导书写的很清楚,按图索骥就可以改好
stat.h 修改成这样,完全按照指导书来就行。需要定义一个字符数组。用处见proc.c
#ifndef _SYS_STAT_H #define _SYS_STAT_H #include <sys/types.h> struct stat { dev_t st_dev; ino_t st_ino; umode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; }; #define S_IFMT 00170000 #define S_IFREG 0100000 #define S_IFBLK 0060000 #define S_IFDIR 0040000 #define S_IFPROC 0050000 #define S_IFCHR 0020000 #define S_IFIFO 0010000 #define S_ISUID 0004000 #define S_ISGID 0002000 #define S_ISVTX 0001000 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #define S_ISPROC(m) (((m) & S_IFMT) == S_IFPROC) #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_IRWXU 00700 #define S_IRUSR 00400 #define S_IWUSR 00200 #define S_IXUSR 00100 #define S_IRWXG 00070 #define S_IRGRP 00040 #define S_IWGRP 00020 #define S_IXGRP 00010 #define S_IRWXO 00007 #define S_IROTH 00004 #define S_IWOTH 00002 #define S_IXOTH 00001 char psbuffer[1024]; extern int chmod(const char *_path, mode_ta mode); extern int fstat(int fildes, struct stat *stat_buf); extern int mkdir(const char *_path, mode_t mode); extern int mkfifo(const char *_path, mode_t mode); extern int stat(const char *filename, struct stat *stat_buf); extern mode_t umask(mode_t mask); #endif
main.c 这样改 吧mknod和mkdir的宏加在开头
然后在init函数中调用一下就可以了,参数神马的指导书里也有详细讲解。
/* * linux/init/main.c * * (C) 1991 Linus Torvalds */ #define __LIBRARY__ #include <unistd.h> #include <time.h> #include <sys/stat.h> /* * we need this inline - forking from kernel space will result * in NO COPY ON WRITE (!!!), until an execve is executed. This * is no problem, but for the stack. This is handled by not letting * main() use the stack at all after fork(). Thus, no function * calls - which means inline code for fork too, as otherwise we * would use the stack upon exit from 'fork()'. * * Actually only pause and fork are needed inline, so that there * won't be any messing with the stack from main(), but we define * some others too. */ static inline _syscall0(int,fork) static inline _syscall0(int,pause) static inline _syscall1(int,setup,void *,BIOS) static inline _syscall0(int,sync) _syscall2(int,mkdir,const char*,name,mode_t,mode) _syscall3(int,mknod,const char*,filename,mode_t,mode,dev_t,dev) #include <linux/tty.h> #include <linux/sched.h> #include <linux/head.h> #include <asm/system.h> #include <asm/io.h> #include <stddef.h> #include <stdarg.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <linux/fs.h> static char printbuf[1024]; extern int vsprintf(); extern void init(void); extern void blk_dev_init(void); extern void chr_dev_init(void); extern void hd_init(void); extern void floppy_init(void); extern void mem_init(long start, long end); extern long rd_init(long mem_start, int length); extern long kernel_mktime(struct tm * tm); extern long startup_time; /* * This is set up by the setup-routine at boot-time */ #define EXT_MEM_K (*(unsigned short *)0x90002) #define DRIVE_INFO (*(struct drive_info *)0x90080) #define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) /* * Yeah, yeah, it's ugly, but I cannot find how to do this correctly * and this seems to work. I anybody has more info on the real-time * clock I'd be interested. Most of this was trial and error, and some * bios-listing reading. Urghh. */ #define CMOS_READ(addr) ({ \ outb_p(0x80|addr,0x70); \ inb_p(0x71); \ }) #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) static void time_init(void) { struct tm time; do { time.tm_sec = CMOS_READ(0); time.tm_min = CMOS_READ(2); time.tm_hour = CMOS_READ(4); time.tm_mday = CMOS_READ(7); time.tm_mon = CMOS_READ(8); time.tm_year = CMOS_READ(9); } while (time.tm_sec != CMOS_READ(0)); BCD_TO_BIN(time.tm_sec); BCD_TO_BIN(time.tm_min); BCD_TO_BIN(time.tm_hour); BCD_TO_BIN(time.tm_mday); BCD_TO_BIN(time.tm_mon); BCD_TO_BIN(time.tm_year); time.tm_mon--; startup_time = kernel_mktime(&time); } static long memory_end = 0; static long buffer_memory_end = 0; static long main_memory_start = 0; struct drive_info { char dummy[32]; } drive_info; void main(void) /* This really IS void, no error here. */ { /* The startup routine assumes (well, ...) this */ /* * Interrupts are still disabled. Do necessary setups, then * enable them */ ROOT_DEV = ORIG_ROOT_DEV; drive_info = DRIVE_INFO; memory_end = (1<<20) + (EXT_MEM_K<<10); memory_end &= 0xfffff000; if (memory_end > 16*1024*1024) memory_end = 16*1024*1024; if (memory_end > 12*1024*1024) buffer_memory_end = 4*1024*1024; else if (memory_end > 6*1024*1024) buffer_memory_end = 2*1024*1024; else buffer_memory_end = 1*1024*1024; main_memory_start = buffer_memory_end; #ifdef RAMDISK main_memory_start += rd_init(main_memory_start, RAMDISK*1024); #endif mem_init(main_memory_start,memory_end); trap_init(); blk_dev_init(); chr_dev_init(); tty_init(); time_init(); sched_init(); buffer_init(buffer_memory_end); hd_init(); floppy_init(); sti(); move_to_user_mode(); if (!fork()) { /* we count on this going ok */ init(); } /* * NOTE!! For any other task 'pause()' would mean we have to get a * signal to awaken, but task0 is the sole exception (see 'schedule()') * as task 0 gets activated at every idle moment (when no other tasks * can run). For task0 'pause()' just means we go check if some other * task can run, and if not we return here. */ for(;;) pause(); } static int printf(const char *fmt, ...) { va_list args; int i; va_start(args, fmt); write(1,printbuf,i=vsprintf(printbuf, fmt, args)); va_end(args); return i; } static char * argv_rc[] = { "/bin/sh", NULL }; static char * envp_rc[] = { "HOME=/", NULL }; static char * argv[] = { "-/bin/sh",NULL }; static char * envp[] = { "HOME=/usr/root", NULL }; void init(void) { int pid,i; setup((void *) &drive_info); (void) open("/dev/tty0",O_RDWR,0); (void) dup(0); (void) dup(0); mkdir("/proc",0755); mknod("/proc/psinfo",S_IFPROC|0444,0); printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, NR_BUFFERS*BLOCK_SIZE); printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); if (!(pid=fork())) { close(0); if (open("/etc/rc",O_RDONLY,0)) _exit(1); execve("/bin/sh",argv_rc,envp_rc); _exit(2); } if (pid>0) while (pid != wait(&i)) /* nothing */; while (1) { if ((pid=fork())<0) { printf("Fork failed in init\r\n"); continue; } if (!pid) { close(0);close(1);close(2); setsid(); (void) open("/dev/tty0",O_RDWR,0); (void) dup(0); (void) dup(0); _exit(execve("/bin/sh",argv,envp)); } while (1) if (pid == wait(&i)) break; printf("\n\rchild %d died with code %04x\n\r",pid,i); sync(); } _exit(0); /* NOTE! _exit, not exit() */ }namei.c 只需要修改mknod函数中的一行代码就好了~
/* * linux/fs/namei.c * * (C) 1991 Linus Torvalds */ /* * Some corrections by tytso. */ #include <linux/sched.h> #include <linux/kernel.h> #include <asm/segment.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <const.h> #include <sys/stat.h> #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) /* * comment out this line if you want names > NAME_LEN chars to be * truncated. Else they will be disallowed. */ /* #define NO_TRUNCATE */ #define MAY_EXEC 1 #define MAY_WRITE 2 #define MAY_READ 4 /* * permission() * * is used to check for read/write/execute permissions on a file. * I don't know if we should look at just the euid or both euid and * uid, but that should be easily changed. */ static int permission(struct m_inode * inode,int mask) { int mode = inode->i_mode; /* special case: not even root can read/write a deleted file */ if (inode->i_dev && !inode->i_nlinks) return 0; else if (current->euid==inode->i_uid) mode >>= 6; else if (current->egid==inode->i_gid) mode >>= 3; if (((mode & mask & 0007) == mask) || suser()) return 1; return 0; } /* * ok, we cannot use strncmp, as the name is not in our data space. * Thus we'll have to use match. No big problem. Match also makes * some sanity tests. * * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. */ static int match(int len,const char * name,struct dir_entry * de) { register int same ; if (!de || !de->inode || len > NAME_LEN) return 0; if (len < NAME_LEN && de->name[len]) return 0; __asm__("cld\n\t" "fs ; repe ; cmpsb\n\t" "setz %%al" :"=a" (same) :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) ); return same; } /* * find_entry() * * finds an entry in the specified directory with the wanted name. It * returns the cache buffer in which the entry was found, and the entry * itself (as a parameter - res_dir). It does NOT read the inode of the * entry - you'll have to do that yourself if you want to. * * This also takes care of the few special cases due to '..'-traversal * over a pseudo-root and a mount point. */ static struct buffer_head * find_entry(struct m_inode ** dir, const char * name, int namelen, struct dir_entry ** res_dir) { int entries; int block,i; struct buffer_head * bh; struct dir_entry * de; struct super_block * sb; #ifdef NO_TRUNCATE if (namelen > NAME_LEN) return NULL; #else if (namelen > NAME_LEN) namelen = NAME_LEN; #endif entries = (*dir)->i_size / (sizeof (struct dir_entry)); *res_dir = NULL; if (!namelen) return NULL; /* check for '..', as we might have to do some "magic" for it */ if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { /* '..' in a pseudo-root results in a faked '.' (just change namelen) */ if ((*dir) == current->root) namelen=1; else if ((*dir)->i_num == ROOT_INO) { /* '..' over a mount-point results in 'dir' being exchanged for the mounted directory-inode. NOTE! We set mounted, so that we can iput the new dir */ sb=get_super((*dir)->i_dev); if (sb->s_imount) { iput(*dir); (*dir)=sb->s_imount; (*dir)->i_count++; } } } if (!(block = (*dir)->i_zone[0])) return NULL; if (!(bh = bread((*dir)->i_dev,block))) return NULL; i = 0; de = (struct dir_entry *) bh->b_data; while (i < entries) { if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || !(bh = bread((*dir)->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } de = (struct dir_entry *) bh->b_data; } if (match(namelen,name,de)) { *res_dir = de; return bh; } de++; i++; } brelse(bh); return NULL; } /* * add_entry() * * adds a file entry to the specified directory, using the same * semantics as find_entry(). It returns NULL if it failed. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */ static struct buffer_head * add_entry(struct m_inode * dir, const char * name, int namelen, struct dir_entry ** res_dir) { int block,i; struct buffer_head * bh; struct dir_entry * de; *res_dir = NULL; #ifdef NO_TRUNCATE if (namelen > NAME_LEN) return NULL; #else if (namelen > NAME_LEN) namelen = NAME_LEN; #endif if (!namelen) return NULL; if (!(block = dir->i_zone[0])) return NULL; if (!(bh = bread(dir->i_dev,block))) return NULL; i = 0; de = (struct dir_entry *) bh->b_data; while (1) { if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); if (!block) return NULL; if (!(bh = bread(dir->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } de = (struct dir_entry *) bh->b_data; } if (i*sizeof(struct dir_entry) >= dir->i_size) { de->inode=0; dir->i_size = (i+1)*sizeof(struct dir_entry); dir->i_dirt = 1; dir->i_ctime = CURRENT_TIME; } if (!de->inode) { dir->i_mtime = CURRENT_TIME; for (i=0; i < NAME_LEN ; i++) de->name[i]=(i<namelen)?get_fs_byte(name+i):0; bh->b_dirt = 1; *res_dir = de; return bh; } de++; i++; } brelse(bh); return NULL; } /* * get_dir() * * Getdir traverses the pathname until it hits the topmost directory. * It returns NULL on failure. */ static struct m_inode * get_dir(const char * pathname) { char c; const char * thisname; struct m_inode * inode; struct buffer_head * bh; int namelen,inr,idev; struct dir_entry * de; if (!current->root || !current->root->i_count) panic("No root inode"); if (!current->pwd || !current->pwd->i_count) panic("No cwd inode"); if ((c=get_fs_byte(pathname))=='/') { inode = current->root; pathname++; } else if (c) inode = current->pwd; else return NULL; /* empty name is bad */ inode->i_count++; while (1) { thisname = pathname; if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { iput(inode); return NULL; } for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) /* nothing */ ; if (!c) return inode; if (!(bh = find_entry(&inode,thisname,namelen,&de))) { iput(inode); return NULL; } inr = de->inode; idev = inode->i_dev; brelse(bh); iput(inode); if (!(inode = iget(idev,inr))) return NULL; } } /* * dir_namei() * * dir_namei() returns the inode of the directory of the * specified name, and the name within that directory. */ static struct m_inode * dir_namei(const char * pathname, int * namelen, const char ** name) { char c; const char * basename; struct m_inode * dir; if (!(dir = get_dir(pathname))) return NULL; basename = pathname; while ((c=get_fs_byte(pathname++))) if (c=='/') basename=pathname; *namelen = pathname-basename-1; *name = basename; return dir; } /* * namei() * * is used by most simple commands to get the inode of a specified name. * Open, link etc use their own routines, but this is enough for things * like 'chmod' etc. */ struct m_inode * namei(const char * pathname) { const char * basename; int inr,dev,namelen; struct m_inode * dir; struct buffer_head * bh; struct dir_entry * de; if (!(dir = dir_namei(pathname,&namelen,&basename))) return NULL; if (!namelen) /* special case: '/usr/' etc */ return dir; bh = find_entry(&dir,basename,namelen,&de); if (!bh) { iput(dir); return NULL; } inr = de->inode; dev = dir->i_dev; brelse(bh); iput(dir); dir=iget(dev,inr); if (dir) { dir->i_atime=CURRENT_TIME; dir->i_dirt=1; } return dir; } /* * open_namei() * * namei for open - this is in fact almost the whole open-routine. */ int open_namei(const char * pathname, int flag, int mode, struct m_inode ** res_inode) { const char * basename; int inr,dev,namelen; struct m_inode * dir, *inode; struct buffer_head * bh; struct dir_entry * de; if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) flag |= O_WRONLY; mode &= 0777 & ~current->umask; mode |= I_REGULAR; if (!(dir = dir_namei(pathname,&namelen,&basename))) return -ENOENT; if (!namelen) { /* special case: '/usr/' etc */ if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { *res_inode=dir; return 0; } iput(dir); return -EISDIR; } bh = find_entry(&dir,basename,namelen,&de); if (!bh) { if (!(flag & O_CREAT)) { iput(dir); return -ENOENT; } if (!permission(dir,MAY_WRITE)) { iput(dir); return -EACCES; } inode = new_inode(dir->i_dev); if (!inode) { iput(dir); return -ENOSPC; } inode->i_uid = current->euid; inode->i_mode = mode; inode->i_dirt = 1; bh = add_entry(dir,basename,namelen,&de); if (!bh) { inode->i_nlinks--; iput(inode); iput(dir); return -ENOSPC; } de->inode = inode->i_num; bh->b_dirt = 1; brelse(bh); iput(dir); *res_inode = inode; return 0; } inr = de->inode; dev = dir->i_dev; brelse(bh); iput(dir); if (flag & O_EXCL) return -EEXIST; if (!(inode=iget(dev,inr))) return -EACCES; if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || !permission(inode,ACC_MODE(flag))) { iput(inode); return -EPERM; } inode->i_atime = CURRENT_TIME; if (flag & O_TRUNC) truncate(inode); *res_inode = inode; return 0; } int sys_mknod(const char * filename, int mode, int dev) { const char * basename; int namelen; struct m_inode * dir, * inode; struct buffer_head * bh; struct dir_entry * de; if (!suser()) return -EPERM; if (!(dir = dir_namei(filename,&namelen,&basename))) return -ENOENT; if (!namelen) { iput(dir); return -ENOENT; } if (!permission(dir,MAY_WRITE)) { iput(dir); return -EPERM; } bh = find_entry(&dir,basename,namelen,&de); if (bh) { brelse(bh); iput(dir); return -EEXIST; } inode = new_inode(dir->i_dev); if (!inode) { iput(dir); return -ENOSPC; } inode->i_mode = mode; if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISPROC(mode)) inode->i_zone[0] = dev; inode->i_mtime = inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; bh = add_entry(dir,basename,namelen,&de); if (!bh) { iput(dir); inode->i_nlinks=0; iput(inode); return -ENOSPC; } de->inode = inode->i_num; bh->b_dirt = 1; iput(dir); iput(inode); brelse(bh); return 0; } int sys_mkdir(const char * pathname, int mode) { const char * basename; int namelen; struct m_inode * dir, * inode; struct buffer_head * bh, *dir_block; struct dir_entry * de; if (!suser()) return -EPERM; if (!(dir = dir_namei(pathname,&namelen,&basename))) return -ENOENT; if (!namelen) { iput(dir); return -ENOENT; } if (!permission(dir,MAY_WRITE)) { iput(dir); return -EPERM; } bh = find_entry(&dir,basename,namelen,&de); if (bh) { brelse(bh); iput(dir); return -EEXIST; } inode = new_inode(dir->i_dev); if (!inode) { iput(dir); return -ENOSPC; } inode->i_size = 32; inode->i_dirt = 1; inode->i_mtime = inode->i_atime = CURRENT_TIME; if (!(inode->i_zone[0]=new_block(inode->i_dev))) { iput(dir); inode->i_nlinks--; iput(inode); return -ENOSPC; } inode->i_dirt = 1; if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) { iput(dir); free_block(inode->i_dev,inode->i_zone[0]); inode->i_nlinks--; iput(inode); return -ERROR; } de = (struct dir_entry *) dir_block->b_data; de->inode=inode->i_num; strcpy(de->name,"."); de++; de->inode = dir->i_num; strcpy(de->name,".."); inode->i_nlinks = 2; dir_block->b_dirt = 1; brelse(dir_block); inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); inode->i_dirt = 1; bh = add_entry(dir,basename,namelen,&de); if (!bh) { iput(dir); free_block(inode->i_dev,inode->i_zone[0]); inode->i_nlinks=0; iput(inode); return -ENOSPC; } de->inode = inode->i_num; bh->b_dirt = 1; dir->i_nlinks++; dir->i_dirt = 1; iput(dir); iput(inode); brelse(bh); return 0; } /* * routine to check that the specified directory is empty (for rmdir) */ static int empty_dir(struct m_inode * inode) { int nr,block; int len; struct buffer_head * bh; struct dir_entry * de; len = inode->i_size / sizeof (struct dir_entry); if (len<2 || !inode->i_zone[0] || !(bh=bread(inode->i_dev,inode->i_zone[0]))) { printk("warning - bad directory on dev %04x\n",inode->i_dev); return 0; } de = (struct dir_entry *) bh->b_data; if (de[0].inode != inode->i_num || !de[1].inode || strcmp(".",de[0].name) || strcmp("..",de[1].name)) { printk("warning - bad directory on dev %04x\n",inode->i_dev); return 0; } nr = 2; de += 2; while (nr<len) { if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) { brelse(bh); block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); if (!block) { nr += DIR_ENTRIES_PER_BLOCK; continue; } if (!(bh=bread(inode->i_dev,block))) return 0; de = (struct dir_entry *) bh->b_data; } if (de->inode) { brelse(bh); return 0; } de++; nr++; } brelse(bh); return 1; } int sys_rmdir(const char * name) { const char * basename; int namelen; struct m_inode * dir, * inode; struct buffer_head * bh; struct dir_entry * de; if (!suser()) return -EPERM; if (!(dir = dir_namei(name,&namelen,&basename))) return -ENOENT; if (!namelen) { iput(dir); return -ENOENT; } if (!permission(dir,MAY_WRITE)) { iput(dir); return -EPERM; } bh = find_entry(&dir,basename,namelen,&de); if (!bh) { iput(dir); return -ENOENT; } if (!(inode = iget(dir->i_dev, de->inode))) { iput(dir); brelse(bh); return -EPERM; } if ((dir->i_mode & S_ISVTX) && current->euid && inode->i_uid != current->euid) { iput(dir); iput(inode); brelse(bh); return -EPERM; } if (inode->i_dev != dir->i_dev || inode->i_count>1) { iput(dir); iput(inode); brelse(bh); return -EPERM; } if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ iput(inode); iput(dir); brelse(bh); return -EPERM; } if (!S_ISDIR(inode->i_mode)) { iput(inode); iput(dir); brelse(bh); return -ENOTDIR; } if (!empty_dir(inode)) { iput(inode); iput(dir); brelse(bh); return -ENOTEMPTY; } if (inode->i_nlinks != 2) printk("empty directory has nlink!=2 (%d)",inode->i_nlinks); de->inode = 0; bh->b_dirt = 1; brelse(bh); inode->i_nlinks=0; inode->i_dirt=1; dir->i_nlinks--; dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt=1; iput(dir); iput(inode); return 0; } int sys_unlink(const char * name) { const char * basename; int namelen; struct m_inode * dir, * inode; struct buffer_head * bh; struct dir_entry * de; if (!(dir = dir_namei(name,&namelen,&basename))) return -ENOENT; if (!namelen) { iput(dir); return -ENOENT; } if (!permission(dir,MAY_WRITE)) { iput(dir); return -EPERM; } bh = find_entry(&dir,basename,namelen,&de); if (!bh) { iput(dir); return -ENOENT; } if (!(inode = iget(dir->i_dev, de->inode))) { iput(dir); brelse(bh); return -ENOENT; } if ((dir->i_mode & S_ISVTX) && !suser() && current->euid != inode->i_uid && current->euid != dir->i_uid) { iput(dir); iput(inode); brelse(bh); return -EPERM; } if (S_ISDIR(inode->i_mode)) { iput(inode); iput(dir); brelse(bh); return -EPERM; } if (!inode->i_nlinks) { printk("Deleting nonexistent file (%04x:%d), %d\n", inode->i_dev,inode->i_num,inode->i_nlinks); inode->i_nlinks=1; } de->inode = 0; bh->b_dirt = 1; brelse(bh); inode->i_nlinks--; inode->i_dirt = 1; inode->i_ctime = CURRENT_TIME; iput(inode); iput(dir); return 0; } int sys_link(const char * oldname, const char * newname) { struct dir_entry * de; struct m_inode * oldinode, * dir; struct buffer_head * bh; const char * basename; int namelen; oldinode=namei(oldname); if (!oldinode) return -ENOENT; if (S_ISDIR(oldinode->i_mode)) { iput(oldinode); return -EPERM; } dir = dir_namei(newname,&namelen,&basename); if (!dir) { iput(oldinode); return -EACCES; } if (!namelen) { iput(oldinode); iput(dir); return -EPERM; } if (dir->i_dev != oldinode->i_dev) { iput(dir); iput(oldinode); return -EXDEV; } if (!permission(dir,MAY_WRITE)) { iput(dir); iput(oldinode); return -EACCES; } bh = find_entry(&dir,basename,namelen,&de); if (bh) { brelse(bh); iput(dir); iput(oldinode); return -EEXIST; } bh = add_entry(dir,basename,namelen,&de); if (!bh) { iput(dir); iput(oldinode); return -ENOSPC; } de->inode = oldinode->i_num; bh->b_dirt = 1; brelse(bh); iput(dir); oldinode->i_nlinks++; oldinode->i_ctime = CURRENT_TIME; oldinode->i_dirt = 1; iput(oldinode); return 0; }
/* * linux/fs/read_write.c * * (C) 1991 Linus Torvalds */ #include <sys/stat.h> #include <errno.h> #include <sys/types.h> #include <linux/kernel.h> #include <linux/sched.h> #include <asm/segment.h> extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); extern int read_pipe(struct m_inode * inode, char * buf, int count); extern int write_pipe(struct m_inode * inode, char * buf, int count); extern int block_read(int dev, off_t * pos, char * buf, int count); extern int block_write(int dev, off_t * pos, char * buf, int count); extern int file_read(struct m_inode * inode, struct file * filp, char * buf, int count); extern int file_write(struct m_inode * inode, struct file * filp, char * buf, int count); extern int psread(int dev,char * buf,int count,off_t * f_pos); int sys_lseek(unsigned int fd,off_t offset, int origin) { struct file * file; int tmp; if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) return -EBADF; if (file->f_inode->i_pipe) return -ESPIPE; switch (origin) { case 0: if (offset<0) return -EINVAL; file->f_pos=offset; break; case 1: if (file->f_pos+offset<0) return -EINVAL; file->f_pos += offset; break; case 2: if ((tmp=file->f_inode->i_size+offset) < 0) return -EINVAL; file->f_pos = tmp; break; default: return -EINVAL; } return file->f_pos; } int sys_read(unsigned int fd,char * buf,int count) { struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; verify_area(buf,count); inode = file->f_inode; if (inode->i_pipe) return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; if (S_ISCHR(inode->i_mode)) return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); if (S_ISBLK(inode->i_mode)) return block_read(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISPROC(inode->i_mode)) return psread(inode->i_zone[0],buf,count,&file->f_pos); if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { if (count+file->f_pos > inode->i_size) count = inode->i_size - file->f_pos; if (count<=0) return 0; return file_read(inode,file,buf,count); } printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); return -EINVAL; } int sys_write(unsigned int fd,char * buf,int count) { struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; inode=file->f_inode; if (inode->i_pipe) return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO; if (S_ISCHR(inode->i_mode)) return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); if (S_ISBLK(inode->i_mode)) return block_write(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISREG(inode->i_mode)) return file_write(inode,file,buf,count); printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); return -EINVAL; }
proc.c这样写 要用到put_fs_byte函数,这个试验2用到过。
如果和指导书截图一样把上面的名字也打出来,排版上可能会比较麻烦,我就没写。
刚刚在stat.h里面定义了一个字符数组psbuffer。用处是这样的。
如果把这个数组定义在proc.c里面,因为一次cat可能要调用多次这个处理函数,
这样的话每次调用数据都得更新~~很明显不行的嘛。so,只要在
cat后的第一次调用这个处理函数的时候更新就行了。
如果谁有好的方法,请留言告知。
#include <asm/segment.h> #include <linux/fs.h> #include <linux/sched.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/types.h> #include <unistd.h> #include <string.h> int i,j,k,pid; void addNum(int num){ char c; if (num==0){ psbuffer[j]='0'; j++; psbuffer[j]='\t'; j++; return; } if (num<0){ psbuffer[j]='-'; j++; num=-num; } while (num%10){ psbuffer[j]=(char)((num%10)+'0'); num=num/10; j++; } psbuffer[j]='\t'; j++; } int psread(int dev,char * buf,int count,off_t * f_pos) { struct task_struct * p; if(!(*f_pos)) { j=0; for(k=0;k<1024;k++) psbuffer[k]='\0'; for(i=0;i<64;i++) { p=task[i]; if(p != NULL) { pid = p->pid; addNum(p->pid); addNum(p->state); addNum(p->father); addNum(p->counter); addNum(p->start_time); psbuffer[j]='\n'; j++; } } } for(k=0;k<count;k++) { if(psbuffer[k+(*f_pos)] == '\0') break; put_fs_byte(psbuffer[k+(*f_pos)],buf+k+(*f_pos)); } (*f_pos) = (*f_pos)+k; return k; }