hAPN #A` #  R # n*U #  Y # [ #] # ^ #!"#$%&'ea #()b #* c #+,-.fe #/g #01\o #2345678:q #Kt #LMNOPQRTv #UVx #WXz #YZ[\]^} #_`a' #bcdefghjf #mnopqr #stuv #wxyz{|}O # # #$ # # #q) # #" # # # # # #y/ # # #[É #"ʼn # ʉ # ̉ #ω #҉ # ԉ #~։ #؉ #ى #݉ #߉ #     #A #A0 #;_ #=a #c #g #j # mm #!"o ##$%9r #&'u #'v #(zw #).y #*{ #+} #,-] #. #/00 #1234= #56 #789:;< #=>?@ #ABC #D #EF] #G0 #HIJK...fs7h8include...buf.hcache.ccache.sconst.hdev.hdevice.c device.s file.h filedes.c filedes.s fproc.hfsglo.hinode.cinode.hinode.slink.clink.smain.cmain.smakefilemisc.cmisc.smount.cmount.sopen.copen.sparam.hpath.c path.s!pipe.c"pipe.s#protect.c$protect.s%putc.c&putc.s'read.c(read.s)stadir.c*stadir.s+super.c,super.h-super.s.table.c/table.s0time.c1time.s2type.h3utility.c4utility.s5write.c6write.s/* Buffer (block) cache. To acquire a block, a routine calls get_block(), * telling which block it wants. The block is then regarded as "in use" * and has its 'b_count' field incremented. All the blocks, whether in use * or not, are chained together in an LRU list, with 'front' pointing * to the least recently used block, and 'rear' to the most recently used * block. A reverse chain, using the field b_prev is also maintained. * Usage for LRU is measured by the time the put_block() is done. The second * parameter to put_block() can violate the LRU order and put a block on the * front of the list, if it will probably not be needed soon. If a block * is modified, the modifying routine must set b_dirt to DIRTY, so the block * will eventually be rewritten to the disk. */ EXTERN struct buf { /* Data portion of the buffer. */ union { char b__data[BLOCK_SIZE]; /* ordinary user data */ dir_struct b__dir[NR_DIR_ENTRIES]; /* directory block */ zone_nr b__ind[NR_INDIRECTS]; /* indirect block */ d_inode b__inode[INODES_PER_BLOCK]; /* inode block */ int b__int[INTS_PER_BLOCK]; /* block full of integers */ } b; /* Header portion of the buffer. */ struct buf *b_next; /* used to link bufs in a chain */ struct buf *b_prev; /* used to link bufs the other way */ struct buf *b_hash; /* used to link bufs on hash chains */ block_nr b_blocknr; /* block number of its (minor) device */ dev_nr b_dev; /* major | minor device where block resides */ char b_dirt; /* CLEAN or DIRTY */ char b_count; /* number of users of this buffer */ } buf[NR_BUFS]; /* A block is free if b_dev == NO_DEV. */ #define NIL_BUF (struct buf *) 0 /* indicates absence of a buffer */ /* These defs make it possible to use to bp->b_data instead of bp->b.b__data */ #define b_data b.b__data #define b_dir b.b__dir #define b_ind b.b__ind #define b_inode b.b__inode #define b_int b.b__int EXTERN struct buf *buf_hash[NR_BUF_HASH]; /* the buffer hash table */ EXTERN struct buf *front; /* points to least recently used free block */ EXTERN struct buf *rear; /* points to most recently used free block */ EXTERN int bufs_in_use; /* # bufs currently in use (not on free list) */ /* When a block is released, the type of usage is passed to put_block(). */ #define WRITE_IMMED 0100 /* block should be written to disk now */ #define ONE_SHOT 0200 /* set if block not likely to be needed soon */ #define INODE_BLOCK 0 + WRITE_IMMED /* inode block */ #define DIRECTORY_BLOCK 1 + WRITE_IMMED /* directory block */ #define INDIRECT_BLOCK 2 + WRITE_IMMED /* pointer block */ #define I_MAP_BLOCK 3 + WRITE_IMMED + ONE_SHOT /* inode bit map */ #define ZMAP_BLOCK 4 + WRITE_IMMED + ONE_SHOT /* free zone map */ #define ZUPER_BLOCK 5 + WRITE_IMMED + ONE_SHOT /* super block */ #define FULL_DATA_BLOCK 6 /* data, fully used */ #define PARTIAL_DATA_BLOCK 7 /* data, partly used */ /* The file system maintains a buffer cache to reduce the number of disk * accesses needed. Whenever a read or write to the disk is done, a check is * first made to see if the block is in the cache. This file manages the * cache. * * The entry points into this file are: * get_block: request to fetch a block for reading or writing from cache * put_block: return a block previously requested with get_block * alloc_zone: allocate a new zone (to increase the length of a file) * free_zone: release a zone (when a file is removed) * rw_block: read or write a block from the disk itself * invalidate: remove all the cache blocks on some device */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "super.h" /*===========================================================================* * get_block * *===========================================================================*/ PUBLIC struct buf *get_block(dev, block, only_search) register dev_nr dev; /* on which device is the block? */ register block_nr block; /* which block is wanted? */ int only_search; /* if NO_READ, don't read, else act normal */ { /* Check to see if the requested block is in the block cache. If so, return * a pointer to it. If not, evict some other block and fetch it (unless * 'only_search' is 1). All blocks in the cache, whether in use or not, * are linked together in a chain, with 'front' pointing to the least recently * used block and 'rear' to the most recently used block. If 'only_search' is * 1, the block being requested will be overwritten in its entirety, so it is * only necessary to see if it is in the cache; if it is not, any free buffer * will do. It is not necessary to actually read the block in from disk. * In addition to the LRU chain, there is also a hash chain to link together * blocks whose block numbers end with the same bit strings, for fast lookup. */ register struct buf *bp, *prev_ptr; /* Search the list of blocks not currently in use for (dev, block). */ bp = buf_hash[block & (NR_BUF_HASH - 1)]; /* search the hash chain */ if (dev != NO_DEV) { while (bp != NIL_BUF) { if (bp->b_blocknr == block && bp->b_dev == dev) { /* Block needed has been found. */ if (bp->b_count == 0) bufs_in_use++; bp->b_count++; /* record that block is in use */ return(bp); } else { /* This block is not the one sought. */ bp = bp->b_hash; /* move to next block on hash chain */ } } } /* Desired block is not on available chain. Take oldest block ('front'). * However, a block that is aready in use (b_count > 0) may not be taken. */ if (bufs_in_use == NR_BUFS) panic("All buffers in use", NR_BUFS); bufs_in_use++; /* one more buffer in use now */ bp = front; while (bp->b_count > 0 && bp->b_next != NIL_BUF) bp = bp->b_next; if (bp == NIL_BUF || bp->b_count > 0) panic("No free buffer", NO_NUM); /* Remove the block that was just taken from its hash chain. */ prev_ptr = buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)]; if (prev_ptr == bp) { buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)] = bp->b_hash; } else { /* The block just taken is not on the front of its hash chain. */ while (prev_ptr->b_hash != NIL_BUF) if (prev_ptr->b_hash == bp) { prev_ptr->b_hash = bp->b_hash; /* found it */ break; } else { prev_ptr = prev_ptr->b_hash; /* keep looking */ } } /* If the block taken is dirty, make it clean by rewriting it to disk. */ if (bp->b_dirt == DIRTY && bp->b_dev != NO_DEV) rw_block(bp, WRITING); /* Fill in block's parameters and add it to the hash chain where it goes. */ bp->b_dev = dev; /* fill in device number */ bp->b_blocknr = block; /* fill in block number */ bp->b_count++; /* record that block is being used */ bp->b_hash = buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)]; buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)] = bp; /* add to hash list */ /* Go get the requested block, unless only_search = NO_READ. */ if (dev != NO_DEV && only_search == NORMAL) rw_block(bp, READING); return(bp); /* return the newly acquired block */ } /*===========================================================================* * put_block * *===========================================================================*/ PUBLIC put_block(bp, block_type) register struct buf *bp; /* pointer to the buffer to be released */ int block_type; /* INODE_BLOCK, DIRECTORY_BLOCK, or whatever */ { /* Return a block to the list of available blocks. Depending on 'block_type' * it may be put on the front or rear of the LRU chain. Blocks that are * expected to be needed again shortly (e.g., partially full data blocks) * go on the rear; blocks that are unlikely to be needed again shortly * (e.g., full data blocks) go on the front. Blocks whose loss can hurt * the integrity of the file system (e.g., inode blocks) are written to * disk immediately if they are dirty. */ register struct buf *next_ptr, *prev_ptr; if (bp == NIL_BUF) return; /* it is easier to check here than in caller */ /* If block is no longer in use, first remove it from LRU chain. */ bp->b_count--; /* there is one use fewer now */ if (bp->b_count > 0) return; /* block is still in use */ bufs_in_use--; /* one fewer block buffers in use */ next_ptr = bp->b_next; /* successor on LRU chain */ prev_ptr = bp->b_prev; /* predecessor on LRU chain */ if (prev_ptr != NIL_BUF) prev_ptr->b_next = next_ptr; else front = next_ptr; /* this block was at front of chain */ if (next_ptr != NIL_BUF) next_ptr->b_prev = prev_ptr; else rear = prev_ptr; /* this block was at rear of chain */ /* Put this block back on the LRU chain. If the ONE_SHOT bit is set in * 'block_type', the block is not likely to be needed again shortly, so put * it on the front of the LRU chain where it will be the first one to be * taken when a free buffer is needed later. */ if (block_type & ONE_SHOT) { /* Block probably won't be needed quickly. Put it on front of chain. * It will be the next block to be evicted from the cache. */ bp->b_prev = NIL_BUF; bp->b_next = front; if (front == NIL_BUF) rear = bp; /* LRU chain was empty */ else front->b_prev = bp; front = bp; } else { /* Block probably will be needed quickly. Put it on rear of chain. * It will not be evicted from the cache for a long time. */ bp->b_prev = rear; bp->b_next = NIL_BUF; if (rear == NIL_BUF) front = bp; else rear->b_next = bp; rear = bp; } /* Some blocks are so important (e.g., inodes, indirect blocks) that they * should be written to the disk immediately to avoid messing up the file * system in the event of a crash. */ if ((block_type & WRITE_IMMED) && bp->b_dirt==DIRTY && bp->b_dev != NO_DEV) rw_block(bp, WRITING); /* Super blocks must not be cached, lest mount use cached block. */ if (block_type == ZUPER_BLOCK) bp->b_dev = NO_DEV; } /*===========================================================================* * alloc_zone * *===========================================================================*/ PUBLIC zone_nr alloc_zone(dev, z) dev_nr dev; /* device where zone wanted */ zone_nr z; /* try to allocate new zone near this one */ { /* Allocate a new zone on the indicated device and return its number. */ bit_nr b, bit; struct super_block *sp; int major, minor; extern bit_nr alloc_bit(); extern struct super_block *get_super(); /* Note that the routine alloc_bit() returns 1 for the lowest possible * zone, which corresponds to sp->s_firstdatazone. To convert a value * between the bit number, 'b', used by alloc_bit() and the zone number, 'z', * stored in the inode, use the formula: * z = b + sp->s_firstdatazone - 1 * Alloc_bit() never returns 0, since this is used for NO_BIT (failure). */ sp = get_super(dev); /* find the super_block for this device */ bit = (bit_nr) z - (sp->s_firstdatazone - 1); b = alloc_bit(sp->s_zmap, (bit_nr) sp->s_nzones - sp->s_firstdatazone + 1, sp->s_zmap_blocks, bit); if (b == NO_BIT) { err_code = ENOSPC; major = (int) (sp->s_dev >> MAJOR) & BYTE; minor = (int) (sp->s_dev >> MINOR) & BYTE; if (sp->s_dev == ROOT_DEV) printf("No space on root device (RAM disk)\n"); else printf("No space on device %d/%d\n", major, minor); return(NO_ZONE); } return(sp->s_firstdatazone - 1 + (zone_nr) b); } /*===========================================================================* * free_zone * *===========================================================================*/ PUBLIC free_zone(dev, numb) dev_nr dev; /* device where zone located */ zone_nr numb; /* zone to be returned */ { /* Return a zone. */ register struct super_block *sp; extern struct super_block *get_super(); if (numb == NO_ZONE) return; /* checking here easier than in caller */ /* Locate the appropriate super_block and return bit. */ sp = get_super(dev); free_bit(sp->s_zmap, (bit_nr) numb - (sp->s_firstdatazone - 1) ); } /*===========================================================================* * rw_block * *===========================================================================*/ PUBLIC rw_block(bp, rw_flag) register struct buf *bp; /* buffer pointer */ int rw_flag; /* READING or WRITING */ { /* Read or write a disk block. This is the only routine in which actual disk * I/O is invoked. If an error occurs, a message is printed here, but the error * is not reported to the caller. If the error occurred while purging a block * from the cache, it is not clear what the caller could do about it anyway. */ int r; long pos; dev_nr dev; extern int rdwt_err; if (bp->b_dev != NO_DEV) { pos = (long) bp->b_blocknr * BLOCK_SIZE; r = dev_io(rw_flag, bp->b_dev, pos, BLOCK_SIZE, FS_PROC_NR, bp->b_data); if (r < 0) { dev = bp->b_dev; if (r != EOF) { printf("Unrecoverable disk error on device %d/%d, block %d\n", (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr); } else { bp->b_dev = NO_DEV; /* invalidate block */ } rdwt_err = r; /* report error to interested parties */ } } bp->b_dirt = CLEAN; } /*===========================================================================* * invalidate * *===========================================================================*/ PUBLIC invalidate(device) dev_nr device; /* device whose blocks are to be purged */ { /* Remove all the blocks belonging to some device from the cache. */ register struct buf *bp; for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) if (bp->b_dev == device) bp->b_dev = NO_DEV; } _get_block _get_block: ,#6 31 1 sal cl _buf_hash ,#65535 je I0013 je I0013 1030, I0019 1032, I0019 cmpb 1035 I001D _bufs_in_use I001D: 1035 , I0019: 1028 I0016 _bufs_in_use,#20 I00110 0 _1 _panic I00110: _bufs_in_use _front , I00113: al,1035 jle I00112 1024 je I00112 1024 3 I00112: je I00116 al,1035 jle I00117 I00116: 32768 mov _2 _panic I00117: 1030 31 1 sal cl _buf_hash , I0011E 1030() 31 1 sal cl 1028 _buf_hash(), C I0011E: 1028 je I0011C 1028, I00121 1028 1028(), C I00121: 1028 E I0011C: cmpb 1034,#1 I00124 1032,#65535 4 _rw_block I00124: 1032, 1030, 1035 , 1030 31 1 sal cl _buf_hash mov 1028(), 1030 31 sal cl _buf_hash, ,#65535 8 I00128 _rw_block I00128: _put_block _put_block: ,#6 I0023 I0023: 1035 , al,1035 jle I0026 I0026: _bufs_in_use 1024 1026 je I0029 1024, I002A I0029: _front, I002A: je I002C 1026, I002D I002C: _rear, I002D: testb al,#128 je I002F 1026 _front 1024, _front I00212 _rear, I00213 I00212: _front 1026, I00213: _front, I00210 I002F: _rear 1026, 1024 _rear I00215 _front, I00216 I00215: _rear 1024, I00216: _rear, I00210: testb al,#64 je I00218 cmpb 1034,#1 I00218 1032,#65535 je I00218 _rw_block I00218: 197 I0021D 1032,#65535 I0021D: _alloc_zone _alloc_zone: ,#10 _get_super , 8 1 2() 8() 1 6(bx) #26 _alloc_bit ,#8 I0033 _err_code,#-28 8 38 shr cl , 38 shr cl -10(), 38,#256 I0036 _3 _printk I0037 I0036: -10() _4 _printk I0037: I0031 I0033: 8 1 I0031: _free_zone _free_zone: I0043 I0043: _get_super 8 1 26 _free_bit pop _rw_block _rw_block: ,#8 1032,#65535 je I0053 #1024 1030 .mli4 , , 024 1032 _dev_io ,#14 jge I0053 1032 , ,#-104 je I0059 shr cl 8 shr cl 1030 _5 _printk ,#8 I005A I0059: 1032,#65535 I005A: _rdwt_err, I0053: 1034 _invalidate _invalidate: ,#_buf I0065: ,#_buf+20720 jae I0062 1032, I0063 1032,#65535 I0063: ,#1036 I0065 I0062: mov , _1: 27713 8300 30050 26214 29285 8307 28265 29984 25971 _2: 26144 25970 8293 30050 26214 29285 _3: 29472 24944 25955 28448 8302 28530 29807 25632 30309 25449 8293 21032 19777 25632 29545 10603 10 _4: 29472 24944 25955 28448 8302 25956 26998 25955 9504 12132 25637 10 _5: 28245 25970 28515 25974 24946 27746 8293 26980 27507 25888 29298 29295 28448 8302 25956 26998 25955 9504 12132 25637 8236 27746 25455 8299 25637 10 /* Tables sizes */ #define NR_ZONE_NUMS 9 /* # zone numbers in an inode */ #define NR_BUFS 20 /* # blocks in the buffer cache */ #define NR_BUF_HASH 32 /* size of buf hash table; MUST BE POWER OF 2*/ #define NR_FDS 20 /* max file descriptors per process */ #define NR_FILPS 64 /* # slots in filp table */ #define I_MAP_SLOTS 4 /* max # of blocks in the inode bit map */ #define ZMAP_SLOTS 6 /* max # of blocks in the zone bit map */ #define NR_INODES 32 /* # slots in "in core" inode table */ #define NR_SUPERS 5 /* # slots in super block table */ #define NAME_SIZE 14 /* # bytes in a directory component */ #define FS_STACK_BYTES 512 /* size of file system stack */ /* Miscellaneous constants */ #define SUPER_MAGIC 0x137F /* magic number contained in super-block */ #define SU_UID (uid) 0 /* super_user's uid */ #define SYS_UID (uid) 0 /* uid for processes MM and INIT */ #define SYS_GID (gid) 0 /* gid for processes MM and INIT */ #define NORMAL 0 /* forces get_block to do disk read */ #define NO_READ 1 /* prevents get_block from doing disk read */ #define XPIPE 0 /* used in fp_task when suspended on pipe */ #define NO_BIT (bit_nr) 0 /* returned by alloc_bit() to signal failure */ #define DUP_MASK 0100 /* mask to distinguish dup2 from dup */ #define LOOK_UP 0 /* tells search_dir to lookup string */ #define ENTER 1 /* tells search_dir to make dir entry */ #define DELETE 2 /* tells search_dir to delete entry */ #define CLEAN 0 /* disk and memory copies identical */ #define DIRTY 1 /* disk and memory copies differ */ #define BOOT_BLOCK (block_nr) 0 /* block number of boot block */ #define SUPER_BLOCK (block_nr)1 /* block number of super block */ #define ROOT_INODE (inode_nr) 1 /* inode number for root directory */ /* Derived sizes */ #define ZONE_NUM_SIZE sizeof(zone_nr) /* # bytes in zone nr*/ #define NR_DZONE_NUM (NR_ZONE_NUMS-2) /* # zones in inode */ #define DIR_ENTRY_SIZE sizeof(dir_struct) /* # bytes/dir entry */ #define INODES_PER_BLOCK (BLOCK_SIZE/INODE_SIZE) /* # inodes/disk blk */ #define INODE_SIZE (sizeof (d_inode)) /* bytes in disk inode*/ #define NR_DIR_ENTRIES (BLOCK_SIZE/DIR_ENTRY_SIZE) /* # dir entries/blk*/ #define NR_INDIRECTS (BLOCK_SIZE/ZONE_NUM_SIZE) /* # zones/indir blk */ #define INTS_PER_BLOCK (BLOCK_SIZE/sizeof(int)) /* # integers/blk */ #define SUPER_SIZE sizeof(struct super_block) /* super_block size */ #define PIPE_SIZE (NR_DZONE_NUM*BLOCK_SIZE) /* pipe size in bytes*/ #define MAX_ZONES (NR_DZONE_NUM+NR_INDIRECTS+(long)NR_INDIRECTS*NR_INDIRECTS) /* max # of zones in a file */ #define printf printk /* Device table. This table is indexed by major device number. It provides * the link between major device numbers and the routines that process them. */ EXTERN struct dmap { int (*dmap_open)(); int (*dmap_rw)(); int (*dmap_close)(); int dmap_task; } dmap[]; /* When a needed block is not in the cache, it must be fetched from the disk. * Special character files also require I/O. The routines for these are here. * * The entry points in this file are: * dev_open: called when a special file is opened * dev_close: called when a special file is closed * dev_io: perform a read or write on a block or character device * do_ioctl: perform the IOCTL system call * rw_dev: procedure that actually calls the kernel tasks * rw_dev2: procedure that actually calls task for /dev/tty * no_call: dummy procedure (e.g., used when device need not be opened) */ #include "../h/const.h" #include "../h/type.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "dev.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" PRIVATE message dev_mess; PRIVATE major, minor, task; extern max_major; /*===========================================================================* * dev_open * *===========================================================================*/ PUBLIC int dev_open(dev, mod) dev_nr dev; /* which device to open */ int mod; /* how to open it */ { /* Special files may need special processing upon open. */ find_dev(dev); (*dmap[major].dmap_open)(task, &dev_mess); return(dev_mess.REP_STATUS); } /*===========================================================================* * dev_close * *===========================================================================*/ PUBLIC dev_close(dev) dev_nr dev; /* which device to close */ { /* This procedure can be used when a special file needs to be closed. */ find_dev(dev); (*dmap[major].dmap_close)(task, &dev_mess); } /*===========================================================================* * dev_io * *===========================================================================*/ PUBLIC int dev_io(rw_flag, dev, pos, bytes, proc, buff) int rw_flag; /* READING or WRITING */ dev_nr dev; /* major-minor device number */ long pos; /* byte position */ int bytes; /* how many bytes to transfer */ int proc; /* in whose address space is buff? */ char *buff; /* virtual address of the buffer */ { /* Read or write from a device. The parameter 'dev' tells which one. */ find_dev(dev); /* Set up the message passed to task. */ dev_mess.m_type = (rw_flag == READING ? DISK_READ : DISK_WRITE); dev_mess.DEVICE = (dev >> MINOR) & BYTE; dev_mess.POSITION = pos; dev_mess.PROC_NR = proc; dev_mess.ADDRESS = buff; dev_mess.COUNT = bytes; /* Call the task. */ (*dmap[major].dmap_rw)(task, &dev_mess); /* Task has completed. See if call completed. */ if (dev_mess.REP_STATUS == SUSPEND) suspend(task); /* suspend user */ return(dev_mess.REP_STATUS); } /*===========================================================================* * do_ioctl * *===========================================================================*/ PUBLIC do_ioctl() { /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */ struct filp *f; register struct inode *rip; extern struct filp *get_filp(); if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code); rip = f->filp_ino; /* get inode pointer */ if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) return(ENOTTY); find_dev(rip->i_zone[0]); dev_mess.m_type = TTY_IOCTL; dev_mess.PROC_NR = who; dev_mess.TTY_LINE = minor; dev_mess.TTY_REQUEST = m.TTY_REQUEST; dev_mess.TTY_SPEK = m.TTY_SPEK; dev_mess.TTY_FLAGS = m.TTY_FLAGS; /* Call the task. */ (*dmap[major].dmap_rw)(task, &dev_mess); /* Task has completed. See if call completed. */ if (dev_mess.m_type == SUSPEND) suspend(task); /* User must be suspended. */ m1.TTY_SPEK = dev_mess.TTY_SPEK; /* erase and kill */ m1.TTY_FLAGS = dev_mess.TTY_FLAGS; /* flags */ return(dev_mess.REP_STATUS); } /*===========================================================================* * find_dev * *===========================================================================*/ PRIVATE find_dev(dev) dev_nr dev; /* device */ { /* Extract the major and minor device number from the parameter. */ major = (dev >> MAJOR) & BYTE; /* major device number */ minor = (dev >> MINOR) & BYTE; /* minor device number */ if (major == 0 || major >= max_major) panic("bad major dev", major); task = dmap[major].dmap_task; /* which task services the device */ dev_mess.DEVICE = minor; } /*===========================================================================* * rw_dev * *===========================================================================*/ PUBLIC rw_dev(task_nr, mess_ptr) int task_nr; /* which task to call */ message *mess_ptr; /* pointer to message for task */ { /* All file system I/O ultimately comes down to I/O on major/minor device * pairs. These lead to calls on the following routines via the dmap table. */ int proc_nr; proc_nr = mess_ptr->PROC_NR; if (sendrec(task_nr, mess_ptr) != OK) panic("rw_dev: can't send", NO_NUM); while (mess_ptr->REP_PROC_NR != proc_nr) { /* Instead of the reply to this request, we got a message for an * earlier request. Handle it and go receive again. */ revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS); receive(task_nr, mess_ptr); } } /*===========================================================================* * rw_dev2 * *===========================================================================*/ PUBLIC rw_dev2(dummy, mess_ptr) int dummy; /* not used - for compatibility with rw_dev() */ message *mess_ptr; /* pointer to message for task */ { /* This routine is only called for one device, namely /dev/tty. It's job * is to change the message to use the controlling terminal, instead of the * major/minor pair for /dev/tty itself. */ int task_nr, major_device; major_device = (fp->fs_tty >> MAJOR) & BYTE; task_nr = dmap[major_device].dmap_task; /* task for controlling tty */ mess_ptr->DEVICE = (fp->fs_tty >> MINOR) & BYTE; rw_dev(task_nr, mess_ptr); } /*===========================================================================* * no_call * *===========================================================================*/ PUBLIC int no_call(task_nr, m_ptr) int task_nr; /* which task */ message *m_ptr; /* message pointer */ { /* Null operation always succeeds. */ m_ptr->REP_STATUS = OK; } _dev_open _dev_open: _find_dev 3 _major sal cl _dmap _dev_mess _task () _dev_mess+6 _dev_close _dev_close: _find_dev 3 _major sal cl _dmap+4 _dev_mess _task () _dev_io _dev_io: _find_dev I0033 3 I0034 I0033: 4 I0034: _dev_mess+2 shr cl _dev_mess+4, _dev_mess+10, 10() _dev_mess+10+2, 1 _dev_mess+6, 1 _dev_mess+18, 12() _dev_mess+8, 3 _major sal cl _dmap+2 _dev_mess _task () _dev_mess+6,#-998 I0036 _task _suend I0036: _dev_mess+6 _do_ioctl _do_ioctl: _m+4 _get_filp I0043 _err_code I0041 I0043: 4 61440 8192 je I0046 -25 I0041 I0046: 14 _find_dev _dev_mess+2,#5 _who _dev_mess+6, _minor _dev_mess+4, _m+8 _dev_mess+8, #_dev_mess+10 #_m+10 4 rep mov 3 _major sal cl _dmap+2 _dev_mess _task () _dev_mess+2,#-998 I0049 _task _suend I0049: #_m1+10 #_dev_mess+10 4 rep mov _dev_mess+6 I0041: _find_dev: 8 shr cl _major, shr cl _minor, _major je I0052 _m_major _major, jl I0053 I0052: _major _1 _panic I0053: 3 _major sal cl _dmap+6 _task, _minor _dev_mess+4, _rw_dev _rw_dev: 6 _sendrec je I0066 32768 _2 _panic I0066: 4, je I0065 6 4() _revive _receive I0066 I0065: _rw_dev2 _rw_dev2: _fp 8 52 shr cl 3 sal cl _dmap+6() _fp 52 shr cl 4, _rw_dev _no_call _no_call: 6 _task: .zerow 2/2 _minor: .zerow 2/2 _major: .zerow 2/2 _dev_mess: .zerow 24/2 _1: 24930 8292 24941 28522 8306 25956 118 _2: 30578 25695 30309 8250 24931 10094 8308 25971 10 /* This is the filp table. It is an intermediary between file descriptors and * inodes. A slot is free if filp_count == 0. */ EXTERN struct filp { mask_bits filp_mode; /* RW bits, telling how file is opened */ int filp_count; /* how many file descriptors share this slot? */ struct inode *filp_ino; /* pointer to the inode */ file_pos filp_pos; /* file position */ } filp[NR_FILPS]; #define NIL_FILP (struct filp *) 0 /* indicates absence of a filp slot */ /* This file contains the procedures that manipulate file descriptors. * * The entry points into this file are * get_fd: look for free file descriptor and free filp slots * get_filp: look up the filp entry for a given file descriptor * find_filp: find a filp slot that points to a given inode */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" /*===========================================================================* * get_fd * *===========================================================================*/ PUBLIC int get_fd(bits, k, fpt) mask_bits bits; /* mode of the file to be created (RWX bits) */ int *k; /* place to return file descriptor */ struct filp **fpt; /* place to return filp slot */ { /* Look for a free file descriptor and a free filp slot. Fill in the mode word * in the latter, but don't claim either one yet, since the open() or creat() * may yet fail. */ register struct filp *f; register int i; *k = -1; /* we need a way to tell if file desc found */ /* Search the fproc table for a free file descriptor. */ for (i = 0; i < NR_FDS; i++) { if (fp->fp_filp[i] == NIL_FILP) { /* A file descriptor has been located. */ *k = i; break; } } /* Check to see if a file descriptor has been found. */ if (*k < 0) return(EMFILE); /* this is why we initialized k to -1 */ /* Now that a file descriptor has been found, look for a free filp slot. */ for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { if (f->filp_count == 0) { f->filp_mode = bits; f->filp_pos = 0L; *fpt = f; return(OK); } } /* If control passes here, the filp table must be full. Report that back. */ return(ENFILE); } /*===========================================================================* * get_filp * *===========================================================================*/ PUBLIC struct filp *get_filp(fild) int fild; /* file descriptor */ { /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ err_code = EBADF; if (fild < 0 || fild >= NR_FDS ) return(NIL_FILP); return(fp->fp_filp[fild]); /* may also be NIL_FILP */ } /*===========================================================================* * find_filp * *===========================================================================*/ PUBLIC struct filp *find_filp(rip, bits) register struct inode *rip; /* inode referred to by the filp to be found */ int bits; /* mode of the filp to be found (RWX bits) */ { /* Find a filp slot that refers to the inode 'rip' in a way as described * by the mode bit 'bits'. Used for determining whether somebody is still * interested in either end of a pipe; other applications are conceivable. * Like 'get_fd' it performs its job by linear search through the filp table. */ register struct filp *f; for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { if (f->filp_count != 0 && f->filp_ino == rip && (f->filp_mode & bits)){ return(f); } } /* If control passes here, the filp wasn't there. Report that back. */ return(NIL_FILP); } _get_fd _get_fd: ,#-1 I0015: ,#20 jge I0012 _fp sal 1 6 I0013 I0012 I0015 jge I001A -24 I001A: ,#_filp I001F: ,#_filp+640 jae I001C 2 I001D 6 8 I001D: ,#10 I001F I001C: -23 _get_filp _get_filp: _err_code,#-9 jl I0022 ,#20 jl I0023 I0022: I0021 I0023: _fp sal 1 6 I0021: _find_filp _find_filp: ,#_filp I0035: ,#_filp+640 jae I0032 2 je I0033 4, I0033 test je I0033 I0031 I0033: ,#10 I0035 I0032: I0031: /* This is the per-process information. A slot is reserved for each potential * process. Thus NR_PROCS must be the same as in the kernel. It is not possible * or even necessary to tell when a slot is free here. */ EXTERN struct fproc { mask_bits fp_umask; /* mask set by umask system call */ struct inode *fp_workdir; /* pointer to working directory's inode */ struct inode *fp_rootdir; /* pointer to current root dir (see chroot) */ struct filp *fp_filp[NR_FDS]; /* the file descriptor table */ uid fp_realuid; /* real user id */ uid fp_effuid; /* effective user id */ gid fp_realgid; /* real group id */ gid fp_effgid; /* effective group id */ dev_nr fs_tty; /* major/minor of controlling tty */ int fp_fd; /* place to save fd if rd/wr can't finish */ char *fp_buffer; /* place to save buffer if rd/wr can't finish */ int fp_nbytes; /* place to save bytes if rd/wr can't finish */ char fp_suspended; /* set to indicate process hanging */ char fp_revived; /* set to indicate process being revived */ char fp_task; /* which task is proc suspended on */ } fproc[NR_PROCS]; /* Field values. */ #define NOT_SUSPENDED 0 /* process is not suspended on pipe or task */ #define SUSPENDED 1 /* process is suspended on pipe or task */ #define NOT_REVIVING 0 /* process is not being revived */ #define REVIVING 1 /* process is being revived from suspension */  Va&ZUPsoeee0uP1Pee>e|>eE|Fe㋇ZЉF>etv6e^^>et+UP>euFe~ir^=u{F-e@e^w6XS%Se^G6S%Se^_8e^_:e^G<^G=e]ÃF@kPVPJ^^ePtP@N^^ t PVPJ^^eeee]U^eePvN^^]UiF~}mFÁeePP24^^FeFGvc7^eFGeG.eG0eG2eG3eF덉]U rlvlltlFl~s5^LJ^LJ^ v^vF pFl~rQ1ۉF^FFF-F1PFvvQ[YZځ1RQPFvvQ[YZځRQMQ tN~luvlpt9~utl$^v ^vF .Fl~s^vF vlxl]UV^V^V^1PPP5F2Pv\P"GF\^wXP=t PHWP!H^^^vwD PPXPF~~ vtWPG^^F`PFPv6^^eBF:PeF+PeFFFFPe^eeP1PJ^^ t PWP_G^^ee11ۋNNPQXO1YFQOeeeee^eePPJ^^ t PWPF^^WPzJ^FFvXO[9r1PvP3FPvP3FPvvfE^Ƈ Pv5^^Pv5^^11^ORP1PPOFNvv1PPOu u1PvvWPIFF6 XPI^]UPPF\~]s^G&F2F\^G&1Pv7/^^PP/^^F^%=@u#^G 0=|^wXN=t PJXPE^^^FG*v2^^FG(^G0P)^ t PXPGE^^]U P6e6eD t6,eFPFPPx7F~tve7ezM% [!Á^1Pv.ePNF,e^~t ~tv~uj^%PX1PPv<F~uFv'^=F61PPv<F~t^Pw^^FXZL~t v.^v%eFËFG^G^FGvX]UP>euPmP6e6eXC t6,eQe7eVL% [!SeCL%[ ؉Fe.LPv.ePP.^6,eX]UFPv^^F~u1PFPv^^F~t>,et^vw (.^^F~u v-^1P^ ^^0@^FGPv/^^^P"SFPvF~tIvT-^^ ^^0H^G&v2-^^,e1P%~tF,e^v -^^,evX]U >e|>e~P'P6e6eA t6,e e1XPXJFFPFPv~4F~tv.eP^F~u6,e1Pvv:F~t vU,^v^%P^Ft_v7,^Pwe4u ^6eGD4FJ^Pw^^!FI^Pw^^XZIeFËFG^G^FGvX]U 6e4^F~u6,e^GF^%IFFtI= tFcI=`u3FRI=`ueuteGtceSXG%GFeSXG%zGFekG%?_Ge e^F>eu1P>et>e}P6e1^F~u6,e~uPP^[uPq^GwFFF^-u!tC }PD^GF^GwFFFFF^%FFFF=`uF^-u u FFp\FJF= uT^6e6e6evvwv5F~}F FFFFVFVF~trFE=`ta^vvw %^áeO w)X[)u!tC ~PF^+F^u!tC ~1Pvvv ^'t&FP6evvvk F~v>eu*vv1PP6FVeE+^9veEP+FPXDF~}+FDF~uGF^+F^F^F^-u!tC F+FVu!tB ~FFvv6evvvvvvF~tL>p\}C^eee+^eFv1D[É^FFVFVF~u]FD= t7FC=`t&F^+F^u!tC ~^FNGOr9^GW ^G&\^'tS^FN+GOu!tA |9^GGFFPv-^^Fރ~t ^GG^FNGO~u^^)uUvv1PP/Du u7F C=tFB=@u^e^e^eFB=u^G)>p\tp\^>p\uFBF~uv FBPXBPX]U^%=`t1PPF~tvv1PPmBF^GFvvvmF^G F~uF~u@~u1PPP&Fv ^uvvv@F~u]6,e ~u ~ uP1PF~u%~ u^FN+GOu!tA |Fvvv?&F~u4~ t-~u'^FN+GOu!tA | ~ uv^~u1PPFf ^vSF APvvv F~u^Ƈ F @F =uPPFvvg'^^vX]Uvu!^Fvv1PP@FNF왉F^F^F왉F^NV)ډNF^-u!tC }_^S1^F,A[ËF~u1PFv@@XPF?[É^v~F^-F^F^-u!tC } ^GF^GF~u1P4F^-F^Fv?v?XF^1Pvw $Fvvv1PPk?1É2@[ËFBPv%^^vv1PP@V^~u1PFv>>XF^1Pvw #F1^Fv?[ËFBPvH%^^~u1P3Fv>>XPFu>[É^vX]U~u2v\x\F |\~\^w\^z\1^\\0^v\^x\1^|\~\w\z\F \\1^ \\r\P7^t\]Ue^e6e6evF~u]Ë^1Pvw ]"FPv-$^^]UP^]U^G&Fv$^Fvv1PPu=QPFX[F^F^-u!tC }/^v S1^F>[Ï2^GW 1PF^-F^FFF^-u!tC } ^^^GF~u/^vwt {$^^F~u6,e^FGFF^-F^vv1PPxe~PPv1P~ ~PPv!^^=u-\@e-e@\\\P1P71^^PTF ^ W-u!tB ~ 1P6^1P+^ O-u uPPvaPX]U~ueeG<e e6e\6eeO8eeO:F؋eG>e]UPFe~irs^<ud^w6Xd5%PFT5[9u?^vD6Ë_F9Gu"F-e@1SP^^eNu]ÃF@냉]UP~|~| vXP],^^FÁe^^<t ^=u]Ë^9;<=>?@ABCDEFGHIJ>u ^G=e^G<^FG:vvq^^]U >e~P2e^~|~| vXP+^^FÁe^^<u1P^G>0؉F~u^G64%4F~|~| PXP[+^^^FËGF^_GF1ɋF%3\^\\\Pv.^^ t PXP*^^F9\t,6\6\r^^ePvb.^^ tڸP YP*^^˸PvG^^1PX]Uvx^\㋇^[\S6\^^\]UvN^\㋇b[\S6\^^]Uv'^~uPP\1ɋF%2\^\^ \^\^\^ \\㋇`[\S6\^^>\u6\^\]UPP6e^F~u6,e^GF^%= tPk^wg^\e\\\e\\e\㋇`[\S6\^^>\u6\^e\6\X]UF%1\1ɋF%1\>\t [9\| 6\YP(^^\㋟d[\\\]UP^GFvv<,^^ t P&YP(^^^F9Gt^vwt^^vv+^^׉]UPPeG4%0FFËd[Fe1ɋG4%0^GvvS^^]U^G]UFPv9^^F~u1P$~uvFPvO^^FvN^vX]U^?/u ewewFv^vvW^^F~u v^1P;^?uv.vv^^Fv^~u1PFFFFX]UFFFF^0䘉F~/uF~es4~/t.~t(^9^s ^FFF^0䘉FŃ~/u~esF^0䘉F^9^s ^F~er ,e1PvX]U ^?u^vw"t T^^P1PFPvvF~t ^,e1P^vw ^^F~u1P^"tr^"uiF@À?.u^F$]~]sR^vD 9G&u>va^^_*G F^_*w"v^^Fvv-^^Fv,^F2맋^(u8F\~]s^F9G*uv^^Pw&V^^FŃF2vX]U^%=@tP6~ uPPF1PvvOF~tv^ww1PP-FFFFF^FN+GOu!tA |vvvF^1Pvw FFF^9^rFFF9Fv~ tF~ t_^?tW^PvS" t?~ u^^Ƈ c"^GW ^^APv0^^1P~ u^?uFFN~t!APv^^F^F^~ tP~u=FF~uP^wwviF~u6,elFF^PvS0"^^^Ƈ APvc^^r!^GW ^G&F9Fv11^,^GW1PX]U>euPAP6e6eL" t6,e$.ePC^F~u6,e FFF\~]s%^F9G&uF^&uFFF2ԃ~tP~uP^FG&1Pv ^^^FG&^wX*=u#^?r^r^r ^s^G&PSP6e6e^! t^G&6,e..eP^F~u^G&6,eF^$~F^%F~`t~ uFF~uPv_ ^^F~u,e^~t ^?uFF~uv^ tFF~u^%=@u^%=@tF~t2v ^v{ ^~tv^6v^^G&v&^G(^FG*^FG(^eO01PX]U >euPP6e6e t6,e.eP^F~u6,eFF]~,cs&^$~^F9G u ^FG$FF*Ӄ~~PFF\~]s^F9G&uFFF2~tv^ t P:YP^^v^~uP1^_*G(^w*- ^^w(# ^^G*^G&1PX]UPPvq^F~uP3^%=`t,ev ^P^GFv ^vX]UP6e6e t6,eE.eP^F~u6,e-F^ uF~u^%=@u >euF~t v> ^vP6e6e tv ^6,eFP.eP^^F~u,e^~u5FPv^^F~u,e^~uF v^F~u^vD 9G tF~u^P"SFPvF~u^ ^^0@^G&vZ^vS^vX]UP6e6e t6,eFP.eP^^F~u6,eFFPv^^F~u,e^~t v^vi^%=@u >euF~uPFPFPvF~u^ ^^0H^G&vy^vr^vX]U^G Fv^FF1F^^'u ^GGFF^FN+GOu!tA }Wvvv7F~t+Fv$$XFvv ^^F^F^F^돋^wvl ^^^GF~tnFv$x$XF1Pvv FFF^9^s^7v ^^FBPv ^^vv ^^v^]Uv@^F^wrl#[Ëv\rP ^w ^v PDYP4^^FF#^9Gv.F1R#PvK^NˉGF뾋^GFFF]#^9Gv.F1RF#FPv^NˉGF뾋^GF^ ^GF^ rl"^v_\SX"rl1PX]Uv^Frl"^v_\)SX"rlFF"^9Gv^FøPw ^^FFFR"^9Gv^FøPw^^F1]UF9F rF F "F Fv ![)SX!FFF~uvFPX!FvNX uF^FF^^^^F9Fu^7Xd!F~uF~|Fv;!2!XuiF+FF ^É^F 9Fw ^^2FF^N ^Ƈ F P1FgF5FF 9FuFF1PX]U Fs F Fv\ [)SXN FFFFVF^F~u]ËF^NuFPXYPe^^F^^N#^Ƈ ]UPF\~]s^F9G&uv F2FPYP^^]X]UPP^GF~uP&F\~]s^F9G&uP F21PX]UP^w h^F^G ]UPP~u7^G&F1PPw&F2Pvv;^FG&,^PPw&F2Pvv ^Ƈ ^G1PvB^^]UFF]~,cs>^$~)^F9G u$^F9G"u^$^@vKFFF*뻃~u ,e1P.^FG ^FG"^G$~t 1Pv ^^vX]UP~u]Ë^$^H^?uD^ u&vd^^^G'^vw"t ^^^&u Pv^^]U v^F^vv1QwPVFF~t,e^G&F=%1F^1ɋG&%F^&u YP^vvYP1PhFFvP*^^F~u^vS(^^9F^^G evG0DevG3D ^FG v ^vX]UP^GG ^GW ^G&F~ }^FGF]UPvQ^F^vS^^]U^w +^F^G"- 1^GGF^1Pvw F^G"- 1^^~u Pvv Pvv^Ƈ @Pv^^^G&]UP^$^@]UF%ËxlF~tS~tM^F9u5^F9u)^ url^ ^^0@vt^F뭃>rlu PYP0^^rlvl^^ 0 ~^t ^F܃~t^ 0 ~ PZP^^^%ËxlFF9Fu^v%Ƌxl2^t(^F9u^v ^F΋^ u^t Pv^^^F^F^ ^^0@^%Ëvxl^%ËFxl~t~u 1Pvm^^vX]U~u]Ë^ ^^0H^ 0 ~]rl^FF~t ^F^vl~t ^F^tlFt8^LJ^vl>vlu ^tl vlF^vl6^tl^LJ>tlu ^vl tlF^tlF\@t ^ u^t Pv9^^F,=u ^LJ]U vC^F^G-+F؉Fv~D+EvwPVF~t,e^G&%F^1ɋG&%sF^&u "ZPl^vvFZP\1P ^G-FPX]UP~u]vV^F^G-+FPS}^^]U^u^11FV^vPPvvvF~}K^F~t+^1ɋF%VPR`ZP ^LJ^p\^Ƈ ]UPFl~s^F9u ^LJF ݉]UPP^F~} eFÃu F^Fڋ^?}PAFi~rls1^u"F^^GGF^1P F ȸPX]U,e~|~|1PeFwX]UPFi~rls5^t&^F9Gu^7F9[tv F 1PX]UP>eucee^ew^>et ew^weXGewy^>et1P^w0eXG01Pe6e6eS;PX]UP>euPe6e6eSFvX]UPPPvv6  t6,ed.eP^F~u6,eM^%=@tF1PPvF~t v^v^7^F^1PX]UPPP6e6e  t6,e4.eP ^F~u6,e6e1PvIFv^vX]UP6e^F~u6,e^6evw PX]U&^^^w X3^^vG"D^vD^1G PX^G^vGD^1G PX^G ^wX^G ^vG_D\^'u-~t'^?u^^ڋ^ڋvO+DLO^vG_ D\^vG_ D\^vG_ D\FF1PvPv6ePӃ FދFމ]UPPP6e6e t6,e.eP\^F~u6,ej^6eD09Gt>euF vS^F~t v^v1^%Pe% [ ؋^^G&vt^1PX]UPP>euPhP6e6e4 t6,eL.eP^F~u6,e5v^F~u^eO^eO ^G&v^vX]UPeЉFe%ЋeF]UPPP6e6e t6,e>.eP^F~u6,e'eRuPvFv[^vX]U^F~t ew.ew0F~t eG20P eG30PF~uFO^G9FuF^G 09FuFFFvX%FFF F9FtFFIFt FFuF~uFt v ^FF]UP^w ^F^0tP1PX]UPPP6e6e t6,e_.eP^F~u6,eHF^6eD09Gt >euF~u^eeOW ^G&v^vX]Uhee1]UP>euP;\e6e\\\PPt ^^F~t vZP^^1PX]UFP6e^^^e^e^e^e^e^e^e^e1]U e % Fe^v@^=u6,eF9euFPeP1PF~t3vf>e|>e|PRe9^u6eCeeË^FËve΋GD^eˋ_^@6eX]UPc^F^G,W.^0u^G1F]~,cs$^$~^&u Pv^^F*F\~]s$^&t^1u Pv^^F2Fl~s8^F~t!^ u1ɋFu Pvr^^F Fl~s8^F~t!^ u1ɋFt Pv.^^F 1]U >etPee^ee^F@vNX tvF[vFee^F~}-^FÃt^FË_^@F͋^w^^w^1PX]UPP>etPueeee^e<u e>ue^e֋eG<F~}^eBFew^ew^1PX]UP>etPIee^>eu^eO.^eO0>e.u^eO3^eO21PX]U>e~P6e6eZ^^e1PX]UPP\\PP5^^F~t vZP^^PQ^F^\\O,W.^0u^G1\\]UvF[0PvF[0[9t1P NuָPX]U~]ûF uNF uAF u4FFFFFFvF[7vF[XNu*FFFFFFvF[vFNu]U~u-~'F.eFevF[vFNu1PF~~ ,eP3FFFR.eRPv6ePAʃ ,e6,eX]U]U>\t]\vZP~^^Fc=t vZPa^^ZPX^ ]U~u4]1FPP6$$[XX>$du ~ u]U>$u]$PP^^$]U1PPPPvvPP]U1PPPPPvPPm2v]U^,^.^6PP^^]U1PPPvvvPP]U1PPvPPvPP]U1PPvPPvPP]U^GvP^^ t P[P/^^]U1PPvPPvPP^,.W^02OW^46OW ^8:O W]U1PPPPPP PP)]U1PPPv vvvP]U^,^ .^ 0^2^4^6vvd^^]UPPv ^F^,^.^ 0F2~ vNX tv F [vFvv^^]UP^*(Pva^^F~tv>*}*ۉ&P6*X]UPFvF[0 tFF@]ù UF^ ]U$^^^?uc^?%tvF[0P^FF^0=0|+^0=9^0-0P f[É^FȋFFFF^0PvF[FFFVF nvF[FF/F1^^FF?vF[FFF1^^FFvF[wFFF FFvF[wFFFFFvF[wFFFFFvF[Fv4^FvF[FFFFFvF[0Fݘ t F0P^߃FF+FH+F؉F~/vNX u! P^%P^vF[0P^[ZFPvvvUFF+FF~~vNX t Pc^FHF~|vB0PF^NF]U FF^-u u ^ 0PF^-u!tC }~ u^F^FFF~ }^^ FF~ u@vv1P P^^ ^^ 0䘙^N)QS1P PFN~u=Fv[%^^ F^%F^~u=FvZ[%^^ F^%F^FF^-u tFFHF~|b^^ ?u~u ^^  A^^ 0= }^^ ^^00^^ ^^07FN똃~t-Pv vF[XXvX]ÌøXW )&1&u=u_[1YZ^_9w r9wtH@Ë+\;\w Xu Ӆu㭓I|9Эuu_9tt uu Zu1RPhUW)V F^Ny ؃ׅy كt؃_]uÉ)щ)UWV)u&GW߈(ɉ͈(ɈԈ(RPQ9r WWRP)_)ǃ։^)ƃX)y M_t݈lj)^_]É\D9u1!}t)1ҋLD!}1ۃ|}ڃ1!}\ߋDT!}ڹ9wr9Tv+T@미[[[\,\ B\Y\SPPUB^D^F^J@PP@ ]get_work couldn't revive anyonefs receive errorZONE_NUM_SIZE != 2SUPER_SIZE > BLOCK_SIZEBLOCK_SIZE % INODE_SIZE != 0NR_FDS > 127NR_BUFS < 6inode size != 32Diskette in drive 0 is not root file systemRAM disk is too big. # blocks = FS Can't report to MMCan't report size to MEMLoading RAM disk from root diskette. Loaded: 0K %3DK %c RAM disk loaded. Please remove root diskette. Root file system corrupted. Possibly wrong diskette.init: can't load root bit maps @`n  g @T ` \  ' @ revive errunpause err 1unpause err 2unpause err 3unpause err 4bad major devrw_dev: can't senddo_umounttoo many map blocksfreeing unused block or inode--check file syscan't find superblock for device (in decimal)Out of i-nodes on root device (RAM disk) Out of i-nodes on device %d/%d All buffers in useNo free bufferNo space on root device (RAM disk) No space on device %d/%d Unrecoverable disk error on device %d/%d, block %d do_stime errorclock_time errFile system panic: %s %d ,eL8I~H  L,M.L}?E B,CL@ L)l+ILELLAL[ELLCLLcGLLLLFDFLLILLLLLLL3"LLLLLC@LLL L#JL#G###G###G###G######G##sys_copy can't sendQDPOPXPcQd7PoVPs2QxPError: Division by 0 Illegal EM instruct'n Err in EM case instr Variable out of range Err in EM set instr Floating pt not impl. Heap overflow /* File System global variables */ EXTERN struct fproc *fp; /* pointer to caller's fproc struct */ EXTERN int super_user; /* 1 if caller is super_user, else 0 */ EXTERN int dont_reply; /* normally 0; set to 1 to inhibit reply */ EXTERN int susp_count; /* number of procs suspended on pipe */ EXTERN int reviving; /* number of pipe processes to be revived */ EXTERN file_pos rdahedpos; /* position to read ahead */ EXTERN struct inode *rdahed_inode; /* pointer to inode to read ahead */ /* The parameters of the call are kept here. */ EXTERN message m; /* the input message itself */ EXTERN message m1; /* the output message used for reply */ EXTERN int who; /* caller's proc number */ EXTERN int fs_call; /* system call number */ EXTERN char user_path[MAX_PATH];/* storage for user path name */ /* The following variables are used for returning results to the caller. */ EXTERN int err_code; /* temporary storage for error number */ EXTERN char fstack[FS_STACK_BYTES]; /* the File System's stack. */ /* This file manages the inode table. There are procedures to allocate and * deallocate inodes, acquire, erase, and release them, and read and write * them from the disk. * * The entry points into this file are * get_inode: search inode table for a given inode; if not there, read it * put_inode: indicate that an inode is no longer needed in memory * alloc_inode: allocate a new, unused inode * wipe_inode: erase some fields of a newly allocated inode * free_inode: mark an inode as available for a new file * rw_inode: read a disk block and extract an inode, or corresp. write * dup_inode: indicate that someone else is using an inode table entry */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "super.h" /*===========================================================================* * get_inode * *===========================================================================*/ PUBLIC struct inode *get_inode(dev, numb) dev_nr dev; /* device on which inode resides */ inode_nr numb; /* inode number */ { /* Find a slot in the inode table, load the specified inode into it, and * return a pointer to the slot. If 'dev' == NO_DEV, just return a free slot. */ register struct inode *rip, *xp; /* Search the inode table both for (dev, numb) and a free slot. */ xp = NIL_INODE; for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) { if (rip->i_count > 0) { /* only check used slots for (dev, numb) */ if (rip->i_dev == dev && rip->i_num == numb) { /* This is the inode that we are looking for. */ rip->i_count++; return(rip); /* (dev, numb) found */ } } else xp = rip; /* remember this free slot for later */ } /* Inode we want is not currently in use. Did we find a free slot? */ if (xp == NIL_INODE) { /* inode table completely full */ err_code = ENFILE; return(NIL_INODE); } /* A free inode slot has been located. Load the inode into it. */ xp->i_dev = dev; xp->i_num = numb; xp->i_count = 1; if (dev != NO_DEV) rw_inode(xp, READING); /* get inode from disk */ return(xp); } /*===========================================================================* * put_inode * *===========================================================================*/ PUBLIC put_inode(rip) register struct inode *rip; /* pointer to inode to be released */ { /* The caller is no longer using this inode. If no one else is using it either * write it back to the disk immediately. If it has no links, truncate it and * return it to the pool of available inodes. */ if (rip == NIL_INODE) return; /* checking here is easier than in caller */ if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */ if ((rip->i_nlinks & BYTE) == 0) { /* i_nlinks == 0 means free the inode. */ truncate(rip); /* return all the disk blocks */ rip->i_mode = I_NOT_ALLOC; /* clear I_TYPE field */ rip->i_pipe = NO_PIPE; free_inode(rip->i_dev, rip->i_num); } if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING); } } /*===========================================================================* * alloc_inode * *===========================================================================*/ PUBLIC struct inode *alloc_inode(dev, bits) dev_nr dev; /* device on which to allocate the inode */ mask_bits bits; /* mode of the inode */ { /* Allocate a free inode on 'dev', and return a pointer to it. */ register struct inode *rip; register struct super_block *sp; int major, minor; inode_nr numb; bit_nr b; extern bit_nr alloc_bit(); extern struct inode *get_inode(); extern struct super_block *get_super(); /* Acquire an inode from the bit map. */ sp = get_super(dev); /* get pointer to super_block */ b=alloc_bit(sp->s_imap, (bit_nr)sp->s_ninodes+1, sp->s_imap_blocks,(bit_nr)0); if (b == NO_BIT) { err_code = ENFILE; major = (int) (sp->s_dev >> MAJOR) & BYTE; minor = (int) (sp->s_dev >> MINOR) & BYTE; if (sp->s_dev == ROOT_DEV) printf("Out of i-nodes on root device (RAM disk)\n"); else printf("Out of i-nodes on device %d/%d\n", major, minor); return(NIL_INODE); } numb = (inode_nr) b; /* Try to acquire a slot in the inode table. */ if ( (rip = get_inode(NO_DEV, numb)) == NIL_INODE) { /* No inode table slots available. Free the inode just allocated. */ free_bit(sp->s_imap, b); } else { /* An inode slot is available. Put the inode just allocated into it. */ rip->i_mode = bits; rip->i_nlinks = (links) 0; rip->i_uid = fp->fp_effuid; rip->i_gid = fp->fp_effgid; rip->i_dev = dev; /* was provisionally set to NO_DEV */ /* The fields not cleared already are cleared in wipe_inode(). They have * been put there because truncate() needs to clear the same fields if * the file happens to be open while being truncated. It saves space * not to repeat the code twice. */ wipe_inode(rip); } return(rip); } /*===========================================================================* * wipe_inode * *===========================================================================*/ PUBLIC wipe_inode(rip) register struct inode *rip; /* The inode to be erased. */ { /* Erase some fields in the inode. This function is called from alloc_inode() * when a new inode is to be allocated, and from truncate(), when an existing * inode is to be truncated. */ register int i; extern real_time clock_time(); rip->i_size = 0; rip->i_modtime = clock_time(); rip->i_dirt = DIRTY; for (i = 0; i < NR_ZONE_NUMS; i++) rip->i_zone[i] = NO_ZONE; } /*===========================================================================* * free_inode * *===========================================================================*/ PUBLIC free_inode(dev, numb) dev_nr dev; /* on which device is the inode */ inode_nr numb; /* number of inode to be freed */ { /* Return an inode to the pool of unallocated inodes. */ register struct super_block *sp; extern struct super_block *get_super(); /* Locate the appropriate super_block. */ sp = get_super(dev); free_bit(sp->s_imap, (bit_nr) numb); } /*===========================================================================* * rw_inode * *===========================================================================*/ PUBLIC rw_inode(rip, rw_flag) register struct inode *rip; /* pointer to inode to be read/written */ int rw_flag; /* READING or WRITING */ { /* An entry in the inode table is to be copied to or from the disk. */ register struct buf *bp; register d_inode *dip; register struct super_block *sp; block_nr b; extern struct buf *get_block(); extern struct super_block *get_super(); /* Get the block where the inode resides. */ sp = get_super(rip->i_dev); b = (block_nr) (rip->i_num - 1)/INODES_PER_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks + 2; bp = get_block(rip->i_dev, b, NORMAL); dip = bp->b_inode + (rip->i_num - 1) % INODES_PER_BLOCK; /* Do the read or write. */ if (rw_flag == READING) { copy((char *)rip, (char *) dip, INODE_SIZE); /* copy from blk to inode */ } else { copy((char *)dip, (char *) rip, INODE_SIZE); /* copy from inode to blk */ bp->b_dirt = DIRTY; } put_block(bp, INODE_BLOCK); rip->i_dirt = CLEAN; } /*===========================================================================* * dup_inode * *===========================================================================*/ PUBLIC dup_inode(ip) struct inode *ip; /* The inode to be duplicated. */ { /* This routine is a simplified form of get_inode() for the case where * the inode pointer is already known. */ ip->i_count++; } S/* Inode table. This table holds inodes that are currently in use. In some * cases they have been opened by an open() or creat() system call, in other * cases the file system itself needs the inode for one reason or another, * such as to search a directory for a path name. * The first part of the struct holds fields that are present on the * disk; the second part holds fields not present on the disk. * The disk inode part is also declared in "type.h" as 'd_inode'. */ EXTERN struct inode { unshort i_mode; /* file type, protection, etc. */ uid i_uid; /* user id of the file's owner */ file_pos i_size; /* current file size in bytes */ real_time i_modtime; /* when was file data last changed */ gid i_gid; /* group number */ links i_nlinks; /* how many links to this file */ zone_nr i_zone[NR_ZONE_NUMS]; /* zone numbers for direct, ind, and dbl ind */ /* The following items are not present on the disk. */ dev_nr i_dev; /* which device is the inode on */ inode_nr i_num; /* inode number on its (minor) device */ short int i_count; /* # times inode used; 0 means slot is free */ char i_dirt; /* CLEAN or DIRTY */ char i_pipe; /* set to I_PIPE if pipe */ char i_mount; /* this bit is set if file mounted on */ char i_seek; /* set on LSEEK, cleared on READ/WRITE */ } inode[NR_INODES]; #define NIL_INODE (struct inode *) 0 /* indicates absence of inode slot */ /* Field values. Note that CLEAN and DIRTY are defined in "const.h" */ #define NO_PIPE 0 /* i_pipe is NO_PIPE if inode is not a pipe */ #define I_PIPE 1 /* i_pipe is I_PIPE if inode is a pipe */ #define NO_MOUNT 0 /* i_mount is NO_MOUNT if file not mounted on */ #define I_MOUNT 1 /* i_mount is I_MOUNT if file mounted on */ #define NO_SEEK 0 /* i_seek = NO_SEEK if last op was not SEEK */ #define ISEEK 1 /* i_seek = ISEEK if last op was SEEK */ _get_inode _get_inode: ,#6 ,#_inode I0015: ,#_inode+1344 jae I0012 36 jle I0017 32, I0013 34, I0013 36 , I0017: ,#42 I0015 I001E _err_code,#-23 I001E: 32, 34, 36,#1 ,#65535 je I00111 _rw_inode I00111: _put_inode _put_inode: I0023 I0023: 36 , I0026 cmpb 13 I0029 _truncate 39 34 32() _free_inode I0029: cmpb 38,#1 I0026 _rw_inode I0026: _alloc_inode _alloc_inode: ,#12 _get_super () 1 4 #18 _alloc_bit ,#8 -12(), -12() I0033 _err_code,#-23 8 38 shr cl , 38 shr cl , 38,#256 I0036 _1 _printk pop I0037 I0036: _2 _printk I0037: I0031 I0033: -12() -10(), -10() 65535 _get_inode I0039 -12() 18 _free_bit I003A I0039: 13 _fp 48 2(), _fp al,51 12(),al 32, _wipe_inode I003A: I0031: _wipe_inode _wipe_inode: 4 6 _clock_time 8, 10, 38,#1 I0045: ,#9 jge I0042 sal 1 14 I0045 I0042: _free_inode _free_inode: _get_super 18 _free_bit _rw_inode _rw_inode: ,#8 32 _get_super , 34 1 32 v 4 6 2 , 32 _get_block 34 1 32 v 5 sal cl , I0063 32 _copy I0064 I0063: 32 _copy 1034,#1 I0064: 64 _put_block 38 _dup_inode _dup_inode: mov 36 , _1: 30031 8308 26223 26912 28205 11 29541 28448 8302 28530 29807 25632 30309 25449 8293 21032 19777 25632 29545 10603 10 _2: 30031 8308 26223 26912 28205 11 29541 28448 8302 25956 26998 25955 9504 12132 25637 10 /* This file handles the LINK and UNLINK system calls. It also deals with * deallocating the storage used by a file when the last UNLINK is done to a * file and the blocks must be returned to the free block pool. * * The entry points into this file are * do_link: perform the LINK system call * do_unlink: perform the UNLINK system call * truncate: release all the blocks associated with an inode */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" /*===========================================================================* * do_link * *===========================================================================*/ PUBLIC int do_link() { /* Perform the link(name, name2) system call. */ register struct inode *ip, *rip; register int r; char string[NAME_SIZE]; struct inode *new_ip; extern struct inode *advance(), *last_dir(), *eat_path(); /* See if 'name' (file to be linked) exists. */ if (fetch_name(name1, name1_length, M1) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); /* Check to see if the file has maximum number of links already. */ r = OK; if ( (rip->i_nlinks & BYTE) == MAX_LINKS) r = EMLINK; /* Only super_user may link to directories. */ if (r == OK) if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM; /* If error with 'name', return the inode. */ if (r != OK) { put_inode(rip); return(r); } /* Does the final directory of 'name2' exist? */ if (fetch_name(name2, name2_length, M1) != OK) { put_inode(rip); return(err_code); } if ( (ip = last_dir(user_path, string)) == NIL_INODE) r = err_code; /* If 'name2' exists in full (even if no space) set 'r' to error. */ if (r == OK) { if ( (new_ip = advance(ip, string)) == NIL_INODE) { r = err_code; if (r == ENOENT) r = OK; } else { put_inode(new_ip); r = EEXIST; } } /* Check for links across devices. */ if (r == OK) if (rip->i_dev != ip->i_dev) r = EXDEV; /* Try to link. */ if (r == OK) r = search_dir(ip, string, &rip->i_num, ENTER); /* If success, register the linking. */ if (r == OK) { rip->i_nlinks++; rip->i_dirt = DIRTY; } /* Done. Release both inodes. */ put_inode(rip); put_inode(ip); return(r); } /*===========================================================================* * do_unlink * *===========================================================================*/ PUBLIC int do_unlink() { /* Perform the unlink(name) system call. */ register struct inode *rip, *rlast_dir_ptr; register int r; inode_nr numb; char string[NAME_SIZE]; extern struct inode *advance(), *last_dir(); /* Get the last directory in the path. */ if (fetch_name(name, name_length, M3) != OK) return(err_code); if ( (rlast_dir_ptr = last_dir(user_path, string)) == NIL_INODE) return(err_code); /* The last directory exists. Does the file also exist? */ r = OK; if ( (rip = advance(rlast_dir_ptr, string)) == NIL_INODE) r = err_code; /* If error, return inode. */ if (r != OK) { put_inode(rlast_dir_ptr); return(r); } /* See if the file is a directory. */ if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM; /* only super_user can unlink directory */ if (r == OK) r = search_dir(rlast_dir_ptr, string, &numb, DELETE); if (r == OK) { rip->i_nlinks--; rip->i_dirt = DIRTY; } /* If unlink was possible, it has been done, otherwise it has not. */ put_inode(rip); put_inode(rlast_dir_ptr); return(r); } /*===========================================================================* * truncate * *===========================================================================*/ PUBLIC truncate(rip) register struct inode *rip; /* pointer to inode to be truncated */ { /* Remove all the zones from the inode 'rip' and mark it dirty. */ register file_pos position; register zone_type zone_size; register block_nr b; register zone_nr z, *iz; register int scale; register struct buf *bp; register dev_nr dev; extern struct buf *get_block(); extern block_nr read_map(); dev = rip->i_dev; /* device on which inode resides */ scale = scale_factor(rip); zone_size = (zone_type) BLOCK_SIZE << scale; if (rip->i_pipe == I_PIPE) rip->i_size = PIPE_SIZE; /* pipes can shrink */ /* Step through the file a zone at a time, finding and freeing the zones. */ for (position = 0; position < rip->i_size; position += zone_size) { if ( (b = read_map(rip, position)) != NO_BLOCK) { z = (zone_nr) b >> scale; free_zone(dev, z); } } /* All the data zones have been freed. Now free the indirect zones. */ free_zone(dev, rip->i_zone[NR_DZONE_NUM]); /* single indirect zone */ if ( (z = rip->i_zone[NR_DZONE_NUM+1]) != NO_ZONE) { b = (block_nr) z << scale; bp = get_block(dev, b, NORMAL); /* get double indirect zone */ for (iz = &bp->b_ind[0]; iz < &bp->b_ind[NR_INDIRECTS]; iz++) { free_zone(dev, *iz); } /* Now free the double indirect zone itself. */ put_block(bp, INDIRECT_BLOCK); free_zone(dev, z); } /* The inode being truncated might currently be open, so certain fields must * be cleared immediately, even though these fields are also cleared by * alloc_inode(). The function wipe_inode() does the dirty work in both cases. */ wipe_inode(rip); } _do_link _do_link: ,#24 _m+4 _m+10 _fetch_name je I0013 _err_code _user_path _eat_path I0016 _err_code cmpb 13,#127 I0019 ,#-31 I0019: I001C 61440 16384 I001C _super_user I001C ,#-1 I001C: je I00113 _put_inode I00113: _m+6 _m+12 _fetch_name je I00116 _put_inode _err_code I00116: -20() _user_path _last_r I00119 _err_code , I00119: I0011C -20() _advance -22(), -22() I0011F _err_code , ,#-2 I0011C C I0011F: -22() _put_inode ,#-17 I0011C: I00125 32() 32, 5 ,#-18 I00125: I0012B 34 -20() _search_r ,#8 , I0012B: I0012E 13 -2, -2 38,#1 I0012E: _put_inode _put_inode _do_unlink _do_unlink: ,#24 3 _m+4 _m+8 _fetch_name je I0023 _err_code I0021 I0023: -22() _user_path _last_r I0026 push _err_code I0021 I0026: -22() _advance I0029 _err_code , I0029: je I002C _put_inode I0021 I002C: 61440 16384 I002F _super_user I002F ,#-1 I002F: I00213 -22() _search_r ,#8 , I00213: I00216 13 -2, -2 38,#1 I00216: _put_inode _put_inode I0021: _truncate _truncate: ,#22 32 -20(), _scale_factor -1, -1 cwd 024 jz 1f 2: sal 1 rcl 1 1: , , cmpb 39,#1 I0033 4,#7168 6 I0033: I0038: 4 sbb 6 1f je 1f 1: or jge I0035 _read_map -10(), -10() je I0036 -1 -10() shr cl -12(), -12() -20() _free_zone I0036: adc , I0038 I0035: 28 -20() _free_zone 30 -12(), -12() je I003D -1 -12() sal cl -10(), -10() -20() _get_block -1, -1 -1, I00312: -1 1024 -1, jae I003F -1 -20() _free_zone -1,#2 I00312 I003F: 66 -1 _put_block -12() -20() _free_zone I003D: _wipe_inode /* This file contains the main program of the File System. It consists of * a loop that gets messages requesting work, carries out the work, and sends * replies. * * The entry points into this file are * main: main program of the File System * reply: send a reply to a process after the requested work is done */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" #include "super.h" #define M64K 0xFFFF0000L /* 16 bit mask for DMA check */ #define INFO 2 /* where in data_org is info from build */ #define MAX_RAM 512 /* maxium RAM disk size in blocks */ /*===========================================================================* * main * *===========================================================================*/ PUBLIC main() { /* This is the main program of the file system. The main loop consists of * three major activities: getting new work, processing the work, and sending * the reply. This loop never terminates as long as the file system runs. */ int error; extern int (*call_vector[NCALLS])(); fs_init(); /* This is the main loop that gets work, processes it, and sends replies. */ while (TRUE) { get_work(); /* sets who and fs_call */ fp = &fproc[who]; /* pointer to proc table struct */ super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ dont_reply = FALSE; /* in other words, do reply is default */ /* Call the internal function that does the work. */ if (fs_call < 0 || fs_call >= NCALLS) error = E_BAD_CALL; else error = (*call_vector[fs_call])(); /* Copy the results back to the user and send reply. */ if (dont_reply) continue; reply(who, error); if (rdahed_inode != NIL_INODE) read_ahead(); /* do block read ahead */ } } /*===========================================================================* * get_work * *===========================================================================*/ PRIVATE get_work() { /* Normally wait for new input. However, if 'reviving' is * nonzero, a suspended process must be awakened. */ register struct fproc *rp; if (reviving != 0) { /* Revive a suspended process. */ for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) if (rp->fp_revived == REVIVING) { who = rp - fproc; fs_call = rp->fp_fd & BYTE; fd = (rp->fp_fd >>8) & BYTE; buffer = rp->fp_buffer; nbytes = rp->fp_nbytes; rp->fp_suspended = NOT_SUSPENDED; /* no longer hanging*/ rp->fp_revived = NOT_REVIVING; reviving--; return; } panic("get_work couldn't revive anyone", NO_NUM); } /* Normal case. No one to revive. */ if (receive(ANY, &m) != OK) panic("fs receive error", NO_NUM); who = m.m_source; fs_call = m.m_type; } /*===========================================================================* * reply * *===========================================================================*/ PUBLIC reply(whom, result) int whom; /* process to reply to */ int result; /* result of the call (usually OK or error #) */ { /* Send a reply to a user process. It may fail (if the process has just * been killed by a signal, so don't check the return code. If the send * fails, just ignore it. */ reply_type = result; send(whom, &m1); } /*===========================================================================* * fs_init * *===========================================================================*/ PRIVATE fs_init() { /* Initialize global variables, tables, etc. */ register struct inode *rip; int i; extern struct inode *get_inode(); buf_pool(); /* initialize buffer pool */ load_ram(); /* Load RAM disk from root diskette. */ load_super(); /* Load super block for root device */ /* Initialize the 'fproc' fields for process 0 and process 2. */ for (i = 0; i < 3; i+= 2) { fp = &fproc[i]; rip = get_inode(ROOT_DEV, ROOT_INODE); fp->fp_rootdir = rip; dup_inode(rip); fp->fp_workdir = rip; fp->fp_realuid = (uid) SYS_UID; fp->fp_effuid = (uid) SYS_UID; fp->fp_realgid = (gid) SYS_GID; fp->fp_effgid = (gid) SYS_GID; fp->fp_umask = ~0; } /* Certain relations must hold for the file system to work at all. */ if (ZONE_NUM_SIZE != 2) panic("ZONE_NUM_SIZE != 2", NO_NUM); if (SUPER_SIZE > BLOCK_SIZE) panic("SUPER_SIZE > BLOCK_SIZE", NO_NUM); if(BLOCK_SIZE % INODE_SIZE != 0)panic("BLOCK_SIZE % INODE_SIZE != 0", NO_NUM); if (NR_FDS > 127) panic("NR_FDS > 127", NO_NUM); if (NR_BUFS < 6) panic("NR_BUFS < 6", NO_NUM); if (sizeof(d_inode) != 32) panic("inode size != 32", NO_NUM); } /*===========================================================================* * buf_pool * *===========================================================================*/ PRIVATE buf_pool() { /* Initialize the buffer pool. On the IBM PC, the hardware DMA chip is * not able to cross 64K boundaries, so any buffer that happens to lie * across such a boundary is not used. This is not very elegant, but all * the alternative solutions are as bad, if not worse. The fault lies with * the PC hardware. */ register struct buf *bp; vir_bytes low_off, high_off; phys_bytes org; extern phys_clicks get_base(); bufs_in_use = 0; front = &buf[0]; rear = &buf[NR_BUFS - 1]; for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) { bp->b_blocknr = NO_BLOCK; bp->b_dev = NO_DEV; bp->b_next = bp + 1; bp->b_prev = bp - 1; } buf[0].b_prev = NIL_BUF; buf[NR_BUFS - 1].b_next = NIL_BUF; /* Delete any buffers that span a 64K boundary. */ #ifdef i8088 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) { org = get_base() << CLICK_SHIFT; /* phys addr where FS is */ low_off = (vir_bytes) bp->b_data; high_off = low_off + BLOCK_SIZE - 1; if (((org + low_off) & M64K) != ((org + high_off) & M64K)) { if (bp == &buf[0]) { front = &buf[1]; buf[1].b_prev = NIL_BUF; } else if (bp == &buf[NR_BUFS - 1]) { rear = &buf[NR_BUFS - 2]; buf[NR_BUFS - 2].b_next = NIL_BUF; } else { /* Delete a buffer in the middle. */ bp->b_prev->b_next = bp + 1; bp->b_next->b_prev = bp - 1; } } } #endif for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next; buf_hash[NO_BLOCK & (NR_BUF_HASH - 1)] = front; } /*===========================================================================* * load_ram * *===========================================================================*/ PRIVATE load_ram() { /* The root diskette contains a block-by-block image of the root file system * starting at 0. Go get it and copy it to the RAM disk. */ register struct buf *bp, *bp1; int count; long k_loaded; struct super_block *sp; block_nr i; phys_clicks ram_clicks, init_org, init_text_clicks, init_data_clicks; extern phys_clicks data_org[INFO + 2]; extern struct buf *get_block(); /* Get size of INIT by reading block on diskette where 'build' put it. */ init_org = data_org[INFO]; init_text_clicks = data_org[INFO + 1]; init_data_clicks = data_org[INFO + 2]; /* Get size of RAM disk by reading root file system's super block */ bp = get_block(BOOT_DEV, SUPER_BLOCK, NORMAL); /* get RAM super block */ copy(super_block, bp->b_data, sizeof(struct super_block)); sp = &super_block[0]; if (sp->s_magic != SUPER_MAGIC) panic("Diskette in drive 0 is not root file system", NO_NUM); count = sp->s_nzones << sp->s_log_zone_size; /* # blocks on root dev */ if (count > MAX_RAM) panic("RAM disk is too big. # blocks = ", count); ram_clicks = count * (BLOCK_SIZE/CLICK_SIZE); put_block(bp, FULL_DATA_BLOCK); /* Tell MM the origin and size of INIT, and the amount of memory used for the * system plus RAM disk combined, so it can remove all of it from the map. */ m1.m_type = BRK2; m1.m1_i1 = init_text_clicks; m1.m1_i2 = init_data_clicks; m1.m1_i3 = init_org + init_text_clicks + init_data_clicks + ram_clicks; m1.m1_p1 = (char *) init_org; if (sendrec(MM_PROC_NR, &m1) != OK) panicikl("FS Can't report to MM", NO_NUM); /* Tell RAM driver where RAM disk is and how big it is. */ m1.m_type = DISK_IOCTL; m1.DEVICE = RAM_DEV; m1.POSITION = (long) init_org + (long) init_text_clicks + init_data_clicks; m1.POSITION = m1.POSITION << CLICK_SHIFT; m1.COUNT = count; if (sendrec(MEM, &m1) != OK) panic("Can't report size to MEM", NO_NUM); /* Copy the blocks one at a time from the root diskette to the RAM */ printf("Loading RAM disk from root diskette. Loaded: 0K "); for (i = 0; i < count; i++) { bp = get_block(BOOT_DEV, (block_nr) i, NORMAL); bp1 = get_block(ROOT_DEV, i, NO_READ); copy(bp1->b_data, bp->b_data, BLOCK_SIZE); bp1->b_dirt = DIRTY; put_block(bp, I_MAP_BLOCK); put_block(bp1, I_MAP_BLOCK); k_loaded = ( (long) i * BLOCK_SIZE)/1024L; /* K loaded so far */ if (k_loaded % 5 == 0) printf("\b\b\b\b\b%3DK %c", k_loaded, 0); } printf("\rRAM disk loaded. Please remove root diskette. \n\n"); } /*===========================================================================* * load_super * *===========================================================================*/ PRIVATE load_super() { register struct super_block *sp; register struct inode *rip; extern struct inode *get_inode(); /* Initialize the super_block table. */ for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) sp->s_dev = NO_DEV; /* Read in super_block for the root file system. */ sp = &super_block[0]; sp->s_dev = ROOT_DEV; rw_super(sp,READING); rip = get_inode(ROOT_DEV, ROOT_INODE); /* inode for root dir */ /* Check super_block for consistency (is it the right diskette?). */ if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3 || sp->s_magic != SUPER_MAGIC) panic("Root file system corrupted. Possibly wrong diskette.", NO_NUM); sp->s_imount = rip; dup_inode(rip); sp->s_isup = rip; sp->s_rd_only = 0; if (load_bit_maps(ROOT_DEV) != OK) panic("init: can't load root bit maps", NO_NUM); } _main _main: _fs_init _get_work 6 _who sal cl _fproc _fp, 48 I0016 I0017 I0017: _super_user _dont_reply _fs_call jl I0018 _fs_call,#69 jl I0019 I0018: ,#-102 I001A I0019: _fs_call sal 1 _call_vector () I001A: _dont_reply je I001D I001D: _who _reply _rdahed_inode je I0013 _read_ahead _get_work: _reviving je I0023 ,#_fproc I0028: ,#_fproc+1024 jae I0025 cmpb 61,#1 I0026 _fproc 64 cwd iv _who, 54 _fs_call, 8 54 sar cl ax, _m+4, 56 _m+10, 58 _m+6, 60 61 _reviving I0026: ,#64 I0028 I0025: 32768 _1 _panic I0023: _m 16 _receive je I002D 32768 _2 _panic I002D: _m _who, _m+2 _fs_call, _reply _reply: _m1+2, _m1 _send _fs_init: ,#6 _buf_pool _load_ram _load_super I0045: ,#3 jge I00416 6 sal cl _fproc _fp, 56 _get_inode _fp mov 4, _dup_inode _fp 2, _fp 46 _fp 48 _fp 50 _fp 51 _fp ,#65535 ,#2 I0045 I00416: _buf_pool: ,#10 _bufs_in_use _front,#_buf _rear,#_buf+19684 ,#_buf I0055: ,#_buf+20720 jae I0052 1030 1032,#65535 1036 1024(), -1036 1026(), ,#1036 I0055 I0052: _buf+1026 _buf+20708 ,#_buf I0059: ,#_buf+20720 jae I0056 _get_base 4 sal cl -10(), , 1024 1 , 4 -10() adc 0 #-1 xor 4 4 -10() adc 0 #-1 .cmu4 je I0057 ,#_buf I005E _front,#_buf+1036 _buf+2062 I0057 I005E: ,#_buf+19684 I00511 _rear,#_buf+18648 _buf+19672 I0057 I00511: 1036 1026() 1024(), -1036 1024() 1026(), I0057: ,#1036 I0059 I0056: ,#_buf I00516: ,#_buf+20720 jae I00513 1024 1028(), ,#1036 I00516 I00513: _front _buf_hash, _load_ram: ,#22 _data_org+4 -1, _data_org+6 -20(), _data_org+8 -22(), 512 _get_block ax,#50 _super_block _copy -12(),#_super_block -12() 16 4991 je I0063 32768 _9 _panic I0063: -12() -12() 2 10() sal cl , ,#512 jle I0066 _10 _panic I0066: 6 sal cl -1, 6 _put_block _m1+2,#66 -20() _m1+4, -22() _m1+6, -20() -1 -22() -1 _m1+8, -1 _m1+10, _m1 _sendrec je I0069 32768 _11 _panic I0069: _m1+2,#5 _m1+4 -20() -1 adc 4 4 -22() adc 4 4 _m1+10, _m1+10+2 4 _m1+10+2 2: sal 1 rcl 1 1: _m1+10, _m1+10+2, _m1+8, _m1 -4 _sendrec je I006C 32768 _12 _panic I006C: _13 _printk -1 I00611: -1 jae I006E -1 512 _get_block -1 56 _get_block 024 _copy 1034,#1 95 _put_block 95 _put_block #1024 -1 .mli4 024 .dvi4 -10(), , -10() 5 .rmi4 #0 sbb 0 1f or 1: or I006F -10() _14 _printk ,#8 I006F: -1 1 -1, I00611 I006E: _15 _printk _load_super: ,#_super_block I0075: ,#_super_block+250 jae I0072 38,#65535 ,#50 I0075 I0072: ,#_super_block 38,#256 _rw_super 56 _get_inode 61440 16384 I0076 al,13 3 jl I0076 16 4991 je I0077 I0076: 32768 _16 _panic I0077: 42, _dup_inode 40, 48 56 _load_bit_maps je I007C 32768 _17 _panic I007C: _1: 25959 24436 28535 27506 25376 30063 08 10094 8308 25970 26998 25974 24864 31086 28271 101 _2: 29542 29216 25445 26981 25974 25888 29298 29295 _3: 20314 17742 20063 19797 21343 23113 8261 15649 12832 _4: .word 21843 17744 24402 18771 17754 15904 16928 20300 19267 21343 23113 69 _5: 19522 17231 24395 18771 17754 9504 18720 20302 17732 21343 23113 8261 15649 12320 _6: 21070 18015 21316 15904 12576 14130 _7: 21070 16991 18005 8275 8252 54 _8: 28265 11 8293 26995 25978 8480 8253 12851 _9: 26948 27507 29797 25972 26912 8302 29284 30313 8293 8240 29545 28192 29807 29216 28527 8308 26982 25964 29472 29561 25972 109 _10: 16722 8269 26980 27507 26912 8307 28532 8303 26978 11879 8992 25120 28524 27491 8307 8253 _11: 21318 17184 28257 29735 29216 28773 29295 8308 28532 19744 77 _12: 24899 10094 8308 25970 28528 29810 29472 31337 8293 28532 19744 19781 _13: 28492 25697 28265 8295 16722 8269 26980 27507 26144 28530 8301 28530 29807 25632 29545 25963 29812 11877 28492 25697 01 8250 19248 32 _14: 2056 2056 9480 17459 8267 25381 _15: 21005 19777 25632 29545 8299 28524 25697 01 8238 20512 25964 29537 8293 25970 28525 25974 29216 28527 8308 26980 27507 29797 25972 8238 .word 8224 0 _16: 28498 29807 26144 27753 8293 31091 29811 28005 25376 29295 30066 29808 01 8238 20512 29551 26995 27746 8313 29303 28271 8295 26980 27507 29797 25972 46 _17: 28265 29801 8250 24931 10094 8308 28524 25697 29216 28527 8308 26978 8308 24941 29552 CFLAGS= -Di8088 -w -F -T. h=/usr/include l=/usr/lib obj = main.s open.s read.s write.s pipe.s device.s \ path.s mount.s link.s super.s inode.s cache.s filedes.s \ stadir.s protect.s time.s misc.s utility.s table.s putc.s fs: makefile $l/head.s $(obj) $l/libc.a $l/end.s @echo "Start linking FS. /lib/cem will be removed to make space on RAM disk" @rm -f /lib/cem /tmp/* asld -o fs $l/head.s $(obj) $l/libc.a $l/end.s @echo "FS done. Please restore /lib/cem manually" cache.s: const.h type.h $h/const.h $h/type.h cache.s: $h/error.h cache.s: buf.h cache.s: file.h cache.s: fproc.h cache.s: glo.h cache.s: inode.h cache.s: super.h device.s: const.h type.h $h/const.h $h/type.h device.s: $h/com.h device.s: $h/error.h device.s: dev.h device.s: file.h device.s: fproc.h device.s: glo.h device.s: inode.h device.s: param.h filedes.s: const.h type.h $h/const.h $h/type.h filedes.s: $h/error.h filedes.s: file.h filedes.s: fproc.h filedes.s: glo.h filedes.s: inode.h inode.s: const.h type.h $h/const.h $h/type.h inode.s: $h/error.h inode.s: buf.h inode.s: file.h inode.s: fproc.h inode.s: glo.h inode.s: inode.h inode.s: super.h link.s: const.h type.h $h/const.h $h/type.h link.s: $h/error.h link.s: buf.h link.s: file.h link.s: fproc.h link.s: glo.h link.s: inode.h link.s: param.h main.s: const.h type.h $h/const.h $h/type.h main.s: $h/callnr.h main.s: $h/com.h main.s: $h/error.h main.s: buf.h main.s: file.h main.s: fproc.h main.s: glo.h main.s: inode.h main.s: param.h main.s: super.h misc.s: const.h type.h $h/const.h $h/type.h misc.s: $h/callnr.h misc.s: $h/com.h misc.s: $h/error.h misc.s: buf.h misc.s: file.h misc.s: fproc.h misc.s: glo.h misc.s: inode.h misc.s: param.h misc.s: super.h mount.s: const.h type.h $h/const.h $h/type.h mount.s: $h/error.h mount.s: buf.h mount.s: file.h mount.s: fproc.h mount.s: glo.h mount.s: inode.h mount.s: param.h mount.s: super.h open.s: const.h type.h $h/const.h $h/type.h open.s: $h/callnr.h open.s: $h/error.h open.s: buf.h open.s: file.h open.s: fproc.h open.s: glo.h open.s: inode.h open.s: param.h path.s: const.h type.h $h/const.h $h/type.h path.s: $h/error.h path.s: buf.h path.s: file.h path.s: fproc.h path.s: glo.h path.s: inode.h path.s: super.h pipe.s: const.h type.h $h/const.h $h/type.h pipe.s: $h/callnr.h pipe.s: $h/com.h pipe.s: $h/error.h pipe.s: $h/signal.h pipe.s: file.h pipe.s: fproc.h pipe.s: glo.h pipe.s: inode.h pipe.s: param.h protect.s: const.h type.h $h/const.h $h/type.h protect.s: $h/error.h protect.s: buf.h protect.s: file.h protect.s: fproc.h protect.s: glo.h protect.s: inode.h protect.s: param.h protect.s: super.h putc.s: const.h type.h $h/const.h $h/type.h putc.s: $h/com.h read.s: const.h type.h $h/const.h $h/type.h read.s: $h/com.h read.s: $h/error.h read.s: buf.h read.s: file.h read.s: fproc.h read.s: glo.h read.s: inode.h read.s: param.h read.s: super.h stadir.s: const.h type.h $h/const.h $h/type.h stadir.s: $h/error.h stadir.s: $h/stat.h stadir.s: file.h stadir.s: fproc.h stadir.s: glo.h stadir.s: inode.h stadir.s: param.h super.s: const.h type.h $h/const.h $h/type.h super.s: $h/error.h super.s: buf.h super.s: inode.h super.s: super.h table.s: const.h type.h $h/const.h $h/type.h table.s: $h/com.h table.s: $h/callnr.h table.s: $h/error.h table.s: $h/stat.h table.s: buf.h table.s: dev.h table.s: file.h table.s: fproc.h table.s: glo.h table.s: inode.h table.s: super.h time.s: const.h type.h $h/const.h $h/type.h time.s: $h/callnr.h time.s: $h/com.h time.s: $h/error.h time.s: file.h time.s: fproc.h time.s: glo.h time.s: inode.h time.s: param.h utility.s: const.h type.h $h/const.h $h/type.h utility.s: $h/com.h utility.s: $h/error.h utility.s: buf.h utility.s: file.h utility.s: fproc.h utility.s: glo.h utility.s: inode.h utility.s: param.h utility.s: super.h write.s: const.h type.h $h/const.h $h/type.h write.s: $h/error.h write.s: buf.h write.s: file.h write.s: fproc.h write.s: glo.h write.s: inode.h write.s: super.h /* This file contains a collection of miscellaneous procedures. Some of them * perform simple system calls. Some others do a little part of system calls * that are mostly performed by the Memory Manager. * * The entry points into this file are * do_dup: perform the DUP system call * do_sync: perform the SYNC system call * do_fork: adjust the tables after MM has performed a FORK system call * do_exit: a process has exited; note that in the tables * do_set: set uid or gid for some process * do_revive: revive a process that was waiting for something (e.g. TTY) */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "dev.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" #include "super.h" /*===========================================================================* * do_dup * *===========================================================================*/ PUBLIC int do_dup() { /* Perform the dup(fd) or dup(fd,fd2) system call. */ register int rfd; register struct fproc *rfp; struct filp *dummy; int r; extern struct filp *get_filp(); /* Is the file descriptor valid? */ rfd = fd & ~DUP_MASK; /* kill off dup2 bit, if on */ rfp = fp; if (get_filp(rfd) == NIL_FILP) return(err_code); /* Distinguish between dup and dup2. */ if (fd == rfd) { /* bit not on */ /* dup(fd) */ if ( (r = get_fd(0, &fd2, &dummy)) != OK) return(r); } else { /* dup2(fd, fd2) */ if (fd2 < 0 || fd2 >= NR_FDS) return(EBADF); if (rfd == fd2) return(fd2); /* ignore the call: dup2(x, x) */ fd = fd2; /* prepare to close fd2 */ do_close(); /* cannot fail */ } /* Success. Set up new file descriptors. */ rfp->fp_filp[fd2] = rfp->fp_filp[rfd]; rfp->fp_filp[fd2]->filp_count++; return(fd2); } /*===========================================================================* * do_sync * *===========================================================================*/ PUBLIC int do_sync() { /* Perform the sync() system call. Flush all the tables. */ register struct inode *rip; register struct buf *bp; register struct super_block *sp; dev_nr d; extern real_time clock_time(); extern struct super_block *get_super(); /* The order in which the various tables are flushed is critical. The * blocks must be flushed last, since rw_inode() and rw_super() leave their * results in the block cache. */ /* Update the time in the root super_block. */ sp = get_super(ROOT_DEV); sp->s_time = clock_time(); if (sp->s_rd_only == FALSE) sp->s_dirt = DIRTY; /* Write all the dirty inodes to the disk. */ for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING); /* Write all the dirty super_blocks to the disk. */ for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) if (sp->s_dev != NO_DEV && sp->s_dirt == DIRTY) rw_super(sp, WRITING); /* Write all the dirty blocks to the disk. First do drive 0, then the rest. * This avoids starting drive 0, then starting drive 1, etc. */ for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) { d = bp->b_dev; if (d != NO_DEV && bp->b_dirt == DIRTY && ((d>>MINOR) & BYTE) == 0) rw_block(bp, WRITING); } for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) { d = bp->b_dev; if (d != NO_DEV && bp->b_dirt == DIRTY && ((d>>MINOR) & BYTE) != 0) rw_block(bp, WRITING); } return(OK); /* sync() can't fail */ } /*===========================================================================* * do_fork * *===========================================================================*/ PUBLIC int do_fork() { /* Perform those aspects of the fork() system call that relate to files. * In particular, let the child inherit its parents file descriptors. * The parent and child parameters tell who forked off whom. The file * system uses the same slot numbers as the kernel. Only MM makes this call. */ register struct fproc *cp; register char *sptr, *dptr; int i; /* Only MM may make this call directly. */ if (who != MM_PROC_NR) return(ERROR); /* Copy the parent's fproc struct to the child. */ sptr = (char *) &fproc[parent]; /* pointer to parent's 'fproc' struct */ dptr = (char *) &fproc[child]; /* pointer to child's 'fproc' struct */ i = sizeof(struct fproc); /* how many bytes to copy */ while (i--) *dptr++ = *sptr++; /* fproc[child] = fproc[parent] */ /* Increase the counters in the 'filp' table. */ cp = &fproc[child]; for (i = 0; i < NR_FDS; i++) if (cp->fp_filp[i] != NIL_FILP) cp->fp_filp[i]->filp_count++; /* Record the fact that both root and working dir have another user. */ dup_inode(cp->fp_rootdir); dup_inode(cp->fp_workdir); return(OK); } /*===========================================================================* * do_exit * *===========================================================================*/ PUBLIC int do_exit() { /* Perform the file system portion of the exit(status) system call. */ register int i, exitee; /* Only MM may do the EXIT call directly. */ if (who != MM_PROC_NR) return(ERROR); /* Nevertheless, pretend that the call came from the user. */ fp = &fproc[slot1]; /* get_filp() needs 'fp' */ exitee = slot1; if (fp->fp_suspended == SUSPENDED) { if (fp->fp_task == XPIPE) susp_count--; pro = exitee; do_unpause(); fp->fp_suspended = NOT_SUSPENDED; } /* Loop on file descriptors, closing any that are open. */ for (i=0; i < NR_FDS; i++) { fd = i; do_close(); } /* Release root and working directories. */ put_inode(fp->fp_rootdir); put_inode(fp->fp_workdir); return(OK); } /*===========================================================================* * do_set * *===========================================================================*/ PUBLIC int do_set() { /* Set uid or gid field. */ register struct fproc *tfp; /* Only MM may make this call directly. */ if (who != MM_PROC_NR) return(ERROR); tfp = &fproc[slot1]; if (fs_call == SETUID) { tfp->fp_realuid = (uid) real_user_id; tfp->fp_effuid = (uid) eff_user_id; } if (fs_call == SETGID) { tfp->fp_effgid = (gid) eff_grp_id; tfp->fp_realgid = (gid) real_grp_id; } return(OK); } /*===========================================================================* * do_revive * *===========================================================================*/ PUBLIC int do_revive() { /* A task, typically TTY, has now gotten the characters that were needed for a * previous read. The process did not get a reply when it made the call. * Instead it was suspended. Now we can send the reply to wake it up. This * business has to be done carefully, since the incoming message is from * a task (to which no reply can be sent), and the reply must go to a process * that blocked earlier. The reply to the caller is inhibited by setting the * 'dont_reply' flag, and the reply to the blocked process is done explicitly * in revive(). */ if (who > 0) return(EPERM); revive(m.REP_PROC_NR, m.REP_STATUS); dont_reply = TRUE; /* don't reply to the TTY task */ return(OK); } ~_do_dup _do_dup: ,#10 _m+4 65471 _fp , _get_filp 0 I0013 _err_code _m+4, I0016 _m+6 _get_fd , je I0017 _m+6 jl I001B _m+6,#20 jl I001C I001B: -9 I001C: _m+6 , I00110 _m+6 I00110: _m+6 _m+4, _do_close I0017: sal 1 _m+6 sal 1 6 6(), _m+6 sal 1 6 2 -10(), _m+6 _do_sync _do_sync: ,#8 56 _get_super , _clock_time 44, 46, cmpb 48 I0023 49,#1 I0023: ,#_inode I0028: ,#_inode+1344 jae I0025 36 jle I0026 cmpb 38,#1 I0026 _rw_inode I0026: ,#42 I0028 I0025: ,#_super_block I00210: ,#_super_block+250 jae I002D 38,#65535 je I002E cmpb 49,#1 I002E _rw_super I002E: ,#50 I00210 I002D: ,#_buf I00218: ,#_buf+20720 jae I00215 1032 , ,#65535 je I00216 cmpb 1034,#1 I00216 shr cl testb al, I00216 _rw_block I00216: ,#1036 I00218 I00215: ,#_buf I00221: ,#_buf+20720 jae I0021E 1032 , ,#65535 je I0021F cmpb 1034,#1 I0021F shr cl testb al, je I0021F _rw_block I0021F: ,#1036 I00221 I0021E: _do_fork _do_fork: ,#10 _who je I0033 -1 I0031 I0033: 6 _m+4 sal cl _fproc , _m+6 sal cl _fproc , ,#64 I0036: je I0035 ,#1 (),al ,#1 I0036 I0035: 6 _m+6 sal cl _fproc , I003B: ,#20 jge I0038 sal 1 6 je I0039 sal 1 6 2 -10(), I0039: I003B I0038: 4 _dup_inode 2 _dup_inode I0031: _do_exit _do_exit: _who je I0043 -1 I0041 I0043: 6 _m+4 sal cl _fproc _fp, _m+4 , _fp cmpb 60,#1 I0046 _fp cmpb 62 I0049 _su_count I0049: _m+4, _do_unpause _fp 60 I0046: I004E: ,#20 jge I004B _m+4, _do_close I004E I004B: _fp 4 _put_inode _fp 2 _put_inode I0041: _do_set _do_set: _who je I0053 -1 I0051 I0053: 6 _m+4 sal cl _fproc , _fs_call,#23 I0056 mov _m+6 46, _m+8 48, I0056: _fs_call,#46 I0059 _m+8 51,cl _m+6 50,cl I0059: I0051: _do_revive _do_revive: _who jle I0063 -1 I0061 I0063: _m+6 _m+4 _revive _dont_reply,#1 I0061: /* This file performs the MOUNT and UMOUNT system calls. * * The entry points into this file are * do_mount: perform the MOUNT system call * do_umount: perform the UMOUNT system call */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" #include "super.h" /*===========================================================================* * do_mount * *===========================================================================*/ PUBLIC int do_mount() { /* Perform the mount(name, mfile, rd_only) system call. */ register struct inode *rip, *root_ip; struct super_block *xp, *sp; dev_nr dev; mask_bits bits; int r, found, loaded; extern struct inode *get_inode(), *eat_path(); extern dev_nr name_to_dev(); /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file, return error. */ if (fetch_name(name1, name1_length, M1) != OK) return(err_code); if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code); /* Scan super block table to see if dev already mounted & find a free slot.*/ sp = NIL_SUPER; found = FALSE; for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) { if (xp->s_dev == dev) found = TRUE; /* is it mounted already? */ if (xp->s_dev == NO_DEV) sp = xp; /* record free slot */ } if (found) return(EBUSY); /* already mounted */ if (sp == NIL_SUPER) return(ENFILE); /* no super block available */ /* Fill in the super block. */ sp->s_dev = dev; /* rw_super() needs to know which dev */ rw_super(sp, READING); sp->s_dev = dev; /* however, rw_super() overwrites s_dev */ /* Make a few basic checks to see if super block looks reasonable. */ if (sp->s_magic != SUPER_MAGIC || sp->s_ninodes < 1 || sp->s_nzones < 1 || sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1) { sp->s_dev = NO_DEV; return(EINVAL); } /* Now get the inode of the file to be mounted on. */ if (fetch_name(name2, name2_length, M1) != OK) { sp->s_dev = NO_DEV; return(err_code); } if ( (rip = eat_path(user_path)) == NIL_INODE) { sp->s_dev = NO_DEV; return(err_code); } /* It may not be busy. */ r = OK; if (rip->i_count > 1) r = EBUSY; /* It may not be special. */ bits = rip->i_mode & I_TYPE; if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; /* Get the root inode of the mounted file system. */ root_ip = NIL_INODE; /* if 'r' not OK, make sure this is defined */ if (r == OK) { if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code; } if (root_ip != NIL_INODE && root_ip->i_mode == 0) r = EINVAL; /* Load the i-node and zone bit maps from the new device. */ loaded = FALSE; if (r == OK) { if (load_bit_maps(dev) != OK) r = ENFILE; /* load bit maps */ loaded = TRUE; } /* File types of 'rip' and 'root_ip' may not conflict. */ if ( (r == OK) && ((rip->i_mode & I_TYPE) == I_DIRECTORY) && ((root_ip->i_mode & I_TYPE) != I_DIRECTORY)) r = ENOTDIR; /* If error, return the super block and both inodes; release the maps. */ if (r != OK) { put_inode(rip); put_inode(root_ip); if (loaded) unload_bit_maps(dev); do_sync(); invalidate(dev); sp->s_dev = NO_DEV; return(r); } /* Nothing else can go wrong. Perform the mount. */ rip->i_mount = I_MOUNT; /* this bit says the inode is mounted on */ sp->s_imount = rip; sp->s_isup = root_ip; sp->s_rd_only = rd_only; return(OK); } /*===========================================================================* * do_umount * *===========================================================================*/ PUBLIC int do_umount() { /* Perform the umount(name) system call. */ register struct inode *rip; struct super_block *sp, *sp1; dev_nr dev; int count; extern dev_nr name_to_dev(); /* Only the super-user may do UMOUNT. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file, return error. */ if (fetch_name(name, name_length, M3) != OK) return(err_code); if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code); /* See if the mounted device is busy. Only 1 inode using it should be * open -- the root inode -- and that inode only 1 time. */ count = 0; for (rip = &inode[0]; rip< &inode[NR_INODES]; rip++) if (rip->i_count > 0 && rip->i_dev == dev) count += rip->i_count; if (count > 1) return(EBUSY); /* can't umount a busy file system */ /* Find the super block. */ sp = NIL_SUPER; for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) { if (sp1->s_dev == dev) { sp = sp1; break; } } /* Release the bit maps, sync the disk, and invalidate cache. */ if (sp != NIL_SUPER) if (unload_bit_maps(dev) != OK) panic("do_umount", NO_NUM); do_sync(); /* force any cached blocks out of memory */ invalidate(dev); /* invalidate cache entries for this dev */ if (sp == NIL_SUPER) return(EINVAL); /* Finish off the unmount. */ sp->s_imount->i_mount = NO_MOUNT; /* inode returns to normal */ put_inode(sp->s_imount); /* release the inode mounted on */ put_inode(sp->s_isup); /* release the root inode of the mounted fs */ sp->s_imount = NIL_INODE; sp->s_dev = NO_DEV; return(OK); } /*===========================================================================* * name_to_dev * *===========================================================================*/ PRIVATE dev_nr name_to_dev(path) char *path; /* pointer to path name */ { /* Convert the block special file 'path' to a device number. If 'path' * is not a block special file, return error code in 'err_code'. */ register struct inode *rip; register dev_nr dev; extern struct inode *eat_path(); /* If 'path' can't be opened, give up immediately. */ if ( (rip = eat_path(path)) == NIL_INODE) return(NO_DEV); /* If 'path' is not a block special file, return error. */ if ( (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) { err_code = ENOTBLK; put_inode(rip); return(NO_DEV); } /* Extract the device number. */ dev = (dev_nr) rip->i_zone[0]; put_inode(rip); return(dev); } _do_mount _do_mount: ,#18 _super_user I0013 -1 _m+4 _m+10 _fetch_name je I0016 _err_code _user_path _name_to_dev -10(), -10(),#65535 I0019 _err_code I0019: -1 ,#_super_block I001E: ,#_super_block+250 jae I001B -10() 38, I00110 -1,#1 I00110: 38,#65535 I001C , I001C: ,#50 I001E I001B: -1 je I00116 -16 I00116: I00119 -23 I00119: -10() 38, _rw_super -10() 38, 16 4991 I0011B bx, ,#1 jb I0011B 2,#1 jb I0011B 4,#1 jb I0011B 6,#1 jae I0011C I0011B: 38,#65535 -22 I0011C: _m+6 _m+12 _fetch_name 3 38,#65535 _err_code I00123: _user_path _eat_path I00126 38,#65535 _err_code I00126: -1 36,#1 jle I00129 -1,#-16 I00129: 61440 -12(), -12(),#24576 B -12(),#8192 I0012C I0012B: -1,#-20 I0012C: -1 I00130 -10() _get_inode I00130 _err_code -1, I00130: je I00136 I00136 -1,#-22 I00136: -18(bp) -1 I0013A -10() _load_bit_maps je I0013D -1,#-23 I0013D: -1,#1 I0013A: -1 I00140 61440 16384 I00140 61440 16384 je I00140 -1,#-20 I00140: -1 je I00145 _put_inode _put_inode -1 je I00148 -10() _unload_bit_maps I00148: _do_sync -10() _invalidate 38,#65535 -1 I00145: 40,#1 42, 40, _m+8 48,cl _do_umount _do_umount: ,#12 _super_user I0023 -1 I0021 I0023: 3 _m+4 _m+8 _fetch_name je I0026 push _err_code I0021 I0026: _user_path _name_to_dev , ,#65535 I0029 _err_code I0021 I0029: -10() ,#_inode I002E: ,#_inode+1344 jae I002B 36 jle I002C 32, I002C -10() 36 -10(), I002C: ,#42 I002E I002B: -10(),#1 jle I00214 -16 I0021 I00214: ,#_super_block I00219: ,#_super_block+250 jae I00216 38, I00217 I00216 I00217: ,#50 I00219 I00216: je I0021E _unload_bit_maps je I0021E 32768 _1 _panic I0021E: _do_sync _invalidate I00224 -22 I0021 I00224: 42 40 - 42 _put_inode 40 _put_inode 42 38,#65535 I0021: _name_to_dev: _eat_path I0033 65535 I0031 I0033: 61440 24576 je I0036 _err_code,#-15 _put_inode 65535 I0031 I0036: 14 _put_inode I0031: _1: 28516 30047 28525 28277 116 /* This file contains the procedures for creating, opening, closing, and * seeking on files. * * The entry points into this file are * do_creat: perform the CREAT system call * do_mknod: perform the MKNOD system call * do_open: perform the OPEN system call * do_close: perform the CLOSE system call * do_lseek: perform the LSEEK system call */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; /*===========================================================================* * do_creat * *===========================================================================*/ PUBLIC int do_creat() { /* Perform the creat(name, mode) system call. */ register struct inode *rip; register int r; register mask_bits bits; struct filp *fil_ptr; int file_d; extern struct inode *new_node(); /* See if name ok and file descriptor and filp slots are available. */ if (fetch_name(name, name_length, M3) != OK) return(err_code); if ( (r = get_fd(W_BIT, &file_d, &fil_ptr)) != OK) return(r); /* Create a new inode by calling new_node(). */ bits = I_REGULAR | (mode & ALL_MODES & fp->fp_umask); rip = new_node(user_path, bits, NO_ZONE); r = err_code; if (r != OK && r != EEXIST) return(r); /* At this point two possibilities exist: the given path did not exist * and has been created, or it pre-existed. In the later case, truncate * if possible, otherwise return an error. */ if (r == EEXIST) { /* File exists already. */ switch (rip->i_mode & I_TYPE) { case I_REGULAR: /* truncate regular file */ if ( (r = forbidden(rip, W_BIT, 0)) == OK) truncate(rip); break; case I_DIRECTORY: /* can't truncate directory */ r = EISDIR; break; case I_CHAR_SPECIAL: /* special files are special */ case I_BLOCK_SPECIAL: if ( (r = forbidden(rip, W_BIT, 0)) != OK) break; r = dev_open( (dev_nr) rip->i_zone[0], W_BIT); break; } } /* If error, return inode. */ if (r != OK) { put_inode(rip); return(r); } /* Claim the file descriptor and filp slot and fill them in. */ fp->fp_filp[file_d] = fil_ptr; fil_ptr->filp_count = 1; fil_ptr->filp_ino = rip; return(file_d); } /*===========================================================================* * do_mknod * *===========================================================================*/ PUBLIC int do_mknod() { /* Perform the mknod(name, mode, addr) system call. */ register mask_bits bits; if (!super_user) return(EPERM); /* only super_user may make nodes */ if (fetch_name(name1, name1_length, M1) != OK) return(err_code); bits = (mode & I_TYPE) | (mode & ALL_MODES & fp->fp_umask); put_inode(new_node(user_path, bits, (zone_nr) addr)); return(err_code); } /*===========================================================================* * new_node * *===========================================================================*/ PRIVATE struct inode *new_node(path, bits, z0) char *path; /* pointer to path name */ mask_bits bits; /* mode of the new inode */ zone_nr z0; /* zone number 0 for new inode */ { /* This function is called by do_creat() and do_mknod(). In both cases it * allocates a new inode, makes a directory entry for it on the path 'path', * and initializes it. It returns a pointer to the inode if it can do this; * err_code is set to OK or EEXIST. If it can't, it returns NIL_INODE and * 'err_code' contains the appropriate message. */ register struct inode *rlast_dir_ptr, *rip; register int r; char string[NAME_SIZE]; extern struct inode *alloc_inode(), *advance(), *last_dir(); /* See if the path can be opened down to the last directory. */ if ((rlast_dir_ptr = last_dir(path, string)) == NIL_INODE) return(NIL_INODE); /* The final directory is accessible. Get final component of the path. */ rip = advance(rlast_dir_ptr, string); if ( rip == NIL_INODE && err_code == ENOENT) { /* Last path component does not exist. Make new directory entry. */ if ( (rip = alloc_inode(rlast_dir_ptr->i_dev, bits)) == NIL_INODE) { /* Can't creat new inode: out of inodes. */ put_inode(rlast_dir_ptr); return(NIL_INODE); } /* Force inode to the disk before making directory entry to make * the system more robust in the face of a crash: an inode with * no directory entry is much better than the opposite. */ rip->i_nlinks++; rip->i_zone[0] = z0; rw_inode(rip, WRITING); /* force inode to disk now */ /* New inode acquired. Try to make directory entry. */ if ((r = search_dir(rlast_dir_ptr, string, &rip->i_num,ENTER)) != OK) { put_inode(rlast_dir_ptr); rip->i_nlinks--; /* pity, have to free disk inode */ rip->i_dirt = DIRTY; /* dirty inodes are written out */ put_inode(rip); /* this call frees the inode */ err_code = r; return(NIL_INODE); } } else { /* Either last component exists, or there is some problem. */ if (rip != NIL_INODE) r = EEXIST; else r = err_code; } /* Return the directory inode and exit. */ put_inode(rlast_dir_ptr); err_code = r; return(rip); } /*===========================================================================* * do_open * *===========================================================================*/ PUBLIC int do_open() { /* Perform the open(name, mode) system call. */ register struct inode *rip; struct filp *fil_ptr; register int r; register mask_bits bits; int file_d; extern struct inode *eat_path(); /* See if file descriptor and filp slots are available. The variable * 'mode' is 0 for read, 1 for write, 2 for read+write. The variable * 'bits' needs to be R_BIT, W_BIT, and R_BIT|W_BIT respectively. */ if (mode < 0 || mode > 2) return(EINVAL); if (fetch_name(name, name_length, M3) != OK) return(err_code); bits = (mask_bits) mode_map[mode]; if ( (r = get_fd(bits, &file_d, &fil_ptr)) != OK) return(r); /* Scan path name. */ if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); if ((r = forbidden(rip, bits, 0)) != OK) { put_inode(rip); /* can't open: protection violation */ return(r); } /* Opening regular files, directories and special files are different. */ switch (rip->i_mode & I_TYPE) { case I_DIRECTORY: if (bits & W_BIT) { put_inode(rip); return(EISDIR); } break; case I_CHAR_SPECIAL: /* Assume that first open of char special file is controlling tty. */ if (fp->fs_tty == 0) fp->fs_tty = (dev_nr) rip->i_zone[0]; dev_open((dev_nr) rip->i_zone[0], (int) bits); break; case I_BLOCK_SPECIAL: dev_open((dev_nr) rip->i_zone[0], (int) bits); break; } /* Claim the file descriptor and filp slot and fill them in. */ fp->fp_filp[file_d] = fil_ptr; fil_ptr->filp_count = 1; fil_ptr->filp_ino = rip; return(file_d); } /*===========================================================================* * do_close * *===========================================================================*/ PUBLIC int do_close() { /* Perform the close(fd) system call. */ register struct filp *rfilp; register struct inode *rip; int rw; int mode_word; extern struct filp *get_filp(); /* First locate the inode that belongs to the file descriptor. */ if ( (rfilp = get_filp(fd)) == NIL_FILP) return(err_code); rip = rfilp->filp_ino; /* 'rip' points to the inode */ /* Check to see if the file is special. */ mode_word = rip->i_mode & I_TYPE; if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { if (mode_word == I_BLOCK_SPECIAL) { /* Invalidate cache entries unless special is mounted or ROOT.*/ do_sync(); /* purge cache */ if (mounted(rip) == FALSE) invalidate((dev_nr) rip->i_zone[0]); } dev_close((dev_nr) rip->i_zone[0]); } /* If the inode being closed is a pipe, release everyone hanging on it. */ if (rfilp->filp_ino->i_pipe) { rw = (rfilp->filp_mode & R_BIT ? WRITE : READ); release(rfilp->filp_ino, rw, NR_PROCS); } /* If a write has been done, the inode is already marked as DIRTY. */ if (--rfilp->filp_count == 0) put_inode(rfilp->filp_ino); fp->fp_filp[fd] = NIL_FILP; return(OK); } /*===========================================================================* * do_lseek * *===========================================================================*/ PUBLIC int do_lseek() { /* Perform the lseek(ls_fd, offset, whence) system call. */ register struct filp *rfilp; register file_pos pos; extern struct filp *get_filp(); /* Check to see if the file descriptor is valid. */ if ( (rfilp = get_filp(ls_fd)) == NIL_FILP) return(err_code); /* No lseek on pipes. */ if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE); /* The value of 'whence' determines the algorithm to use. */ switch(whence) { case 0: pos = offset; break; case 1: pos = rfilp->filp_pos + offset; break; case 2: pos = rfilp->filp_ino->i_size + offset; break; default: return(EINVAL); } if (pos < (file_pos) 0) return(EINVAL); rfilp->filp_ino->i_seek = ISEEK; /* inhibit read ahead */ rfilp->filp_pos = pos; reply_l1 = pos; /* insert the long into the output message */ return(OK); } _mode_map: 516 _do_creat 6 _do_creat: ,#10 _1: I001D 4 8192 I00117 16384 I00115 24576 I00117 -32768 I00111 3 _m+4 _m+8 _fetch_name je I0013 _err_code -10() _get_fd je I0016 _fp _m+6 3583 or 32768 , _user_path _new_node _err_code , je I0019 ,#-17 je I0019 I0019: ,#-17 I001D 61440 I001F I00111: _forbidden jne I001D _truncate I001D I00115: ,#-21 I001D I00117: _forbidden je I00119 I001D I00119: 14 _dev_open I001D I001F: #_1 .csb2 I001D: je I0011C _put_inode I0011C: _fp -10() sal 1 6, 2,#1 4, -10() _do_mknod _do_mknod: _super_user I0023 -1 I0021 I0023: _m+4 _m+10 _fetch_name je I0026 _err_code I0021 I0026: _fp _m+6 3583 _m+6 and 61440 or _m+8 _user_path _new_node _put_inode _err_code I0021: _new_node: ,#22 -20() _last_r I0033 I0031 I0033: -20() _advance I0036 _err_code,#-2 I0036 32 _alloc_inode I003A _put_inode I0031 I003A: 13 -22(), -22() 14, _rw_inode 34 -20() _search_r ,#8 , je I0037 _put_inode 13 -22(), -22() 38,#1 _put_inode _err_code, I0031 I0036: je I00310 ,#-17 I0037 I00310: _err_code , I0037: _put_inode _err_code, I0031: _do_open _do_open: ,#10 _2: I00413 3 8192 I00418 16384 I00414 24576 I0041C _m+6 jl I0042 _m+6,#2 jle I0043 I0042: -22 I0041 I0043: 3 _m+4 _m+8 _fetch_name je I0047 _err_code I0041 I0047: _m+6 al,_mode_map , -10() _get_fd , je I004A I0041 I004A: _user_path _eat_path I004D _err_code I0041 I004D: _forbidden , je I00410 _put_inode I0041 I00410: 61440 I00412 I00414: testb ,#2 je I00413 _put_inode -21 I0041 I00418: _fp 52 I0041A _fp 14 52(), I0041A: 14 _dev_open I00413 I0041C: 14 _dev_open I00413 I00412: #_2 .csb2 I00413: _fp -10() sal 1 6, 2,#1 4, -10() I0041: _do_close _do_close: ,#10 _m+4 _get_filp I0053 _err_code I0051 I0053: 4 61440 , 8192 je I0055 24576 I0056 I0055: 24576 I005A _do_sync _mounted I005A 14 _invalidate I005A: 14 _dev_close I0056: 4 cmpb 39 je I00510 testb ,#4 je I00513 4 I00514 I00513: 3 I00514: 6 4 _release I00510: 2 -10(), -10() I00516 4 _put_inode I00516: _fp _m+4 sal 1 6 I0051: _do_lseek _do_lseek: ,#6 _3: I006D 2 I006A I006B I006C _m+4 _get_filp I0063 _err_code I0061 I0063: 4 cmpb 39,#1 I0066 -29 I0061 I0066: _m+6 I0068 I006A: _m+10 , _m+10+2 , I0069 I006B: 6 8 _m+10 adc _m+10+2 , , I0069 I006C: 4 4 6 _m+10 adc _m+10+2 , , I0069 I006D: -22 I0061 I0068: #_3 pop .csa2 I0069: 0 sbb 0 1f je 1f 1: or jge I006F -22 I0061 I006F: 4 41,#1 6, 8, _m1+10, _m1+10+2, I0061: /* The following names are synonyms for the variables in the input message. */ #define acc_time m.m2_l1 #define addr m.m1_i3 #define buffer m.m1_p1 #define cd_flag m.m1_i2 #define child m.m1_i2 #define co_mode m.m1_i1 #define eff_grp_id m.m1_i3 #define eff_user_id m.m1_i3 #define erki m.m1_p1 #define fd m.m1_i1 #define fd2 m.m1_i2 #define ioflags m.m1_i3 #define group m.m1_i3 #define real_grp_id m.m1_i2 #define ls_fd m.m2_i1 #define mk_mode m.m1_i2 #define mode m.m3_i2 #define name m.m3_p1 #define name1 m.m1_p1 #define name2 m.m1_p2 #define name_length m.m3_i1 #define name1_length m.m1_i1 #define name2_length m.m1_i2 #define nbytes m.m1_i2 #define offset m.m2_l1 #define owner m.m1_i2 #define parent m.m1_i1 #define pathname m.m3_ca1 #define pro m.m1_i1 #define rd_only m.m1_i3 #define real_user_id m.m1_i2 #define request m.m1_i2 #define sig m.m1_i2 #define slot1 m.m1_i1 #define tp m.m2_l1 #define update_time m.m2_l2 #define utime_file m.m2_p1 #define utime_length m.m2_i1 #define whence m.m2_i2 /* The following names are synonyms for the variables in the output message. */ #define reply_type m1.m_type #define reply_l1 m1.m2_l1 #define reply_i1 m1.m1_i1 #define reply_i2 m1.m1_i2 #define reply_t1 m1.m4_l1 #define reply_t2 m1.m4_l2 #define reply_t3 m1.m4_l3 #define reply_t4 m1.m4_l4 /* This file contains the procedures that look up path names in the directory * system and determine the inode number that goes with a given path name. * * The entry points into this file are * eat_path: the 'main' routine of the path-to-inode conversion mechanism * last_dir: find the final directory on a given path * advance: parse one component of a path name * search_dir: search a directory for a string and return its inode number */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "super.h" /*===========================================================================* * eat_path * *===========================================================================*/ PUBLIC struct inode *eat_path(path) char *path; /* the path name to be parsed */ { /* Parse the path 'path' and put its inode in the inode table. If not * possible, return NIL_INODE as function value and an error code in 'err_code'. */ register struct inode *ldip, *rip; char string[NAME_SIZE]; /* hold 1 path component name here */ extern struct inode *last_dir(), *advance(); /* First open the path down to the final directory. */ if ( (ldip = last_dir(path, string)) == NIL_INODE) return(NIL_INODE); /* we couldn't open final directory */ /* The path consisting only of "/" is a special case, check for it. */ if (string[0] == '\0') return(ldip); /* Get final component of the path. */ rip = advance(ldip, string); put_inode(ldip); return(rip); } /*===========================================================================* * last_dir * *===========================================================================*/ PUBLIC struct inode *last_dir(path, string) char *path; /* the path name to be parsed */ char string[NAME_SIZE]; /* the final component is returned here */ { /* Given a path, 'path', located in the fs address space, parse it as * far as the last directory, fetch the inode for the last directory into * the inode table, and return a pointer to the inode. In * addition, return the final component of the path in 'string'. * If the last directory can't be opened, return NIL_INODE and * the reason for failure in 'err_code'. */ register struct inode *rip; register char *new_name; register struct inode *new_ip; extern struct inode *advance(); extern char *get_name(); /* Is the path absolute or relative? Initialize 'rip' accordingly. */ rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir); dup_inode(rip); /* inode will be returned with put_inode */ /* Scan the path component by component. */ while (TRUE) { /* Extract one component. */ if ( (new_name = get_name(path, string)) == (char*) 0) { put_inode(rip); /* bad path in user space */ return(NIL_INODE); } if (*new_name == '\0') return(rip); /* normal exit */ /* There is more path. Keep parsing. */ new_ip = advance(rip, string); put_inode(rip); /* rip either obsolete or irrelevant */ if (new_ip == NIL_INODE) return(NIL_INODE); /* The call to advance() succeeded. Fetch next component. */ path = new_name; rip = new_ip; } } /*===========================================================================* * get_name * *===========================================================================*/ PRIVATE char *get_name(old_name, string) char *old_name; /* path name to parse */ char string[NAME_SIZE]; /* component extracted from 'old_name' */ { /* Given a pointer to a path name in fs space, 'old_name', copy the next * component to 'string' and pad with zeros. A pointer to that part of * the name as yet unparsed is returned. Roughly speaking, * 'get_name' = 'old_name' - 'string'. * * This routine follows the standard convention that /usr/ast, /usr//ast, * //usr///ast and /usr/ast/ are all equivalent. */ register int c; register char *np, *rnp; np = string; /* 'np' points to current position */ rnp = old_name; /* 'rnp' points to unparsed string */ while ( (c = *rnp) == '/') rnp++; /* skip leading slashes */ /* Copy the unparsed path, 'old_name', to the array, 'string'. */ while ( rnp < &user_path[MAX_PATH] && c != '/' && c != '\0') { if (np < &string[NAME_SIZE]) *np++ = c; c = *++rnp; /* advance to next character */ } /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */ while (c == '/' && rnp < &user_path[MAX_PATH]) c = *++rnp; /* Pad the component name out to NAME_SIZE chars, using 0 as filler. */ while (np < &string[NAME_SIZE]) *np++ = '\0'; if (rnp >= &user_path[MAX_PATH]) { err_code = E_LONG_STRING; return((char *) 0); } return(rnp); } /*===========================================================================* * advance * *===========================================================================*/ PUBLIC struct inode *advance(dirp, string) struct inode *dirp; /* inode for directory to be searched */ char string[NAME_SIZE]; /* component name to look for */ { /* Given a directory and a component of a path, look up the component in * the directory, find the inode, open it, and return a pointer to its inode * slot. If it can't be done, return NIL_INODE. */ register struct inode *rip; struct inode *rip2; register struct super_block *sp; int r; dev_nr mnt_dev; inode_nr numb; extern struct inode *get_inode(); /* If 'string' is empty, yield same inode straight away. */ if (string[0] == '\0') return(get_inode(dirp->i_dev, dirp->i_num)); /* If 'string' is not present in the directory, signal error. */ if ( (r = search_dir(dirp, string, &numb, LOOK_UP)) != OK) { err_code = r; return(NIL_INODE); } /* The component has been found in the directory. Get inode. */ if ( (rip = get_inode(dirp->i_dev, numb)) == NIL_INODE) return(NIL_INODE); if (rip->i_num == ROOT_INODE) if (dirp->i_num == ROOT_INODE) { if (string[1] == '.') { for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++) { if (sp->s_dev == rip->i_dev) { /* Release the root inode. Replace by the * inode mounted on. */ put_inode(rip); mnt_dev = sp->s_imount->i_dev; rip2 = get_inode(mnt_dev, sp->s_imount->i_num); rip = advance(rip2, string); put_inode(rip2); break; } } } } /* See if the inode is mounted on. If so, switch to root directory of the * mounted file system. The super_block provides the linkage between the * inode mounted on and the root directory of the mounted file system. */ while (rip->i_mount == I_MOUNT) { /* The inode is indeed mounted on. */ for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) { if (sp->s_imount == rip) { /* Release the inode mounted on. Replace by the * inode of the root inode of the mounted device. */ put_inode(rip); rip = get_inode(sp->s_dev, ROOT_INODE); break; } } } return(rip); /* return pointer to inode's component */ } /*===========================================================================* * search_dir * *===========================================================================*/ PUBLIC int search_dir(ldir_ptr, string, numb, flag) register struct inode *ldir_ptr; /* ptr to inode for dir to search */ char string[NAME_SIZE]; /* component to search for */ inode_nr *numb; /* pointer to inode number */ int flag; /* LOOK_UP, ENTER, or DELETE */ { /* This function searches the directory whose inode is pointed to by 'ldip': * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb'; * if (flag == ENTER) enter 'string' in the directory with inode # '*numb'; * if (flag == DELETE) delete 'string' from the directory; */ register dir_struct *dp; register struct buf *bp; register int r; mask_bits bits; file_pos pos; unsigned new_slots, old_slots; block_nr b; int e_hit; extern struct buf *get_block(), *new_block(); extern block_nr read_map(); extern real_time clock_time(); /* If 'ldir_ptr' is not a pointer to a searchable dir inode, error. */ if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) return(ENOTDIR); bits = (flag == LOOK_UP ? X_BIT : W_BIT|X_BIT); if ( (r = forbidden(ldir_ptr, bits, 0)) != OK) return(r); /* Step through the directory one block at a time. */ old_slots = ldir_ptr->i_size/DIR_ENTRY_SIZE; new_slots = 0; e_hit = FALSE; for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) { b = read_map(ldir_ptr, pos); /* get block number */ /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */ bp = get_block(ldir_ptr->i_dev, b, NORMAL); /* get a dir block */ /* Search a directory block. */ for (dp = &bp->b_dir[0]; dp < &bp->b_dir[NR_DIR_ENTRIES]; dp++) { if (++new_slots > old_slots) { /* not found, but room left */ if (flag == ENTER) e_hit = TRUE; break; } if (flag != ENTER && dp->d_inum != 0 && cmp_string(dp->d_name, string, NAME_SIZE)) { /* LOOK_UP or DELETE found what it wanted. */ if (flag == DELETE) { dp->d_inum = 0; /* erase entry */ bp->b_dirt = DIRTY; ldir_ptr->i_modtime = clock_time(); } else *numb = dp->d_inum; /* 'flag' is LOOK_UP */ put_block(bp, DIRECTORY_BLOCK); return(OK); } /* Check for free slot for the benefit of ENTER. */ if (flag == ENTER && dp->d_inum == 0) { e_hit = TRUE; /* we found a free slot */ break; } } /* The whole block has been searched or ENTER has a free slot. */ if (e_hit) break; /* e_hit set if ENTER can be performed now */ put_block(bp, DIRECTORY_BLOCK); /* otherwise, continue searching dir */ } /* The whole directory has now been searched. */ if (flag != ENTER) return(ENOENT); /* This call is for ENTER. If no free slot has been found so far, try to * extend directory. */ if (e_hit == FALSE) { /* directory is full and no room left in last block */ new_slots ++; /* increase directory size by 1 entry */ if (new_slots == 0) return(EFBIG); /* dir size limited by slot count */ if ( (bp = new_block(ldir_ptr, ldir_ptr->i_size)) == NIL_BUF) return(err_code); dp = &bp->b_dir[0]; } /* 'bp' now points to a directory block with space. 'dp' points to slot. */ copy(dp->d_name, string, NAME_SIZE); dp->d_inum = *numb; bp->b_dirt = DIRTY; put_block(bp, DIRECTORY_BLOCK); ldir_ptr->i_modtime = clock_time(); ldir_ptr->i_dirt = DIRTY; if (new_slots > old_slots) ldir_ptr->i_size = (file_pos) new_slots * DIR_ENTRY_SIZE; return(OK); } _eat_path _eat_path: ,#18 -1 _last_r I0013 cmpb -1 I0016 -1 _advance _put_inode _last_r _last_r: ,#6 cmpb ,#47 I0023 _fp 4 I0024 I0023: _fp 2 I0024: _dup_inode I0026: _get_name I0029 _put_inode I0021 I0029: cmpb I002C I0021 I002C: _advance , _put_inode I002F I0021 I002F: , I0026 I0021: _get_name: ,#6 , I0033: ,#47 I0036 ,#1 I0033 I0036: ,#_user_path+128 jae I003E ,#47 je I003E je I003E 14 , jae I003B ,#1 I003B: ,#1 I0036 I003E: ,#47 I00312 ,#_user_path+128 jae I00312 ,#1 I003E I00312: 14 , jae I00311 ,#1 I00312 I00311: ,#_user_path+128 jb I00315 _err_code,#-103 I0031 I00315: I0031: _advance _advance: ,#12 cmpb I0043 34 32() _get_inode I0041 I0043: -12() _search_r ,#8 , je I0046 _err_code, I0041 I0046: -12() 32 _get_inode I0049 I0041 I0049: 34,#1 I0041C 34,#1 I0041C cmpb ,#46 I0041C ,#_super_block+50 I00417: ,#_super_block+250 jae I0041C 32() 38, I00415 _put_inode 42 32 -10(), 42 34 -10() _get_inode _advance , _put_inode I0041C I00415: ,#50 I00417 I0041C: cmpb 40,#1 I0041B ,#_super_block I00421: ,#_super_block+250 jae I0041C 42, I0041F _put_inode 38 _get_inode I0041C I0041F: ,#50 I00421 I0041B: I0041: _search_r _search_r: ,#22 61440 16384 je I0053 -20 I0051 I0053: 10() I0056 I0057 I0056: 3 I0057: _forbidden , je I0059 I0051 I0059: 6 4 6 .dvi4 -1, -1 -20() -12() -10(bp) I005E: -12() -10() 4 sbb 6 1f je 1f 1: or jge I005B -10() -12() _read_map -1, -1 32 _get_block I00512: 1024 , jae I005F -1 1 -1, -1 -1, jbe I00514 10(),#1 I005F -20(),#1 I005F I00514: 10(),#1 je I0051A je I0051A 4 2 _cmp_string je I0051A 10(),#2 I0051F 1034,#1 _clock_time 8, 10, I00520 I0051F: I00520: 65 _put_block I0051 I0051A: 10(),#1 I00510 I00510 -20(),#1 I005F I00510: , I00512 I005F: -20() je I00526 I005B I00526: 65 _put_block -12() -10() 1024 adc 0 -12(), -10(), I005E I005B: 10(),#1 je I00529 -2 I0051 I00529: -20() I0052C -1 1 -1, -1 I0052F -27 I0051 I0052F: 6 4 _new_block I00532 _err_code I0051 I00532: I0052C: 4 2 _copy 1034,#1 65 _put_block _clock_time 8, 10, 38,#1 -1 -1, jbe I00535 -1 .mli4 4, 6, I00535: I0051: /* This file deals with the suspension and revival of processes. A process can * be suspended because it wants to read or write from a pipe and can't, or * because it wants to read or write from a special file and can't. When a * process can't continue it is suspended, and revived later when it is able * to continue. * * The entry points into this file are * do_pipe: perform the PIPE system call * pipe_check: check to see that a read or write on a pipe is feasible now * suspend: suspend a process that cannot do a requested read or write * release: check to see if a suspended process can be released and do it * revive: mark a suspended process as able to run again * do_unpause: a signal has been sent to a process; see if it suspended */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "../h/signal.h" #include "const.h" #include "type.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" PRIVATE message mess; /*===========================================================================* * do_pipe * *===========================================================================*/ PUBLIC int do_pipe() { /* Perform the pipe(fil_des) system call. */ register struct fproc *rfp; register struct inode *rip; int r; dev_nr device; struct filp *fil_ptr0, *fil_ptr1; int fil_des[2]; /* reply goes here */ extern struct inode *alloc_inode(); /* Acquire two file descriptors. */ rfp = fp; if ( (r = get_fd(R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r); rfp->fp_filp[fil_des[0]] = fil_ptr0; fil_ptr0->filp_count = 1; if ( (r = get_fd(W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NIL_FILP; fil_ptr0->filp_count = 0; return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; fil_ptr1->filp_count = 1; /* Make the inode in the current working directory. */ device = rfp->fp_workdir->i_dev; /* inode dev is same as working dir */ if ( (rip = alloc_inode(device, I_REGULAR)) == NIL_INODE) { rfp->fp_filp[fil_des[0]] = NIL_FILP; fil_ptr0->filp_count = 0; rfp->fp_filp[fil_des[1]] = NIL_FILP; fil_ptr1->filp_count = 0; return(err_code); } rip->i_pipe = I_PIPE; fil_ptr0->filp_ino = rip; dup_inode(rip); /* for double usage */ fil_ptr1->filp_ino = rip; rw_inode(rip, WRITING); /* mark inode as allocated */ reply_i1 = fil_des[0]; reply_i2 = fil_des[1]; return(OK); } /*===========================================================================* * pipe_check * *===========================================================================*/ PUBLIC int pipe_check(rip, rw_flag, virgin, bytes, position) register struct inode *rip; /* the inode of the pipe */ int rw_flag; /* READING or WRITING */ int virgin; /* 1 if no data transferred yet, else 0 */ register int bytes; /* bytes to be read or written (all chunks) */ register file_pos *position; /* pointer to current file position */ { /* Pipes are a little different. If a process reads from an empty pipe for * which a writer still exists, suspend the reader. If the pipe is empty * and there is no writer, return 0 bytes. If a process is writing to a * pipe and no one is reading from it, give a broken pipe error. */ extern struct filp *find_filp(); /* If reading, check for empty pipe. */ if (rw_flag == READING) { if (*position >= rip->i_size) { /* Process is reading from an empty pipe. */ if (find_filp(rip, W_BIT) != NIL_FILP) { /* Writer exists; suspend rdr if no data already read.*/ if (virgin) suspend(XPIPE); /* block reader */ /* If need be, activate sleeping writer. */ if (susp_count > 0) release(rip, WRITE, 1); } return(0); } } else { /* Process is writing to a pipe. */ if (bytes > PIPE_SIZE) return(EFBIG); if (find_filp(rip, R_BIT) == NIL_FILP) { /* Tell MM to generate a SIGPIPE signal. */ mess.m_type = KSIG; mess.PROC1 = fp - fproc; mess.SIG_MAP = 1 << (SIGPIPE - 1); send(MM_PROC_NR, &mess); return(EPIPE); } if (*position + bytes > PIPE_SIZE) { suspend(XPIPE); /* stop writer -- pipe full */ return(0); } /* Writing to an empty pipe. Search for suspended reader. */ if (*position == 0) release(rip, READ, 1); } return(1); } /*===========================================================================* * suspend * *===========================================================================*/ PUBLIC suspend(task) int task; /* who is proc waiting for? (PIPE = pipe) */ { /* Take measures to suspend the processing of the present system call. * Store the parameters to be used upon resuming in the process table. * (Actually they are not used when a process is waiting for an I/O device, * but they are needed for pipes, and it is not worth making the distinction.) */ if (task == XPIPE) susp_count++; /* count procs suspended on pipe */ fp->fp_suspended = SUSPENDED; fp->fp_fd = fd << 8 | fs_call; fp->fp_buffer = buffer; fp->fp_nbytes = nbytes; fp->fp_task = -task; dont_reply = TRUE; /* do not send caller a reply message now */ } /*===========================================================================* * release * *===========================================================================*/ PUBLIC release(ip, call_nr, count) register struct inode *ip; /* inode of pipe */ int call_nr; /* READ or WRITE */ int count; /* max number of processes to release */ { /* Check to see if any process is hanging on the pipe whose inode is in 'ip'. * If one is, and it was trying to perform the call indicated by 'call_nr' * (READ or WRITE), release it. */ register struct fproc *rp; /* Search the proc table. */ for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) { if (rp->fp_suspended == SUSPENDED && (rp->fp_fd & BYTE) == call_nr && rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) { revive(rp - fproc, 0); susp_count--; /* keep track of who is suspended */ if (--count == 0) return; } } } /*===========================================================================* * revive * *===========================================================================*/ PUBLIC revive(proc_nr, bytes) int proc_nr; /* process to revive */ int bytes; /* if hanging on task, how many bytes read */ { /* Revive a previously blocked process. When a process hangs on tty, this * is the way it is eventually released. */ register struct fproc *rfp; if (proc_nr < 0 || proc_nr >= NR_PROCS) panic("revive err", proc_nr); rfp = &fproc[proc_nr]; if (rfp->fp_suspended == NOT_SUSPENDED || rfp->fp_revived == REVIVING)return; /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get * a message right away. The revival process is different for TTY and pipes. * For TTY revival, the work is already done, for pipes it is not: the proc * must be restarted so it can try again. */ if (rfp->fp_task == XPIPE) { /* Revive a process suspended on a pipe. */ rfp->fp_revived = REVIVING; reviving++; /* process was waiting on pipe */ } else { /* Revive a process suspended on TTY or other device. */ rfp->fp_suspended = NOT_SUSPENDED; rfp->fp_nbytes = bytes; /* pretend it only wants what there is */ reply(proc_nr, bytes); /* unblock the process */ } } /*===========================================================================* * do_unpause * *===========================================================================*/ PUBLIC int do_unpause() { /* A signal has been sent to a user who is paused on the file system. * Abort the system call with the EINTR error message. */ register struct fproc *rfp; int proc_nr, task, fild; struct filp *f; dev_nr dev; extern struct filp *get_filp(); if (who > MM_PROC_NR) return(EPERM); proc_nr = pro; if (proc_nr < 0 || proc_nr >= NR_PROCS) panic("unpause err 1", proc_nr); rfp = &fproc[proc_nr]; if (rfp->fp_suspended == NOT_SUSPENDED) return(OK); task = -rfp->fp_task; if (task != XPIPE) { fild = (rfp->fp_fd >> 8) & BYTE; /* extract file descriptor */ if (fild < 0 || fild >= NR_FDS) panic("unpause err 2", NO_NUM); f = rfp->fp_filp[fild]; dev = f->filp_ino->i_zone[0]; /* device on which proc is hanging */ mess.TTY_LINE = (dev >> MINOR) & BYTE; mess.PROC_NR = proc_nr; mess.m_type = CANCEL; if (sendrec(task, &mess) != OK) panic("unpause err 3", NO_NUM); while (mess.REP_PROC_NR != proc_nr) { revive(mess.REP_PROC_NR, mess.REP_STATUS); if (receive(task, &m) != OK) panic("unpause err 4", NO_NUM); } revive(proc_nr, EINTR); /* signal interrupted call */ } return(OK); } _do_pipe _do_pipe: , _fp , -10() -1 4 _get_fd , je I0013 -1 sal 1 -10() 6, -10() 2,#1 -12() -1 _get_fd , je I0016 -1 sal 1 6 -10() 2 -1 sal 1 -12() 6, -12() 2,#1 2 32 , 32768 _alloc_inode I0019 -1 sal 1 6 -10() 2 -1 sal 1 6 -12() mov 2 _err_code I0019: 39,#1 -10() 4, _dup_inode -12() 4, _rw_inode -1 _m1+4, -1 _m1+6, _pipe_check _pipe_check: I0023 12() 2 4() sbb 6() 1f je 1f 1: or jl I0024 _find_filp 0 je I0029 je I002C _suend I002C: _su_count jle I0029 4 _release I0029: I0021 I0023: 10(),#7168 jle I00212 -27 I0021 I00212: 4 _find_filp 0 I00215 _mess+2,#64 _fp _fproc 64 cwd iv _mess+4, _mess+6,#4096 _mess _send -32 I0021 I00215: 10() cwd 12() adc 2 7168 sbb #0 1f je 1f 1: or jle I00218 _suend I0021 I00218: 12() 2 0 sbb 0 1f or 1: or I0024 3 _release I0024: I0021: _suend _suend: I0033 _su_count I0033: _fp 60,#1 8 _m+4 sal cl or _fs_call _fp 54(), _fp _m+10 56, _fp _m+6 58, _fp 62,al _dont_reply,#1 _release _release: -2(),#_fproc I0045: ,#_fproc+1024 jae I0042 cmpb 60,#1 I0043 54 I0043 8 54() sar cl sal 1 6 4, I0043 _fproc 64 cwd iv _revive _su_count I0043 I0043: ,#64 I0045 I0042: _revive _revive: jl I0052 , jl I0053 I0052: _1 _panic I0053: 6 sal cl _fproc , cmpb 60 je I0056 cmpb 61,#1 I0057 I0056: I0057: cmpb 62 I005B 61,#1 _reviving I005C I005B: 60 58, _reply I005C: _do_unpause _do_unpause: ,#12 _who jle I0063 -1 I0061 I0063: _m+4 , jl I0065 , jl I0066 I0065: _2 _panic I0066: 6 sal cl _fproc , cmpb 60 I006A I0061 I006A: al,62 , je I006D 8 54 sar cl , jl I006F ,#20 jl I00610 I006F: 32768 _3 _panic I00610: sal 1 6 -10(), -10() 4 14 -12(), -12() shr cl _mess+4, _mess+6, _mess+2 _mess _sendrec je I00617 32768 _4 _panic I00617: _mess+4, je I00616 _mess+6 _mess+4 _revive _m _receive je I00617 32768 _5 _panic I00617 I00616: -4 _revive I006D: I0061: _mess: .zerow 24/2 _1: 25970 26998 25974 25888 29298 _2: 28277 24944 29557 8293 29285 8306 49 _3: 28277 24944 29557 8293 29285 8306 50 _4: 28277 24944 29557 .word 8293 29285 8306 51 _5: 28277 24944 29557 8293 29285 8306 52 /* This file deals with protection in the file system. It contains the code * for four system calls that relate to protection. * * The entry points into this file are * do_chmod: perform the CHMOD system call * do_chown: perform the CHOWN system call * do_umask: perform the UMASK system call * do_access: perform the ACCESS system call * forbidden: check to see if a given access is allowed on a given inode */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" #include "super.h" /*===========================================================================* * do_chmod * *===========================================================================*/ PUBLIC int do_chmod() { /* Perform the chmod(name, mode) system call. */ register struct inode *rip; register int r; extern struct inode *eat_path(); /* Temporarily open the file. */ if (fetch_name(name, name_length, M3) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); /* Only the owner or the super_user may change the mode of a file. * No one may change the mode of a file on a read-only file system. */ if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM; else r = read_only(rip); /* If error, return inode. */ if (r != OK) { put_inode(rip); return(r); } /* Now make the change. */ rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES); rip->i_dirt = DIRTY; put_inode(rip); return(OK); } /*===========================================================================* * do_chown * *===========================================================================*/ PUBLIC int do_chown() { /* Perform the chown(name, owner, group) system call. */ register struct inode *rip; register int r; extern struct inode *eat_path(); /* Only the super_user may perform the chown() call. */ if (!super_user) return(EPERM); /* Temporarily open the file. */ if (fetch_name(name1, name1_length, M1) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); /* Not permitted to change the owner of a file on a read-only file sys. */ r = read_only(rip); if (r == OK) { rip->i_uid = owner; rip->i_gid = group; rip->i_dirt = DIRTY; } put_inode(rip); return(r); } /*===========================================================================* * do_umask * *===========================================================================*/ PUBLIC int do_umask() { /* Perform the umask(co_mode) system call. */ register mask_bits r; r = ~fp->fp_umask; /* set 'r' to complement of old mask */ fp->fp_umask = ~(co_mode & RWX_MODES); return(r); /* return complement of old mask */ } /*===========================================================================* * do_access * *===========================================================================*/ PUBLIC int do_access() { /* Perform the access(name, mode) system call. */ struct inode *rip; register int r; extern struct inode *eat_path(); /* Temporarily open the file whose access is to be checked. */ if (fetch_name(name, name_length, M3) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); /* Now check the permissions. */ r = forbidden(rip, (mask_bits) mode, 1); put_inode(rip); return(r); } /*===========================================================================* * forbidden * *===========================================================================*/ PUBLIC int forbidden(rip, access_desired, real_uid) register struct inode *rip; /* pointer to inode to be checked */ mask_bits access_desired; /* RWX bits */ int real_uid; /* set iff real uid to be tested */ { /* Given a pointer to an inode, 'rip', and the accessed desired, determine * if the access is allowed, and if not why not. The routine looks up the * caller's uid in the 'fproc' table. If the access is allowed, OK is returned * if it is forbidden, EACCES is returned. */ register mask_bits bits, perm_bits, xmask; int r, shift, test_uid, test_gid; /* Isolate the relevant rwx bits from the mode. */ bits = rip->i_mode; test_uid = (real_uid ? fp->fp_realuid : fp->fp_effuid); test_gid = (real_uid ? fp->fp_realgid : fp->fp_effgid); if (test_uid == SU_UID) { perm_bits = 07; } else { if (test_uid == rip->i_uid) shift = 6; /* owner */ else if (test_gid == rip->i_gid ) shift = 3; /* group */ else shift = 0; /* other */ perm_bits = (bits >> shift) & 07; } /* If access desired is not a subset of what is allowed, it is refused. */ r = OK; if ((perm_bits | access_desired) != perm_bits) r = EACCES; /* If none of the X bits are on, not even the super-user can execute it. */ xmask = (X_BIT << 6) | (X_BIT << 3) | X_BIT; /* all 3 X bits */ if ( (access_desired & X_BIT) && (bits & xmask) == 0) r = EACCES; /* Check to see if someone is trying to write on a file system that is * mounted read-only. */ if (r == OK) if (access_desired & W_BIT) r = read_only(rip); return(r); } /*===========================================================================* * read_only * *===========================================================================*/ PRIVATE int read_only(ip) struct inode *ip; /* ptr to inode whose file sys is to be cked */ { /* Check to see if the file system on which the inode 'ip' resides is mounted * read only. If so, return EROFS, else return OK. */ register struct super_block *sp; extern struct super_block *get_super(); sp = get_super(ip->i_dev); return(sp->s_rd_only ? EROFS : OK); } _do_chmod _do_chmod: 3 _m+4 _m+8 _fetch_name je I0013 _err_code _user_path _eat_path I0016 _err_code _fp 48() 2, je I0019 _super_user I0019 ,#-1 I001A I0019: _read_only I001A: je I001D _put_inode I001D: 61952 _m+6 3583 or 38,#1 _put_inode _do_chown _do_chown: _super_user I0023 -1 I0021 I0023: _m+4 _m+10 _fetch_name ,#6 je I0026 _err_code I0021 I0026: _user_path _eat_path I0029 _err_code I0021 I0029: _read_only I002C _m+6 2, _m+8 12,cl 38,#1 I002C: _put_inode I0021: _do_umask _do_umask: _fp not _m+4 511 not _fp _do_access _do_access: 3 _m+4 _m+8 _fetch_name je I0043 _err_code I0041 I0043: _user_path _eat_path I0046 _err_code I0041 I0046: ,_m+6 #1 _forbidden _put_inode I0041: _forbidden _forbidden: ,#14 je I0053 _fp 46 I0054 I0053: _fp 48 I0054: -12() je I0056 _fp al,50 I0057 I0056: _fp al,51 I0057: -1 -12() I0059 ,#7 I005A I0059: 2 -12(), I005C -10(),#6 I005D I005C: al,12 -1, I005F -10(),#3 I005D I005F: -10() I005D: -10() shr cl 7 I005A: or , je I00512 ,#-13 I00512: ,#73 testb ,#1 je I00515 test , I00515 ,#-13 I00515: I00519 testb ,#2 je I00519 _read_only , I00519: _read_only: 32 _get_super cmpb 48 je I0063 -30 I0061 I0063: I0061: /* FS must occasionally print some message. It uses the standard library * routine printf(), which calls putc() and flush. Library * versions of these routines do printing by sending messages to FS. Here * obviously can't do that, so FS calls the TTY task directly. */ #include "../h/const.h" #include "../h/type.h" #include "../h/com.h" #define STDOUTPUT 1 /* file descriptor for standard output */ #define BUFSIZE 100 /* print buffer size */ PRIVATE int bufcount; /* # characters in the buffer */ PRIVATE char printbuf [BUFSIZE]; /* output is buffered here */ PRIVATE message putchmsg; /* used for message to TTY task */ /*===========================================================================* * putc * *===========================================================================*/ PUBLIC putc(c) char c; { if (c == 0) { flush(); return; } printbuf[bufcount++] = c; if (bufcount == BUFSIZE) flush(); if (c == '\n') flush(); } /*===========================================================================* * flush * *===========================================================================*/ PRIVATE flush() { /* Flush the print buffer. */ if (bufcount == 0) return; putchmsg.m_type = TTY_WRITE; putchmsg.PROC_NR = 1; putchmsg.TTY_LINE = 0; putchmsg.ADDRESS = printbuf; putchmsg.COUNT = bufcount; sendrec(TTY, &putchmsg); bufcount = 0; } _putc _putc: cmpb I0013 _flush al, _printbuf _bufcount _bufcount _bufcount,#100 I0016 _flush cmpb ,#10 I0019 _flush I0019: _flush: _bufcount I0023 I0023: _putchmsg+2,#4 _putchmsg+6,#1 _putchmsg+4 _putchmsg+18,#_printbuf _bufcount _putchmsg+8, _putchmsg -7 _sendrec _bufcount _putchmsg: .zerow 24/2 _printbuf: .zerow 100/2 _bufcount: .zerow 2/2 /* This file contains the heart of the mechanism used to read (and write) * files. Read and write requests are split up into chunks that do not cross * block boundaries. Each chunk is then processed in turn. Reads on special * files are also detected and handled. * * The entry points into this file are * do_read: perform the READ system call by calling read_write * read_write: actually do the work of READ and WRITE * read_map: given an inode and file position, lookup its zone number * rw_user: call the kernel to read and write user space * read_ahead: manage the block read ahead business */ #include "../h/const.h" #include "../h/type.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" #include "super.h" #define FD_MASK 077 /* max file descriptor is 63 */ PRIVATE message umess; /* message for asking SYSTASK for user copy */ PUBLIC int rdwt_err; /* set to EIO if disk error occurs */ /*===========================================================================* * do_read * *===========================================================================*/ PUBLIC int do_read() { return(read_write(READING)); } /*===========================================================================* * read_write * *===========================================================================*/ PUBLIC int read_write(rw_flag) int rw_flag; /* READING or WRITING */ { /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */ register struct inode *rip; register struct filp *f; register file_pos bytes_left, f_size; register unsigned off, cum_io; file_pos position; int r, chunk, virg, mode_word, usr, seg; struct filp *wf; extern struct super_block *get_super(); extern struct filp *find_filp(), *get_filp(); extern real_time clock_time(); /* MM loads segments by putting funny things in upper 10 bits of 'fd'. */ if (who == MM_PROC_NR && (fd & (~BYTE)) ) { usr = (fd >> 8) & BYTE; seg = (fd >> 6) & 03; fd &= FD_MASK; /* get rid of user and segment bits */ } else { usr = who; /* normal case */ seg = D; } /* If the file descriptor is valid, get the inode, size and mode. */ if (nbytes == 0) return(0); /* so char special files need not check for 0*/ if (who != MM_PROC_NR && nbytes < 0) return(EINVAL); /* only MM > 32K */ if ( (f = get_filp(fd)) == NIL_FILP) return(err_code); if ( ((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) return(EBADF); position = f->filp_pos; if (position < (file_pos) 0) return(EINVAL); rip = f->filp_ino; f_size = rip->i_size; r = OK; cum_io = 0; virg = TRUE; mode_word = rip->i_mode & I_TYPE; if (mode_word == I_BLOCK_SPECIAL && f_size == 0) f_size = MAX_P_LONG; rdwt_err = OK; /* set to EIO if disk error occurs */ /* Check for character special files. */ if (mode_word == I_CHAR_SPECIAL) { if ((r = dev_io(rw_flag, (dev_nr) rip->i_zone[0], (long) position, nbytes, who, buffer)) >= 0) { cum_io = r; position += r; r = OK; } } else { if (rw_flag == WRITING && mode_word != I_BLOCK_SPECIAL) { /* Check in advance to see if file will grow too big. */ if (position > get_super(rip->i_dev)->s_max_size - nbytes ) return(EFBIG); /* Clear the zone containing present EOF if hole about * to be created. This is necessary because all unwritten * blocks prior to the EOF must read as zeros. */ if (position > f_size) clear_zone(rip, f_size, 0); } /* Pipes are a little different. Check. */ if (rip->i_pipe && (r = pipe_check(rip, rw_flag, virg, nbytes, &position)) <= 0) return(r); /* Split the transfer into chunks that don't span two blocks. */ while (nbytes != 0) { off = position % BLOCK_SIZE; /* offset within a block */ chunk = MIN(nbytes, BLOCK_SIZE - off); if (chunk < 0) chunk = BLOCK_SIZE - off; if (rw_flag == READING) { if ((bytes_left = f_size - position) <= 0) break; else if (chunk > bytes_left) chunk = bytes_left; } /* Read or write 'chunk' bytes. */ r=rw_chunk(rip, position, off, chunk, rw_flag, buffer, seg,usr); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ buffer += chunk; /* user buffer address */ nbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += chunk; /* position within the file */ virg = FALSE; /* tells pipe_check() that data has been copied */ } } /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (mode_word != I_CHAR_SPECIAL && mode_word != I_BLOCK_SPECIAL && position > f_size) rip->i_size = position; rip->i_modtime = clock_time(); rip->i_dirt = DIRTY; } else { if (rip->i_pipe && position >= rip->i_size) { /* Reset pipe pointers. */ rip->i_size = 0; /* no data left */ position = 0; /* reset reader(s) */ if ( (wf = find_filp(rip, W_BIT)) != NIL_FILP) wf->filp_pos = 0; } } f->filp_pos = position; /* Check to see if read-ahead is called for, and if so, set it up. */ if (rw_flag == READING && rip->i_seek == NO_SEEK && position % BLOCK_SIZE == 0 && (mode_word == I_REGULAR || mode_word == I_DIRECTORY)) { rdahed_inode = rip; rdahedpos = position; } if (mode_word == I_REGULAR) rip->i_seek = NO_SEEK; if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == EOF) r = cum_io; return(r == OK ? cum_io : r); } /*===========================================================================* * rw_chunk * *===========================================================================*/ PRIVATE int rw_chunk(rip, position, off, chunk, rw_flag, buff, seg, usr) register struct inode *rip; /* pointer to inode for file to be rd/wr */ file_pos position; /* position within file to read or write */ unsigned off; /* off within the current block */ int chunk; /* number of bytes to read or write */ int rw_flag; /* READING or WRITING */ char *buff; /* virtual address of the user buffer */ int seg; /* T or D segment in user space */ int usr; /* which user process */ { /* Read or write (part of) a block. */ register struct buf *bp; register int r; int dir, n, block_spec; block_nr b; dev_nr dev; extern struct buf *get_block(), *new_block(); extern block_nr read_map(); block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL; if (block_spec) { b = position/BLOCK_SIZE; dev = (dev_nr) rip->i_zone[0]; } else { b = read_map(rip, position); dev = rip->i_dev; } if (!block_spec && b == NO_BLOCK) { if (rw_flag == READING) { /* Reading from a nonexistent block. Must read as all zeros. */ bp = get_block(NO_DEV, NO_BLOCK, NORMAL); /* get a buffer */ zero_block(bp); } else { /* Writing to a nonexistent block. Create and enter in inode. */ if ((bp = new_block(rip, position)) == NIL_BUF)return(err_code); } } else { /* Normally an existing block to be partially overwritten is first read * in. However, a full block need not be read in. If it is already in * the cache, acquire it, otherwise just acquire a free buffer. */ n = (rw_flag == WRITING && chunk == BLOCK_SIZE ? NO_READ : NORMAL); if(rw_flag == WRITING && off == 0 && position >= rip->i_size) n=NO_READ; bp = get_block(dev, b, n); } /* In all cases, bp now points to a valid buffer. */ if (rw_flag == WRITING && chunk != BLOCK_SIZE && !block_spec && position >= rip->i_size && off == 0) zero_block(bp); dir = (rw_flag == READING ? TO_USER : FROM_USER); r = rw_user(seg, usr, (vir_bytes)buff, (vir_bytes)chunk, bp->b_data+off, dir); if (rw_flag == WRITING) bp->b_dirt = DIRTY; n = (off + chunk == BLOCK_SIZE ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK); put_block(bp, n); return(r); } /*===========================================================================* * read_map * *===========================================================================*/ PUBLIC block_nr read_map(rip, position) register struct inode *rip; /* ptr to inode to map from */ file_pos position; /* position in file whose blk wanted */ { /* Given an inode and a position within the corresponding file, locate the * block (not zone) number in which that position is to be found and return it. */ register struct buf *bp; register zone_nr z; register block_nr b; register long excess, zone, block_pos; register int scale, boff; extern struct buf *get_block(); scale = scale_factor(rip); /* for block-zone conversion */ block_pos = position/BLOCK_SIZE; /* relative blk # in file */ zone = block_pos >> scale; /* position's zone */ boff = block_pos - (zone << scale); /* relative blk # within zone */ /* Is 'position' to be found in the inode itself? */ if (zone < NR_DZONE_NUM) { if ( (z = rip->i_zone[zone]) == NO_ZONE) return(NO_BLOCK); b = ((block_nr) z << scale) + boff; return(b); } /* It is not in the inode, so it must be single or double indirect. */ excess = zone - NR_DZONE_NUM; /* first NR_DZONE_NUM don't count */ if (excess < NR_INDIRECTS) { /* 'position' can be located via the single indirect block. */ z = rip->i_zone[NR_DZONE_NUM]; } else { /* 'position' can be located via the double indirect block. */ if ( (z = rip->i_zone[NR_DZONE_NUM+1]) == NO_ZONE) return(NO_BLOCK); excess -= NR_INDIRECTS; /* single indir doesn't count */ b = (block_nr) z << scale; bp = get_block(rip->i_dev, b, NORMAL); /* get double indirect block */ z = bp->b_ind[excess/NR_INDIRECTS]; /* z is zone # for single ind */ put_block(bp, INDIRECT_BLOCK); /* release double ind block */ excess = excess % NR_INDIRECTS; /* index into single ind blk */ } /* 'z' is zone number for single indirect block; 'excess' is index into it. */ if (z == NO_ZONE) return(NO_BLOCK); b = (block_nr) z << scale; bp = get_block(rip->i_dev, b, NORMAL); /* get single indirect block */ z = bp->b_ind[excess]; put_block(bp, INDIRECT_BLOCK); /* release single indirect blk */ if (z == NO_ZONE) return(NO_BLOCK); b = ((block_nr) z << scale) + boff; return(b); } /*===========================================================================* * rw_user * *===========================================================================*/ PUBLIC int rw_user(s, u, vir, bytes, buff, direction) int s; /* D or T space (stack is also D) */ int u; /* process number to r/w (usually = 'who') */ vir_bytes vir; /* virtual address to move to/from */ vir_bytes bytes; /* how many bytes to move */ char *buff; /* pointer to FS space */ int direction; /* TO_USER or FROM_USER */ { /* Transfer a block of data. Two options exist, depending on 'direction': * TO_USER: Move from FS space to user virtual space * FROM_USER: Move from user virtual space to FS space */ if (direction == TO_USER ) { /* Write from FS space to user space. */ umess.SRC_SPACE = D; umess.SRC_PROC_NR = FS_PROC_NR; umess.SRC_BUFFER = (long) buff; umess.DST_SPACE = s; umess.DST_PROC_NR = u; umess.DST_BUFFER = (long) vir; } else { /* Read from user space to FS space. */ umess.SRC_SPACE = s; umess.SRC_PROC_NR = u; umess.SRC_BUFFER = (long) vir; umess.DST_SPACE = D; umess.DST_PROC_NR = FS_PROC_NR; umess.DST_BUFFER = (long) buff; } umess.COPY_BYTES = (long) bytes; sys_copy(&umess); return(umess.m_type); } /*===========================================================================* * read_ahead * *===========================================================================*/ PUBLIC read_ahead() { /* Read a block into the cache before it is needed. */ register struct inode *rip; struct buf *bp; block_nr b; extern struct buf *get_block(); rip = rdahed_inode; /* pointer to inode to read ahead from */ rdahed_inode = NIL_INODE; /* turn off read ahead */ if ( (b = read_map(rip, rdahedpos)) == NO_BLOCK) return; /* at EOF */ bp = get_block(rip->i_dev, b, NORMAL); put_block(bp, PARTIAL_DATA_BLOCK); } _do_read _do_read: _read_write _read_write _read_write: ,#42 _who I0023 _m+4 test 65280 je I0023 8 _m+4 sar cl -30(), 6 _m+4 sar cl 3 -32(), _m+4 63 _m+4, I0024 I0023: _who -30(), -32(),#1 I0024: _m+6 I0027 I0021 I0027: _who je I002A _m+6 jge I002A -22 I0021 I002A: _m+4 _get_filp I002E _err_code I0021 I002E: I00214 4 I00215 I00214: I00215: test I00211 -9 I0021 I00211: 6 8 -20(), -1 -20() -1 0 sbb 0 1f je 1f 1: or jge I00217 -22 I0021 I00217: 4 4 6 -12(), -10() -22() -1 -2,#1 61440 -2, -2 24576 I0021A -12() -10() 0 sbb 0 1f or 1: or I0021A -12(),#65535 -10(),#32767 I0021A: _rdwt_err -2 8192 I0021E _m+10 _who _m+6 -1 -20() 14 _dev_io ,#14 -22(), -22() jl I0021F -22() .cuu -1, -22() cwd -20() adc -1 -20(), -1, -22() I0021F I0021E: ,#1 I00224 -2 24576 je I00224 -1 -20() 32 _get_super _m+6 cwd 12 14 sbb sbb 1f je 1f 1: or jle I00228 -27 I0021 I00228: -20() -1 -12() sbb -10() 1f je 1f 1: or jle I00224 -10() -12() _clear_zone ,#8 I00224: cmpb 39 je I00232 -20() _m+6 -2 _pipe_check ,#10 -22(), -22() jg I00232 -22() I0021 I00232: _m+6 je I0021F -1 -20() 024 .rmi4 -1, mov 2 _m+6 1024 -1 jbe I00235 _m+6 I00236 I00235: 024 -1 I00236: -2, -2 jge I00238 024 -1 -2, I00238: I0023B -12() -10() -20() sbb -1 , , 0 sbb 0 1f je 1f 1: or jg I0023E I0021F I0023E: -2 cwd sbb 1f je 1f 1: or jle I0023B -2, I0023B: -30() -32() _m+10 -2 -1 -1 -20() _rw_chunk ,#18 -22(), -22() je I00244 I0021F I00244: _rdwt_err jge I00247 I0021F I00247: -2 _m+10 _m+10, _m+6 -2 _m+6, -2 -1 -1, -2 cwd -20() adc -1 -20(), -1, -2 I00232 I0021F: ,#1 I0024A -2 8192 je I0024D -2 24576 je I0024D -20() -1 -12() sbb -10() 1f je 1f 1: or jle I0024D -20() -1 4, 6, I0024D: _clock_time 8, 10, 38,#1 I0024B I0024A: cmpb 39 je I0024B -20() -1 4 sbb 6 1f je 1f 1: or jl I0024B 4 6 -20() -1 _find_filp -3, -3 je I0024B -3 6 8 I0024B: -20() -1 6, 8, I00259 cmpb 41 I00259 -1 -20() 024 .rmi4 #0 sbb 0 1f or 1: or I00259 -2 32768 je I00258 -2 16384 I00259 I00258: _rdahed_inode, -20() _rdahedpos, -1 _rdahedpos+2, I00259: -2 32768 I00260 41 I00260: _rdwt_err je I00263 _rdwt_err -22(), I00263: _rdwt_err,#-104 I00266 -1 -22(), I00266: -22() I00269 -1 I0026A I00269: -22() I0026A: I0021: pop _rw_chunk: ,#14 61440 24576 je I0032 I0033 I0032: I0033: -10() -10() je I0035 024 .dvi4 -12(), 14 -1, I0036 I0035: _read_map -12(), 32 -1, I0036: -10() I0038 -12() I0038 1 I003C 65535 _get_block _zero_block I0039 I003C: _new_block I0039 _err_code I0031 I0038: 1,#1 I00312 12(),#1024 I00312 I00313 I00312: I00313: 1,#1 I00316 10() I00316 4 sbb 6 1f je 1f 1: or jl I00316 ,#1 I00316: -12() -1 _get_block I0039: 1,#1 I0031B 12(),#1024 je I0031B -10() I0031B 4 sbb 6 1f je 1f 1: or jl I0031B 10() I0031B _zero_block I0031B: 1 I00322 I00323 I00322: I00323: mul 10() 12() 1 20() 1 _rw_user ,#12 1,#1 I00325 1034,#1 I00325: 12() 10() 1024 I00328 6 I00329 I00328: 7 I00329: _put_block I0031: _read_map _read_map: ,#24 _scale_factor -20(), 024 .dvi4 -1, -1, -20() cwd -1 -1 2: sar 1 rcr 1 1: -1, -12(), -20() cwd -1 -12() 2: sal 1 rcl 1 1: -1 -1 sbb -22(), -1 -12() 7 sbb 0 1f je 1f 1: or jge I0043 14 #2 -1 -12() .mli4 I0046 I0041 I0046: -20() sal cl mov -22() , I0041 I0043: -1 -12() 7 sbb 0 -10(), , -10() 512 sbb 0 1f je 1f 1: or jge I0049 28 I004A I0049: 30 I004C I0041 I004C: -10() 512 sbb 0 -10(), , -20() sal cl , 32 _get_block -10() 512 .dvi4 #2 .mli4 66 _put_block -10() 512 push .rmi4 -10(), , I004A: I004F I0041 I004F: -20() sal cl , 32 _get_block #2 -10() .mli4 66 _put_block I00412 I0041 I00412: -20() sal cl -22() , I0041: _rw_user _rw_user: 1 I0053 _umess+4,#1 _umess+6,#1 12() cwd _umess+10, _umess+10+2, _umess+5,bl _umess+8, _umess+14, _umess+14+2, I0054 I0053: _umess+4,bl _umess+6, _umess+10, _umess+10+2, _umess+5,#1 _umess+8,#1 12() cwd _umess+14, _umess+14+2, I0054: 10() _umess+18, _umess+18+2, _umess _sys_copy _umess+2 _read_ahead _read_ahead: ,#6 _rdahed_inode , _rdahed_inode _rdahedpos+2 _rdahedpos _read_map , I0063 I0063: 32 _get_block 7 _put_block _rdwt_err _rdwt_err: .zerow 2/2 _umess: .zerow 24/2 /* This file contains the code for performing four system calls relating to * status and directories. * * The entry points into this file are * do_chdir: perform the CHDIR system call * do_chroot: perform the CHROOT system call * do_stat: perform the STAT system call * do_fstat: perform the FSTAT system call */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "../h/stat.h" #include "const.h" #include "type.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" /*===========================================================================* * do_chdir * *===========================================================================*/ PUBLIC int do_chdir() { /* Change directory. This function is also called by MM to simulate a chdir * in order to do EXEC, etc. */ register struct fproc *rfp; if (who == MM_PROC_NR) { rfp = &fproc[slot1]; put_inode(fp->fp_workdir); fp->fp_workdir = (cd_flag ? fp->fp_rootdir : rfp->fp_workdir); dup_inode(fp->fp_workdir); fp->fp_effuid = (cd_flag ? SUPER_USER : rfp->fp_effuid); return(OK); } /* Perform the chdir(name) system call. */ return change(&fp->fp_workdir, name, name_length); } /*===========================================================================* * do_chroot * *===========================================================================*/ PUBLIC int do_chroot() { /* Perform the chroot(name) system call. */ register int r; if (!super_user) return(EPERM); /* only su may chroot() */ r = change(&fp->fp_rootdir, name, name_length); return(r); } /*===========================================================================* * change * *===========================================================================*/ PRIVATE int change(iip, name_ptr, len) struct inode **iip; /* pointer to the inode pointer for the dir */ char *name_ptr; /* pointer to the directory name to change to */ int len; /* length of the directory name string */ { /* Do the actual work for chdir() and chroot(). */ struct inode *rip; register int r; extern struct inode *eat_path(); /* Try to open the new directory. */ if (fetch_name(name_ptr, len, M3) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); /* It must be a directory and also be searchable. */ if ( (rip->i_mode & I_TYPE) != I_DIRECTORY) r = ENOTDIR; else r = forbidden(rip, X_BIT, 0); /* check if dir is searchable */ /* If error, return inode. */ if (r != OK) { put_inode(rip); return(r); } /* Everything is OK. Make the change. */ put_inode(*iip); /* release the old directory */ *iip = rip; /* acquire the new one */ return(OK); } /*===========================================================================* * do_stat * *===========================================================================*/ PUBLIC int do_stat() { /* Perform the stat(name, buf) system call. */ register struct inode *rip; register int r; extern struct inode *eat_path(); /* Both stat() and fstat() use the same routine to do the real work. That * routine expects an inode, so acquire it temporarily. */ if (fetch_name(name1, name1_length, M1) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); r = stat_inode(rip, NIL_FILP, name2); /* actually do the work.*/ put_inode(rip); /* release the inode */ return(r); } /*===========================================================================* * do_fstat * *===========================================================================*/ PUBLIC int do_fstat() { /* Perform the fstat(fd, buf) system call. */ register struct filp *rfilp; extern struct filp *get_filp(); /* Is the file descriptor valid? */ if ( (rfilp = get_filp(fd)) == NIL_FILP) return(err_code); return(stat_inode(rfilp->filp_ino, rfilp, buffer)); } /*===========================================================================* * stat_inode * *===========================================================================*/ PRIVATE int stat_inode(rip, fil_ptr, user_addr) register struct inode *rip; /* pointer to inode to stat */ struct filp *fil_ptr; /* filp pointer, supplied by 'fstat' */ char *user_addr; /* user space address where stat buf goes */ { /* Common code for stat and fstat system calls. */ register struct stat *stp; struct stat statbuf; int r; vir_bytes v; /* Fill in the statbuf struct. */ stp = &statbuf; /* set up pointer to the buffer */ stp->st_dev = (int) rip->i_dev; stp->st_ino = rip->i_num; stp->st_mode = rip->i_mode; stp->st_nlink = rip->i_nlinks & BYTE; stp->st_uid = rip->i_uid; stp->st_gid = rip->i_gid & BYTE; stp->st_rdev = rip->i_zone[0]; stp->st_size = rip->i_size; if ( (rip->i_pipe == I_PIPE) && /* IF it is a pipe */ (fil_ptr != NIL_FILP) && /* AND it was fstat */ (fil_ptr->filp_mode == R_BIT)) /* on the reading end, */ stp->st_size -= fil_ptr->filp_pos; /* adjust the visible size. */ stp->st_atime = rip->i_modtime; stp->st_mtime = rip->i_modtime; stp->st_ctime = rip->i_modtime; /* Copy the struct to user space. */ v = (vir_bytes) user_addr; r = rw_user(D, who, v, (vir_bytes) sizeof statbuf, (char *) stp, TO_USER); return(r); } _do_chr _do_chr: _who I0013 6 _m+4 sal cl _fproc , _fp 2 _put_inode _m+6 je I0016 _fp 4 I0017 2 I0017: _fp 2, _fp 2 _dup_inode _m+6 je I0019 I001A I0019: 48 I001A: _fp 48, _fp _m+4 _m+8 2 _change _do_chroot _do_chroot: _super_user I0023 -1 I0021 I0023: _fp _m+4 _m+8 4 _change I0021: _change: 3 _fetch_name je I0033 _err_code I0031 I0033: _user_path _eat_path I0036 _err_code I0031 I0036: 61440 16384 je I0039 ,#-20 I003A I0039: _forbidden I003A: je I003C _put_inode I0031 I003C: _put_inode I0031: _do_stat _do_stat: _m+4 _m+10 _fetch_name je I0043 _err_code I0041 I0043: _user_path _eat_path I0046 _err_code I0041 I0046: _m+12 _stat_inode _put_inode I0041: _do_fstat _do_fstat: _m+4 _get_filp I0053 _err_code I0051 I0053: _m+10 4 _stat_inode I0051: _stat_inode: ,#38 -32() , 32 34 2(), 4(), al,13 6, 2 8(), al,12 10, 14 12, 4 6 14(), 16(), cmpb 39,#1 I0063 je I0063 ,#4 I0063 14 -3, -3 2 6() sbb 8() 2, I0063: 8 10 18(), 20(), 8 10 22(), 24(), 8 10 26(), 28(), -3, 30 -3 _who _rw_user ,#12 -3, -3 /* This file manages the super block table and the related data structures, * namely, the bit maps that keep track of which zones and which inodes are * allocated and which are free. When a new inode or zone is needed, the * appropriate bit map is searched for a free entry. * * The entry points into this file are * load_bit_maps: get the bit maps for the root or a newly mounted device * unload_bit_maps: write the bit maps back to disk after an UMOUNT * alloc_bit: somebody wants to allocate a zone or inode; find one * free_bit: indicate that a zone or inode is available for allocation * get_super: search the 'superblock' table for a device * mounted: tells if file inode is on mounted (or ROOT) file system * scale_factor: get the zone-to-block conversion factor for a device * rw_super: read or write a superblock */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "inode.h" #include "super.h" #define INT_BITS (sizeof(int)<<3) #define BIT_MAP_SHIFT 13 /* (log2 of BLOCK_SIZE) + 3; 13 for 1k blocks */ /*===========================================================================* * load_bit_maps * *===========================================================================*/ PUBLIC int load_bit_maps(dev) dev_nr dev; /* which device? */ { /* Load the bit map for some device into the cache and set up superblock. */ register int i; register struct super_block *sp; block_nr zbase; extern struct buf *get_block(); extern struct super_block *get_super(); sp = get_super(dev); /* get the superblock pointer */ if (bufs_in_use + sp->s_imap_blocks + sp->s_zmap_blocks >= NR_BUFS - 3) return(ERROR); /* insufficient buffers left for bit maps */ if (sp->s_imap_blocks > I_MAP_SLOTS || sp->s_zmap_blocks > ZMAP_SLOTS) panic("too many map blocks", NO_NUM); /* Load the inode map from the disk. */ for (i = 0; i < sp->s_imap_blocks; i++) sp->s_imap[i] = get_block(dev, SUPER_BLOCK + 1 + i, NORMAL); /* Load the zone map from the disk. */ zbase = SUPER_BLOCK + 1 + sp->s_imap_blocks; for (i = 0; i < sp->s_zmap_blocks; i++) sp->s_zmap[i] = get_block(dev, zbase + i, NORMAL); /* inodes 0 and 1, and zone 0 are never allocated. Mark them as busy. */ sp->s_imap[0]->b_int[0] |= 3; /* inodes 0, 1 busy */ sp->s_zmap[0]->b_int[0] |= 1; /* zone 0 busy */ bufs_in_use += sp->s_imap_blocks + sp->s_zmap_blocks; return(OK); } /*===========================================================================* * unload_bit_maps * *===========================================================================*/ PUBLIC unload_bit_maps(dev) dev_nr dev; /* which device is being unmounted? */ { /* Unload the bit maps so a device can be unmounted. */ register int i; register struct super_block *sp; struct super_block *get_super(); sp = get_super(dev); /* get the superblock pointer */ bufs_in_use -= sp->s_imap_blocks + sp->s_zmap_blocks; for (i = 0; i < sp->s_imap_blocks; i++) put_block(sp->s_imap[i], I_MAP_BLOCK); for (i = 0; i < sp->s_zmap_blocks; i++) put_block(sp->s_zmap[i], ZMAP_BLOCK); return(OK); } /*===========================================================================* * alloc_bit * *===========================================================================*/ PUBLIC bit_nr alloc_bit(map_ptr, map_bits, bit_blocks, origin) struct buf *map_ptr[]; /* pointer to array of bit block pointers */ bit_nr map_bits; /* how many bits are there in the bit map? */ unshort bit_blocks; /* how many blocks are there in the bit map? */ bit_nr origin; /* number of bit to start searching at */ { /* Allocate a bit from a bit map and return its bit number. */ register unsigned k; register int *wptr, *wlim; int i, a, b, w, o, block_count; struct buf *bp; /* Figure out where to start the bit search (depends on 'origin'). */ if (origin >= map_bits) origin = 0; /* for robustness */ b = origin >> BIT_MAP_SHIFT; o = origin - (b << BIT_MAP_SHIFT); w = o/INT_BITS; block_count = (w == 0 ? bit_blocks : bit_blocks + 1); /* The outer while loop iterates on the blocks of the map. The inner * while loop iterates on the words of a block. The for loop iterates * on the bits of a word. */ while (block_count--) { /* If need be, loop on all the blocks in the bit map. */ bp = map_ptr[b]; wptr = &bp->b_int[w]; wlim = &bp->b_int[INTS_PER_BLOCK]; while (wptr != wlim) { /* Loop on all the words of one of the bit map blocks. */ if ((k = (unsigned) *wptr) != (unsigned) ~0) { /* This word contains a free bit. Allocate it. */ for (i = 0; i < INT_BITS; i++) if (((k >> i) & 1) == 0) { a = i + (wptr - &bp->b_int[0])*INT_BITS + (b << BIT_MAP_SHIFT); /* If 'a' beyond map check other blks*/ if (a >= map_bits) { wptr = wlim - 1; break; } *wptr |= 1 << i; bp->b_dirt = DIRTY; return( (bit_nr) a); } } wptr++; /* examine next word in this bit map block */ } if (++b == bit_blocks) b = 0; /* we have wrapped around */ w = 0; } return(NO_BIT); /* no bit could be allocated */ } /*===========================================================================* * free_bit * *===========================================================================*/ PUBLIC free_bit(map_ptr, bit_returned) struct buf *map_ptr[]; /* pointer to array of bit block pointers */ bit_nr bit_returned; /* number of bit to insert into the map */ { /* Return a zone or inode by turning on its bitmap bit. */ int b, r, w, bit; struct buf *bp; b = bit_returned >> BIT_MAP_SHIFT; /* 'b' tells which block it is in */ r = bit_returned - (b << BIT_MAP_SHIFT); w = r/INT_BITS; /* 'w' tells which word it is in */ bit = r % INT_BITS; bp = map_ptr[b]; if (bp == NIL_BUF) return; if (((bp->b_int[w] >> bit)& 1)== 0) panic("freeing unused block or inode--check file sys",(int)bit_returned); bp->b_int[w] &= ~(1 << bit); /* turn the bit on */ bp->b_dirt = DIRTY; } /*===========================================================================* * get_super * *===========================================================================*/ PUBLIC struct super_block *get_super(dev) dev_nr dev; /* device number whose super_block is sought */ { /* Search the superblock table for this device. It is supposed to be there. */ register struct super_block *sp; for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) if (sp->s_dev == dev) return(sp); /* Search failed. Something wrong. */ panic("can't find superblock for device (in decimal)", (int) dev); } /*===========================================================================* * mounted * *===========================================================================*/ PUBLIC int mounted(rip) register struct inode *rip; /* pointer to inode */ { /* Report on whether the given inode is on a mounted (or ROOT) file system. */ register struct super_block *sp; register dev_nr dev; dev = (dev_nr) rip->i_zone[0]; if (dev == ROOT_DEV) return(TRUE); /* inode is on root file system */ for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) if (sp->s_dev == dev) return(TRUE); return(FALSE); } /*===========================================================================* * scale_factor * *===========================================================================*/ PUBLIC int scale_factor(ip) struct inode *ip; /* pointer to inode whose superblock needed */ { /* Return the scale factor used for converting blocks to zones. */ register struct super_block *sp; extern struct super_block *get_super(); sp = get_super(ip->i_dev); return(sp->s_log_zone_size); } /*===========================================================================* * rw_super * *===========================================================================*/ PUBLIC rw_super(sp, rw_flag) register struct super_block *sp; /* pointer to a superblock */ int rw_flag; /* READING or WRITING */ { /* Read or write a superblock. */ register struct buf *bp; dev_nr dev; extern struct buf *get_block(); /* Check if this is a read or write, and do it. */ if (rw_flag == READING) { dev = sp->s_dev; /* save device; it will be overwritten by copy*/ bp = get_block(sp->s_dev, (block_nr) SUPER_BLOCK, NORMAL); copy( (char *) sp, bp->b_data, SUPER_SIZE); sp->s_dev = dev; /* restore device number */ } else { /* On a write, it is not necessary to go read superblock from disk. */ bp = get_block(sp->s_dev, (block_nr) SUPER_BLOCK, NO_READ); copy(bp->b_data, (char *) sp, SUPER_SIZE); bp->b_dirt = DIRTY; } sp->s_dirt = CLEAN; put_block(bp, ZUPER_BLOCK); } /* Super block table. The root file system and every mounted file system * has an entry here. The entry holds information about the sizes of the bit * maps and inodes. The s_ninodes field gives the number of inodes available * for files and directories, including the root directory. Inode 0 is * on the disk, but not used. Thus s_ninodes = 4 means that 5 bits will be * used in the bit map, bit 0, which is always 1 and not used, and bits 1-4 * for files and directories. The disk layout is: * * Item # blocks * boot block 1 * super block 1 * inode map s_imap_blocks * zone map s_zmap_blocks * inodes (s_ninodes + 1 + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK * unused whatever is needed to fill out the current zone * data zones (s_nzones - s_firstdatazone) << s_log_zone_size * * A super_block slot is free if s_dev == NO_DEV. */ EXTERN struct super_block { inode_nr s_ninodes; /* # usable inodes on the minor device */ zone_nr s_nzones; /* total device size, including bit maps etc */ unshort s_imap_blocks; /* # of blocks used by inode bit map */ unshort s_zmap_blocks; /* # of blocks used by zone bit map */ zone_nr s_firstdatazone; /* number of first data zone */ short int s_log_zone_size; /* log2 of blocks/zone */ file_pos s_max_size; /* maximum file size on this device */ int s_magic; /* magic number to recognize super-blocks */ /* The following items are only used when the super_block is in memory. */ struct buf *s_imap[I_MAP_SLOTS]; /* pointers to the in-core inode bit map */ struct buf *s_zmap[ZMAP_SLOTS]; /* pointers to the in-core zone bit map */ dev_nr s_dev; /* whose super block is this? */ struct inode *s_isup; /* inode for root dir of mounted file sys */ struct inode *s_imount; /* inode mounted on */ real_time s_time; /* time of last update */ char s_rd_only; /* set to 1 iff file sys mounted read only */ char s_dirt; /* CLEAN or DIRTY */ } super_block[NR_SUPERS]; #define NIL_SUPER (struct super_block *) 0 _load_bit_maps _load_bit_maps: ,#8 _get_super 4 _bufs_in_use 6() 17 jb I0013 -1 4,#4 ja I0015 6,#6 jbe I0016 I0015: 32768 _1 _panic I001C: 4, jbe I0019 2 _get_block sal 1 18, I001C I0019: 4 2 , I00110: 6, jbe I001D _get_block sal 1 26, 0 I001D: 18 , or 3 26 , or 1 _bufs_in_use 6 4() _bufs_in_use, _unload_bit_maps _unload_bit_maps: ,#6 _get_super _bufs_in_use 6 4() _bufs_in_use, I0025: 4, jbe I0022 sal 1 95 18 _put_block I0025 I0022: I0029: 6, jbe I0026 sal 1 96 26 _put_block I0029 I0026: _alloc_bit _alloc_bit: ,#22 10(), jb I0033 10() I0033: 13 10() shr cl -12(), 13 -12() sal cl 10() -1, 16 -1 cwd iv -1, -1 I0036 I0037 I0036: 1 I0037: -1, I0039: -1 -1 je I0038 -12() sal 1 -20(), -1 sal 1 -20() , -20() 1024 , I003C: , je I003B ,#65535 je I003F I00314: , jge I003F shr cl testb al,#1 I00312 -20() cwd iv 4 sal cl 13 -12() sal cl -10(), -10() , ja I00319 -2 , I003F I00319: -22(), -22() sal cl or -20() 1034,#1 -10() I0031 I00312: I00314 I003F: ,#2 I003C I003B: -12() -12() , I0031C -12() I0031C: -1 I0039 I0038: I0031: _free_bit _free_bit: ,#12 13 shr cl 13 sal cl 16 cwd iv , cwd iv , sal 1 -10(), -10() I0043 I0043: sal 1 -10() sar cl testb al,#1 I0046 _2 _panic I0046: sal 1 -10() -12(), sal cl not -10() 1034,#1 _get_super _get_super: ,#_super_block I0055: ,#_super_block+250 jae I0052 38, I0053 I0051 I0053: ,#50 I0055 I0052: _3 _panic I0051: _mounted _mounted: 14 ,#256 I0063 I0061 I0063: ,#_super_block I0068: ,#_super_block+250 jae I0065 38, I0066 I0061 I0066: ,#50 I0068 I0065: I0061: _scale_factor _scale_factor: 32 _get_super 10 _rw_super _rw_super: cmp I0083 38 38 _get_block 50 _copy 38, I0084 I0083: 38 _get_block 50 _copy 1034,#1 I0084: 49 97 _put_block _1: 28532 8303 24941 31086 27936 28769 25120 28524 27491 115 _2: 29286 25957 28265 8295 28277 29557 01 25120 28524 27491 28448 8306 28265 11 11621 25389 25960 27491 26144 27753 8293 31091 115 _3: 24931 10094 8308 26982 10 29472 28789 29285 27746 25455 8299 28518 8306 25956 26998 25955 10272 28265 25632 25445 28009 27745 41 /* This file contains the table used to map system call numbers onto the * routines that perform them. */ #include "../h/const.h" #include "../h/type.h" #include "../h/stat.h" #include "const.h" #include "type.h" #include "dev.h" #undef EXTERN #define EXTERN #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "super.h" extern do_access(), do_chdir(), do_chmod(), do_chown(), do_chroot(); extern do_close(), do_creat(), do_dup(), do_exit(), do_fork(), do_fstat(); extern do_ioctl(), do_link(), do_lseek(), do_mknod(), do_mount(), do_open(); extern do_pipe(), do_read(), do_revive(), do_set(), do_stat(), do_stime(); extern do_sync(), do_time(), do_tims(), do_umask(), do_umount(), do_unlink(); extern do_unpause(), do_utime(), do_write(), no_call(), no_sys(); extern char fstack[]; char *stackpt = &fstack[FS_STACK_BYTES]; /* initial stack pointer */ int (*call_vector[NCALLS])() = { no_sys, /* 0 = unused */ do_exit, /* 1 = exit */ do_fork, /* 2 = fork */ do_read, /* 3 = read */ do_write, /* 4 = write */ do_open, /* 5 = open */ do_close, /* 6 = close */ no_sys, /* 7 = wait */ do_creat, /* 8 = creat */ do_link, /* 9 = link */ do_unlink, /* 10 = unlink */ no_sys, /* 11 = exec */ do_chdir, /* 12 = chdir */ do_time, /* 13 = time */ do_mknod, /* 14 = mknod */ do_chmod, /* 15 = chmod */ do_chown, /* 16 = chown */ no_sys, /* 17 = break */ do_stat, /* 18 = stat */ do_lseek, /* 19 = lseek */ no_sys, /* 20 = getpid */ do_mount, /* 21 = mount */ do_umount, /* 22 = umount */ do_set, /* 23 = setuid */ no_sys, /* 24 = getuid */ do_stime, /* 25 = stime */ no_sys, /* 26 = (ptrace)*/ no_sys, /* 27 = alarm */ do_fstat, /* 28 = fstat */ no_sys, /* 29 = pause */ do_utime, /* 30 = utime */ no_sys, /* 31 = (stty) */ no_sys, /* 32 = (gtty) */ do_access, /* 33 = access */ no_sys, /* 34 = (nice) */ no_sys, /* 35 = (ftime) */ do_sync, /* 36 = sync */ no_sys, /* 37 = kill */ no_sys, /* 38 = unused */ no_sys, /* 39 = unused */ no_sys, /* 40 = unused */ do_dup, /* 41 = dup */ do_pipe, /* 42 = pipe */ do_tims, /* 43 = times */ no_sys, /* 44 = (prof) */ no_sys, /* 45 = unused */ do_set, /* 46 = setgid */ no_sys, /* 47 = getgid */ no_sys, /* 48 = sig */ no_sys, /* 49 = unused */ no_sys, /* 50 = unused */ no_sys, /* 51 = (acct) */ no_sys, /* 52 = (phys) */ no_sys, /* 53 = (lock) */ do_ioctl, /* 54 = ioctl */ no_sys, /* 55 = unused */ no_sys, /* 56 = (mpx) */ no_sys, /* 57 = unused */ no_sys, /* 58 = unused */ no_sys, /* 59 = exece */ do_umask, /* 60 = umask */ do_chroot, /* 61 = chroot */ no_sys, /* 62 = unused */ no_sys, /* 63 = unused */ no_sys, /* 64 = KSIG: signals originating in the kernel */ do_unpause, /* 65 = UNPAUSE */ no_sys, /* 66 = BRK2 (used to tell MM size of FS,INIT) */ do_revive, /* 67 = REVIVE */ no_sys /* 68 = TASK_REPLY */ }; extern rw_dev(), rw_dev2(); /* The order of the entries here determines the mapping between major device * numbers and tasks. The first entry (major device 0) is not used. The * next entry is major device 1, etc. Character and block devices can be * intermixed at random. If this ordering is changed, BOOT_DEV and ROOT_DEV * must be changed to correspond to the new values. */ struct dmap dmap[] = { /* Open Read/Write Close Task # Device File ---- ---------- ----- ------- ------ ---- */ 0, 0, 0, 0, /* 0 = not used */ no_call, rw_dev, no_call, MEM, /* 1 = /dev/mem */ no_call, rw_dev, no_call, FLOPPY, /* 2 = /dev/fd0 */ no_call, rw_dev, no_call, WINCHESTER, /* 3 = /dev/hd0 */ no_call, rw_dev, no_call, TTY, /* 4 = /dev/tty0 */ no_call, rw_dev2, no_call, TTY, /* 5 = /dev/tty */ no_call, rw_dev, no_call, PRINTER /* 6 = /dev/lp */ }; int max_major = sizeof(dmap)/sizeof(struct dmap); _stackpt _stackpt: _fstack+512 _call_vector _call_vector: _no_sys _do_exit _do_fork _do_read _do_write _do_open _do_close _no_sys _do_creat _do_link _do_unlink _no_sys _do_chr _do_time _do_mknod _do_chmod _do_chown _no_sys _do_stat _do_lseek _no_sys _do_mount _do_umount _do_set _no_sys _do_stime _no_sys _no_sys _do_fstat _no_sys _do_utime _no_sys _no_sys _do_access _no_sys _no_sys _do_sync _no_sys _no_sys _no_sys _no_sys _do_dup _do_pipe _do_tims _no_sys _no_sys _do_set _no_sys _no_sys _no_sys _no_sys _no_sys _no_sys _no_sys _do_ioctl _no_sys _no_sys _no_sys _no_sys _no_sys _do_umask _do_chroot _no_sys _no_sys _no_sys _do_unpause _no_sys _do_revive _no_sys _dmap _dmap: _no_call _rw_dev _no_call -4 _no_call _rw_dev _no_call -5 _no_call _rw_dev _no_call -6 _no_call _rw_dev _no_call -7 _no_call _rw_dev2 _no_call -7 _no_call _rw_dev _no_call _m_major -8 _m_major: _super_block 7 _super_block: .zerow 250/2 _inode _inode: .zerow 1344/2 _fstack _fstack: .zerow 512/2 _err_code _err_code: .zerow 2/2 _user_path _user_path: .zerow 128/2 _fs_call _fs_call: .zerow 2/2 _who _who: .zerow 2/2 _m1 _m1: .zerow 24/2 _m _m: .zerow 24/2 _rdahed_inode _rdahed_inode: .zerow 2/2 _rdahedpos _rdahedpos: .zerow 4/2 _reviving _reviving: .zerow 2/2 _su_count _su_count: .zerow 2/2 _dont_reply _dont_reply: .zerow 2/2 _super_user _super_user: .zerow 2/2 _fp _fp: .zerow 2/2 _fproc _fproc: .zerow 1024/2 _filp _filp: .zerow 640/2 _bufs_in_use _bufs_in_use: .zerow 2/2 _rear _rear: .zerow 2/2 _front _front: .zerow 2/2 _buf_hash _buf_hash: .zerow 64/2 _buf _buf: .zerow 20720/2 /* This file takes care of those system calls that deal with time. * * The entry points into this file are * do_utime: perform the UTIME system call * do_time: perform the TIME system call * do_stime: perform the STIME system call * do_tims: perform the TIMES system call */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" PRIVATE message clock_mess; /*===========================================================================* * do_utime * *===========================================================================*/ PUBLIC int do_utime() { /* Perform the utime(name, timep) system call. */ register struct inode *rip; register int r; extern struct inode *eat_path(); /* Temporarily open the file. */ if (fetch_name(utime_file, utime_length, M1) != OK) return(err_code); if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); /* Only the owner of a file or the super_user can change its time. */ r = OK; if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM; if (r == OK) { rip->i_modtime = update_time; rip->i_dirt = DIRTY; } put_inode(rip); return(r); } /*===========================================================================* * do_time * *===========================================================================*/ PUBLIC int do_time() { /* Perform the time(tp) system call. */ extern real_time clock_time(); reply_l1 = clock_time(); /* return time in seconds */ return(OK); } /*===========================================================================* * do_stime * *===========================================================================*/ PUBLIC int do_stime() { /* Perform the stime(tp) system call. */ register int k; if (!super_user) return(EPERM); clock_mess.m_type = SET_TIME; clock_mess.NEW_TIME = (long) tp; if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("do_stime error", k); return (OK); } /*===========================================================================* * do_tims * *===========================================================================*/ PUBLIC int do_tims() { /* Perform the times(buffer) system call. */ real_time t[4]; sys_times(who, t); reply_t1 = t[0]; reply_t2 = t[1]; reply_t3 = t[2]; reply_t4 = t[3]; return(OK); } _do_utime _do_utime: _m+4 _m+18 _fetch_name je I0013 _err_code _user_path _eat_path I0016 _err_code _fp 48() 2, je I0019 _super_user I0019 ,#-1 I0019: I001D _m+14 _m+14+2 8, 10, 38,#1 I001D: _put_inode _do_time _do_time: _clock_time _m1+10, _m1+10+2, _do_stime _do_stime: _super_user I0033 -1 I0031 I0033: _clock_mess+2,#4 _m+10 _m+10+2 _clock_mess+10, _clock_mess+10+2 _clock_mess -3 _sendrec je I0036 _1 _panic I0036: I0031: _do_tims _do_tims: , -1 _who _sys_times -1 _m1+4, -1 _m1+4+2, -12() _m1+8, -10() _m1+8+2, _m1+12, _m1+12+2, _m1+16, _m1+16+2, _clock_mess: .zerow 24/2 _1: 28516 29535 26996 25965 25888 29298 29295 /* Type definitions local to the File System. */ typedef struct { /* directory entry */ inode_nr d_inum; /* inode number */ char d_name[NAME_SIZE]; /* character string */ } dir_struct; /* Declaration of the disk inode used in rw_inode(). */ typedef struct { /* disk inode. Memory inode is in "inotab.h" */ mask_bits i_mode; /* file type, protection, etc. */ uid i_uid; /* user id of the file's owner */ file_pos i_size; /* current file size in bytes */ real_time i_modtime; /* when was file data last changed */ gid i_gid; /* group number */ links i_nlinks; /* how many links to this file */ zone_nr i_zone[NR_ZONE_NUMS]; /* block nums for direct, ind, and dbl ind */ } d_inode; /* This file contains a few general purpose utility routines. * * The entry points into this file are * clock_time: ask the clock task for the real time * cmp_string: compare two strings (e.g., while searching directory) * copy: copy a string * fetch_name: go get a path name from user space * no_sys: reject a system call that FS does not handle * panic: something awful has occurred; MINIX cannot continue */ #include "../h/const.h" #include "../h/type.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "param.h" #include "super.h" PRIVATE int panicking; /* inhibits recursive panics during sync */ PRIVATE message clock_mess; /*===========================================================================* * clock_time * *===========================================================================*/ PUBLIC real_time clock_time() { /* This routine returns the time in seconds since 1.1.1970. */ register int k; register struct super_block *sp; extern struct super_block *get_super(); clock_mess.m_type = GET_TIME; if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("clock_time err", k); /* Since we now have the time, update the super block. It is almost free. */ sp = get_super(ROOT_DEV); sp->s_time = clock_mess.NEW_TIME; /* update super block time */ if (sp->s_rd_only == FALSE) sp->s_dirt = DIRTY; return (real_time) clock_mess.NEW_TIME; } /*===========================================================================* * cmp_string * *===========================================================================*/ PUBLIC int cmp_string(rsp1, rsp2, n) register char *rsp1, *rsp2; /* pointers to the two strings */ register int n; /* string length */ { /* Compare two strings of length 'n'. If they are the same, return 1. * If they differ, return 0. */ do { if (*rsp1++ != *rsp2++) return(0); } while (--n); /* The strings are identical. */ return(1); } /*===========================================================================* * copy * *===========================================================================*/ PUBLIC copy(dest, source, bytes) char *dest; /* destination pointer */ char *source; /* source pointer */ int bytes; /* how much data to move */ { /* Copy a byte string of length 'bytes' from 'source' to 'dest'. * If all three parameters are exactly divisible by the integer size, copy them * an integer at a time. Otherwise copy character-by-character. */ if (bytes <= 0) return; /* makes test-at-the-end possible */ if (bytes % sizeof(int) == 0 && (int) dest % sizeof(int) == 0 && (int) source % sizeof(int) == 0) { /* Copy the string an integer at a time. */ register int n = bytes/sizeof(int); register int *dpi = (int *) dest; register int *spi = (int *) source; do { *dpi++ = *spi++; } while (--n); } else { /* Copy the string character-by-character. */ register int n = bytes; register char *dpc = (char *) dest; register char *spc = (char *) source; do { *dpc++ = *spc++; } while (--n); } } /*===========================================================================* * fetch_name * *===========================================================================*/ PUBLIC int fetch_name(path, len, flag) char *path; /* pointer to the path in user space */ int len; /* path length, including 0 byte */ int flag; /* M3 means path may be in message */ { /* Go get path and put it in 'user_path'. * If 'flag' = M3 and 'len' <= M3_STRING, the path is present in 'message'. * If it is not, go copy it from user space. */ register char *rpu, *rpm; vir_bytes vpath; if (flag == M3 && len <= M3_STRING) { /* Just copy the path from the message to 'user_path'. */ rpu = &user_path[0]; rpm = pathname; /* contained in input message */ do { *rpu++ = *rpm++; } while (--len); return(OK); } /* String is not contained in the message. Go get it from user space. */ if (len > MAX_PATH) { err_code = E_LONG_STRING; return(ERROR); } vpath = (vir_bytes) path; err_code = rw_user(D, who, vpath, (vir_bytes) len, user_path, FROM_USER); return(err_code); } /*===========================================================================* * no_sys * *===========================================================================*/ PUBLIC int no_sys() { /* Somebody has used an illegal system call number */ return(EINVAL); } /*===========================================================================* * panic * *===========================================================================*/ PUBLIC panic(format, num) char *format; /* format string */ int num; /* number to go with format string */ { /* Something awful has happened. Panics are caused when an internal * inconsistency is detected, e.g., a programming error or illegal value of a * defined constant. */ if (panicking) return; /* do not panic during a sync */ panicking = TRUE; /* prevent another panic during the sync */ printf("File system panic: %s ", format); if (num != NO_NUM) printf("%d",num); printf("\n"); do_sync(); /* flush everything to the disk */ sys_abort(); } _clock_time _clock_time: _clock_mess+2,#3 _clock_mess -3 _sendrec je I0013 _1 _panic 56 _get_super _clock_mess+10 _clock_mess+10+2 44, 46, cmpb 48 I0016 49,#1 _clock_mess+10 _clock_mess+10+2 _cmp_string _cmp_string: I0024: ,#1 je I0023 I0021 I0023: I0024 I0021: _copy _copy: ,#6 jg I0033 I0033: cwd iv or I0036 cwd iv or I0036 cwd iv or I0036 cwd iv , I003C: ,#2 ,#2 I003C I0037 I0036: , I003F: ,#1 (),al ,#1 I003F I0037: _fetch_name _fetch_name: ,#6 ,#3 I0043 ,#14 jg I0043 ,#_user_path ,#_m+10 I0048: ,#1 (),al ,#1 I0048 I0041 I0043: ,#128 jle I004A _err_code,#-103 -1 I0041 I004A: , #1 #_user_path _who _rw_user ,#12 _err_code, _err_code I0041: _no_sys _no_sys: -22 _panic _panic: _panicking je I0063 I0063: _panicking,#1 _2 _printk 32768 je I0066 _3 _printk I0066: _4 _printk _do_sync _sys_abort _clock_mess: .zerow 24/2 _panicking: .zerow 2/2 _1: 27747 25455 24427 26996 25965 25888 29298 _2: 26950 25964 29472 29561 25972 8301 24944 26990 14947 9504 8307 _3: 25637 _4: 10 /* This file is the counterpart of "read.c". It contains the code for writing * insofar as this is not contained in read_write(). * * The entry points into this file are * do_write: call read_write to perform the WRITE system call * write_map: add a new zone to an inode * clear_zone: erase a zone in the middle of a file * new_block: acquire a new block */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "buf.h" #include "file.h" #include "fproc.h" #include "glo.h" #include "inode.h" #include "super.h" /*===========================================================================* * do_write * *===========================================================================*/ PUBLIC int do_write() { /* Perform the write(fd, buffer, nbytes) system call. */ return(read_write(WRITING)); } /*===========================================================================* * write_map * *===========================================================================*/ PRIVATE int write_map(rip, position, new_zone) register struct inode *rip; /* pointer to inode to be changed */ file_pos position; /* file address to be mapped */ zone_nr new_zone; /* zone # to be inserted */ { /* Write a new zone into an inode. */ int scale; zone_nr z, *zp; register block_nr b; long excess, zone; int index; struct buf *bp; int new_ind, new_dbl; extern zone_nr alloc_zone(); extern struct buf *get_block(); extern real_time clock_time(); rip->i_dirt = DIRTY; /* inode will be changed */ bp = NIL_BUF; scale = scale_factor(rip); /* for zone-block conversion */ zone = (position/BLOCK_SIZE) >> scale; /* relative zone # to insert */ /* Is 'position' to be found in the inode itself? */ if (zone < NR_DZONE_NUM) { rip->i_zone[zone] = new_zone; rip->i_modtime = clock_time(); return(OK); } /* It is not in the inode, so it must be single or double indirect. */ excess = zone - NR_DZONE_NUM; /* first NR_DZONE_NUM don't count */ new_ind = FALSE; new_dbl = FALSE; if (excess < NR_INDIRECTS) { /* 'position' can be located via the single indirect block. */ zp = &rip->i_zone[NR_DZONE_NUM]; } else { /* 'position' can be located via the double indirect block. */ if ( (z = rip->i_zone[NR_DZONE_NUM+1]) == NO_ZONE) { /* Create the double indirect block. */ if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE) return(err_code); rip->i_zone[NR_DZONE_NUM+1] = z; new_dbl = TRUE; /* set flag for later */ } /* Either way, 'z' is zone number for double indirect block. */ excess -= NR_INDIRECTS; /* single indirect doesn't count */ index = excess / NR_INDIRECTS; excess = excess % NR_INDIRECTS; if (index >= NR_INDIRECTS) return(EFBIG); b = (block_nr) z << scale; bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ : NORMAL)); if (new_dbl) zero_block(bp); zp= &bp->b_ind[index]; } /* 'zp' now points to place where indirect zone # goes; 'excess' is index. */ if (*zp == NO_ZONE) { /* Create indirect block. */ *zp = alloc_zone(rip->i_dev, rip->i_zone[0]); new_ind = TRUE; if (bp != NIL_BUF) bp->b_dirt = DIRTY; /* if double ind, it is dirty */ if (*zp == NO_ZONE) { put_block(bp, INDIRECT_BLOCK); /* release dbl indirect blk */ return(err_code); /* couldn't create single ind */ } } put_block(bp, INDIRECT_BLOCK); /* release double indirect blk */ /* 'zp' now points to indirect block's zone number. */ b = (block_nr) *zp << scale; bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) ); if (new_ind) zero_block(bp); bp->b_ind[excess] = new_zone; rip->i_modtime = clock_time(); bp->b_dirt = DIRTY; put_block(bp, INDIRECT_BLOCK); return(OK); } /*===========================================================================* * clear_zone * *===========================================================================*/ PUBLIC clear_zone(rip, pos, flag) register struct inode *rip; /* inode to clear */ file_pos pos; /* points to block to clear */ int flag; /* 0 if called by read_write, 1 by new_block */ { /* Zero a zone, possibly starting in the middle. The parameter 'pos' gives * a byte in the first block to be zeroed. Clearzone() is called from * read_write and new_block(). */ register struct buf *bp; register block_nr b, blo, bhi; register file_pos next; register int scale; register zone_type zone_size; extern struct buf *get_block(); extern block_nr read_map(); /* If the block size and zone size are the same, clear_zone() not needed. */ if ( (scale = scale_factor(rip)) == 0) return; zone_size = (zone_type) BLOCK_SIZE << scale; if (flag == 1) pos = (pos/zone_size) * zone_size; next = pos + BLOCK_SIZE - 1; /* If 'pos' is in the last block of a zone, do not clear the zone. */ if (next/zone_size != pos/zone_size) return; if ( (blo = read_map(rip, next)) == NO_BLOCK) return; bhi = ( ((blo>>scale)+1) << scale) - 1; /* Clear all the blocks between 'blo' and 'bhi'. */ for (b = blo; b <= bhi; b++) { bp = get_block(rip->i_dev, b, NO_READ); zero_block(bp); put_block(bp, FULL_DATA_BLOCK); } } /*===========================================================================* * new_block * *===========================================================================*/ PUBLIC struct buf *new_block(rip, position) register struct inode *rip; /* pointer to inode */ file_pos position; /* file pointer */ { /* Acquire a new block and return a pointer to it. Doing so may require * allocating a complete zone, and then returning the initial block. * On the other hand, the current zone may still have some unused blocks. */ register struct buf *bp; block_nr b, base_block; zone_nr z; zone_type zone_size; int scale, r; struct super_block *sp; extern struct buf *get_block(); extern struct super_block *get_super(); extern block_nr read_map(); extern zone_nr alloc_zone(); /* Is another block available in the current zone? */ if ( (b = read_map(rip, position)) == NO_BLOCK) { /* Choose first zone if need be. */ if (rip->i_size == 0) { sp = get_super(rip->i_dev); z = sp->s_firstdatazone; } else { z = rip->i_zone[0]; } if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF); if ( (r = write_map(rip, position, z)) != OK) { free_zone(rip->i_dev, z); err_code = r; return(NIL_BUF); } /* If we are not writing at EOF, clear the zone, just to be safe. */ if ( position != rip->i_size) clear_zone(rip, position, 1); scale = scale_factor(rip); base_block = (block_nr) z << scale; zone_size = (zone_type) BLOCK_SIZE << scale; b = base_block + (block_nr)((position % zone_size)/BLOCK_SIZE); } bp = get_block(rip->i_dev, b, NO_READ); zero_block(bp); return(bp); } /*===========================================================================* * zero_block * *===========================================================================*/ PUBLIC zero_block(bp) register struct buf *bp; /* pointer to buffer to zero */ { /* Zero a block. */ register int n; register int *zip; n = INTS_PER_BLOCK; /* number of integers in a block */ zip = bp->b_int; /* where to start clearing */ do { *zip++ = 0;} while (--n); bp->b_dirt = DIRTY; } _do_write _do_write: _read_write _write_map: ,#26 38,#1 -20() _scale_factor 024 .dvi4 cwd 2: sar 1 rcr 1 1: -1, -1, -1 -1 7 sbb 0 1f je 1f 1: or jge I0023 10() 14 #2 -1 -1 .mli4 _clock_time 8, 10, I0021 I0023: -1 -1 7 sbb 0 -12(), -10(), -22() -2 -12() -10() 512 sbb 0 1f je 1f 1: or jge I0026 28 mov , I0027 I0026: 30 I0029 14 32() _alloc_zone I002C _err_code I0021 I002C: 30, -2,#1 I0029: -12() -10() 512 sbb 0 -12(), -10(), -10() -12() 512 .dvi4 -1, -10() -12() 512 .rmi4 -12(), -10(), -1,#512 jl I002F -27 I0021 I002F: sal cl , -2 je I00212 I00213 I00212: I00213: 32 _get_block -20(), -2 je I00215 -20() _zero_block I00215: -18() sal 1 -20() , I0027: I00218 14 32() _alloc_zone -22(),#1 -20() je I0021B -20() 1034,#1 I0021B: I00218 66 -20() _put_block _err_code I0021 I00218: 66 -20() _put_block sal cl , -22() je I00221 I00222 I00221: I00222: 32 _get_block -20(), -22() je I00224 -20() _zero_block I00224: #2 -12() -10() 10() -20() .mli4 _clock_time 8, 10, -20() 1034,#1 66 -20() _put_block I0021: _clear_zone _clear_zone: ,#18 _scale_factor -1, -1 I0033 I0033: -1 cwd 024 2: sal 1 rcl 1 1: -1, -1, 10(),#1 I0036 -1 -1 .dvi4 -1 -1 .mli4 , , I0036: 1023 adc 0 -12(), -10(), -10() -12() -1 -1 .dvi4 -1 -1 .dvi4 sbb 1f or 1: or je I0039 I0039: -10() -12() _read_map , I003C I003C: -1 shr cl 1 -1 sal cl 1 , I00311: , ja I003E 32 _get_block _zero_block 6 _put_block 1 I00311 I003E: _new_block _new_block: ,#18 _read_map I0043 4 6 0 sbb 0 1f or 1: or I0046 32 _get_super -1, -1 8 , I0047 I0046: 14 , I0047: 32 _alloc_zone , I0049 I0041 I0049: _write_map ,#8 -1, -1 je I004C 32 _free_zone -1 _err_code, I0041 I004C: 4 sbb 6 1f or 1: or je I004F _clear_zone ,#8 I004F: _scale_factor -1, -1 sal cl , -1 cwd 024 2: sal 1 rcl 1 1: -12(), -10(), -10() -12() .rmi4 024 ax .dvi4 I0043: 32 _get_block _zero_block I0041: _zero_block _zero_block: ,#512 I0054: ,#2 I0054 1034,#1 7...Jcallnr.hKcom.hLconst.hMerror.hNsgtty.hOsignal.hPstat.hQtype.h8...9blocksize.h:callnr.h;com.h<const.h=ctype.h>errno.h?error.h@grp.hAlib.hBpwd.hCregexp.hDsetjmp.hEsgtty.hFsignal.hGstat.hHstdio.hItype.h#define BLOCK_SIZE 1024 /* file system data block size */ #define NCALLS 69 /* number of system calls allowed */ #define EXIT 1 #define FORK 2 #define READ 3 #define WRITE 4 #define OPEN 5 #define CLOSE 6 #define WAIT 7 #define CREAT 8 #define LINK 9 #define UNLINK 10 #define CHDIR 12 #define TIME 13 #define MKNOD 14 #define CHMOD 15 #define CHOWN 16 #define BRK 17 #define STAT 18 #define LSEEK 19 #define GETPID 20 #define MOUNT 21 #define UMOUNT 22 #define SETUID 23 #define GETUID 24 #define STIME 25 #define ALARM 27 #define FSTAT 28 #define PAUSE 29 #define UTIME 30 #define ACCESS 33 #define SYNC 36 #define KILL 37 #define DUP 41 #define PIPE 42 #define TIMES 43 #define SETGID 46 #define GETGID 47 #define SIGNAL 48 #define IOCTL 54 #define EXEC 59 #define UMASK 60 #define CHROOT 61 /* The following are not system calls, but are processed like them. */ #define KSIG 64 /* kernel detected a signal */ #define UNPAUSE 65 /* to MM or FS: check for EINTR */ #define BRK2 66 /* to MM: used to say how big FS & INIT are */ #define REVIVE 67 /* to FS: revive a sleeping process */ #define TASK_REPLY 68 /* to FS: reply code from tty task */ /* System calls. */ #define SEND 1 /* function code for sending messages */ #define RECEIVE 2 /* function code for receiving messages */ #define BOTH 3 /* function code for SEND + RECEIVE */ #define ANY (NR_PROCS+100) /* receive(ANY, buf) accepts from any source */ /* Task numbers, function codes and reply codes. */ #define HARDWARE -1 /* used as source on interrupt generated msgs */ #define SYSTASK -2 /* internal functions */ # define SYS_XIT 1 /* fcn code for sys_xit(parent, proc) */ # define SYS_GETSP 2 /* fcn code for sys_sp(proc, &new_sp) */ # define SYS_SIG 3 /* fcn code for sys_sig(proc, sig) */ # define SYS_FORK 4 /* fcn code for sys_fork(parent, child) */ # define SYS_NEWMAP 5 /* fcn code for sys_newmap(procno, map_ptr) */ # define SYS_COPY 6 /* fcn code for sys_copy(ptr) */ # define SYS_EXEC 7 /* fcn code for sys_exec(procno, new_sp) */ # define SYS_TIMES 8 /* fcn code for sys_times(procno, bufptr) */ # define SYS_ABORT 9 /* fcn code for sys_abort() */ #define CLOCK -3 /* clock class */ # define SET_ALARM 1 /* fcn code to CLOCK, set up alarm */ # define CLOCK_TICK 2 /* fcn code for clock tick */ # define GET_TIME 3 /* fcn code to CLOCK, get real time */ # define SET_TIME 4 /* fcn code to CLOCK, set real time */ # define REAL_TIME 1 /* reply from CLOCK: here is real time */ #define MEM -4 /* /dev/ram, /dev/(k)mem and /dev/null class */ # define RAM_DEV 0 /* minor device for /dev/ram */ # define MEM_DEV 1 /* minor device for /dev/mem */ # define KMEM_DEV 2 /* minor device for /dev/kmem */ # define NULL_DEV 3 /* minor device for /dev/null */ #define FLOPPY -5 /* floppy disk class */ #define WINCHESTER -6 /* winchester (hard) disk class */ # define DISKINT 1 /* fcn code for disk interupt */ # define DISK_READ 3 /* fcn code to DISK (must equal TTY_READ) */ # define DISK_WRITE 4 /* fcn code to DISK (must equal TTY_WRITE) */ # define DISK_IOCTL 5 /* fcn code for setting up RAM disk */ #define TTY -7 /* terminal I/O class */ #define PRINTER -8 /* printer I/O class */ # define TTY_CHAR_INT 1 /* fcn code for tty input interrupt */ # define TTY_O_DONE 2 /* fcn code for tty output done */ # define TTY_READ 3 /* fcn code for reading from tty */ # define TTY_WRITE 4 /* fcn code for writing to tty */ # define TTY_IOCTL 5 /* fcn code for ioctl */ # define SUSPEND -998 /* used in interrupts when tty has no data */ /* Names of message fields for messages to CLOCK task. */ #define DELTA_TICKS m6_l1 /* alarm interval in clock ticks */ #define FUNC_TO_CALL m6_f1 /* pointer to function to call */ #define NEW_TIME m6_l1 /* value to set clock to (SET_TIME) */ #define CLOCK_PROC_NR m6_i1 /* which proc (or task) wants the alarm? */ #define SECONDS_LEFT m6_l1 /* how many seconds were remaining */ /* Names of message fields used for messages to block and character tasks. */ #define DEVICE m2_i1 /* major-minor device */ #define PROC_NR m2_i2 /* which (proc) wants I/O? */ #define COUNT m2_i3 /* how many bytes to transfer */ #define POSITION m2_l1 /* file offset */ #define ADDRESS m2_p1 /* core buffer address */ /* Names of message fields for messages to TTY task. */ #define TTY_LINE m2_i1 /* message parameter: terminal line */ #define TTY_REQUEST m2_i3 /* message parameter: ioctl request code */ #define TTY_SPEK m2_l1 /* message parameter: ioctl speed, erasing */ #define TTY_FLAGS m2_l2 /* message parameter: ioctl tty mode */ /* Names of messages fields used in reply messages from tasks. */ #define REP_PROC_NR m2_i1 /* # of proc on whose behalf I/O was done */ #define REP_STATUS m2_i2 /* bytes transferred or error number */ /* Names of fields for copy message to SYSTASK. */ #define SRC_SPACE m5_c1 /* T or D space (stack is also D) */ #define SRC_PROC_NR m5_i1 /* process to copy from */ #define SRC_BUFFER m5_l1 /* virtual address where data come from */ #define DST_SPACE m5_c2 /* T or D space (stack is also D) */ #define DST_PROC_NR m5_i2 /* process to copy to */ #define DST_BUFFER m5_l2 /* virtual address where data go to */ #define COPY_BYTES m5_l3 /* number of bytes to copy */ /* Field names for accounting, SYSTASK and miscellaneous. */ #define USER_TIME m4_l1 /* user time consumed by process */ #define SYSTEM_TIME m4_l2 /* system time consumed by process */ #define CHILD_UTIME m4_l3 /* user time consumed by process' children */ #define CHILD_STIME m4_l4 /* system time consumed by proces children */ #define PROC1 m1_i1 /* indicates a process */ #define PROC2 m1_i2 /* indicates a process */ #define PID m1_i3 /* process id passed from MM to kernel */ #define STACK_PTR m1_p1 /* used for stack ptr in sys_exec, sys_getsp */ #define PR m6_i1 /* process number for sys_sig */ #define SIGNUM m6_i2 /* signal number for sys_sig */ #define FUNC m6_f1 /* function pointer for sys_sig */ #define MEM_PTR m1_p1 /* tells where memory map is for sys_newmap */ #define CANCEL 0 /* general request to force a task to cancel */ #define SIG_MAP m1_i2 /* used by kernel for passing signal bit map */ /* Copyright (C) 1987 by Prentice-Hall, Inc. Permission is hereby granted to * private individuals and educational institutions to modify and * redistribute the binary and source programs of this system to other * private individuals and educational institutions for educational and * research purposes. For corporate or commercial use, permission from * Prentice-Hall is required. In general, such permission will be granted, * subject to a few conditions. */ #define EXTERN extern /* used in *.h files */ #define PRIVATE static /* PRIVATE x limits the scope of x */ #define PUBLIC /* PUBLIC is the opposite of PRIVATE */ #define FORWARD /* some compilers require this to be 'static' */ #define TRUE 1 /* used for turning integers into Booleans */ #define FALSE 0 /* used for turning integers into Booleans */ #define HZ 60 /* clock freq (software settable on IBM-PC) */ #define BLOCK_SIZE 1024 /* # bytes in a disk block */ #define SUPER_USER (uid) 0 /* uid of superuser */ #define MAJOR 8 /* major device = (dev>>MAJOR) & 0377 */ #define MINOR 0 /* minor device = (dev>>MINOR) & 0377 */ #define NR_TASKS 8 /* number of tasks in the transfer vector */ #define NR_PROCS 16 /* number of slots in proc table */ #define NR_SEGS 3 /* # segments per process */ #define T 0 /* proc[i].mem_map[T] is for text */ #define D 1 /* proc[i].mem_map[D] is for data */ #define S 2 /* proc[i].mem_map[S] is for stack */ #define MAX_P_LONG 2147483647 /* maximum positive long, i.e. 2**31 - 1 */ /* Memory is allocated in clicks. */ #define CLICK_SIZE 0020 /* unit in which memory is allocated */ #define CLICK_SHIFT 4 /* log2 of CLICK_SIZE */ /* Process numbers of some important processes */ #define MM_PROC_NR 0 /* process number of memory manager */ #define FS_PROC_NR 1 /* process number of file system */ #define INIT_PROC_NR 2 /* init -- the process that goes multiuser */ #define LOW_USER 2 /* first user not part of operating system */ /* Miscellaneous */ #define BYTE 0377 /* mask for 8 bits */ #define TO_USER 0 /* flag telling to copy from fs to user */ #define FROM_USER 1 /* flag telling to copy from user to fs */ #define READING 0 /* copy data to user */ #define WRITING 1 /* copy data from user */ #define ABS -999 /* this process means absolute memory */ #define WORD_SIZE 2 /* number of bytes per word */ #define NIL_PTR (char *) 0 /* generally useful expression */ #define NO_NUM 0x8000 /* used as numerical argument to panic() */ #define MAX_PATH 128 /* max length of path names */ #define SIG_PUSH_BYTES 8 /* how many bytes pushed by signal */ #define MAX_ISTACK_BYTES 1024 /* maximum initial stack size for EXEC */ /* Device numbers of root (RAM) and boot (fd0) devices. */ #define ROOT_DEV (dev_nr) 256 /* major-minor device number of root dev */ #define BOOT_DEV (dev_nr) 512 /* major-minor device number of boot diskette */ /* Flag bits for i_mode in the inode. */ #define I_TYPE 0170000 /* this field gives inode type */ #define I_REGULAR 0100000 /* regular file, not dir or special */ #define I_BLOCK_SPECIAL 0060000 /* block special file */ #define I_DIRECTORY 0040000 /* file is a directory */ #define I_CHAR_SPECIAL 0020000 /* character special file */ #define I_SET_UID_BIT 0004000 /* set effective uid on exec */ #define I_SET_GID_BIT 0002000 /* set effective gid on exec */ #define ALL_MODES 0006777 /* all bits for user, group and others */ #define RWX_MODES 0000777 /* mode bits for RWX only */ #define R_BIT 0000004 /* Rwx protection bit */ #define W_BIT 0000002 /* rWx protection bit */ #define X_BIT 0000001 /* rwX protection bit */ #define I_NOT_ALLOC 0000000 /* this inode is free */ extern char _ctype_[]; #define _U 0001 #define _L 0002 #define _N 0004 #define _S 0010 #define _P 0020 #define _C 0040 #define _X 0100 #define isalpha(c) ((_ctype_+1)[c]&(_U|_L)) #define isupper(c) ((_ctype_+1)[c]&_U) #define islower(c) ((_ctype_+1)[c]&_L) #define isdigit(c) ((_ctype_+1)[c]&_N) #define isxdigit(c) ((_ctype_+1)[c]&(_N|_X)) #define isspace(c) ((_ctype_+1)[c]&_S) #define ispunct(c) ((_ctype_+1)[c]&_P) #define isalnum(c) ((_ctype_+1)[c]&(_U|_L|_N)) #define isprint(c) ((_ctype_+1)[c]&(_P|_U|_L|_N)) #define iscntrl(c) ((_ctype_+1)[c]&_C) #define isascii(c) ((unsigned)(c)<=0177) #define toupper(c) ((c) - 'a' + 'A') #define tolower(c) ((c) - 'A' + 'a') #define OK 0 #define ERROR 1 #define EPERM 1 #define ENOENT 2 #define ESRCH 3 #define EINTR 4 #define EIO 5 #define ENXIO 6 #define E2BIG 7 #define ENOEXEC 8 #define EBADF 9 #define ECHILD 10 #define EAGAIN 11 #define ENOMEM 12 #define EACCES 13 #define EFAULT 14 #define ENOTBLK 15 #define EBUSY 16 #define EEXIST 17 #define EXDEV 18 #define ENODEV 19 #define ENOTDIR 20 #define EISDIR 21 #define EINVAL 22 #define ENFILE 23 #define EMFILE 24 #define ENOTTY 25 #define ETXTBSY 26 #define EFBIG 27 #define ENOSPC 28 #define ESPIPE 29 #define EROFS 30 #define EMLINK 31 #define EPIPE 32 #define EDOM 33 #define ERANGE 34 #define E_LOCKED 101 #define E_BAD_CALL 102 #define E_LONG_STRING 103 /* Error codes. They are negative since a few system calls, such as READ, can * either return a positive number indicating success, or an error code. */ #define NERROR 34 #define OK 0 #define ERROR -1 #define EPERM -1 #define ENOENT -2 #define ESRCH -3 #define EINTR -4 #define EIO -5 #define ENXIO -6 #define E2BIG -7 #define ENOEXEC -8 #define EBADF -9 #define ECHILD -10 #define EAGAIN -11 #define ENOMEM -12 #define EACCES -13 #define EFAULT -14 #define ENOTBLK -15 #define EBUSY -16 #define EEXIST -17 #define EXDEV -18 #define ENODEV -19 #define ENOTDIR -20 #define EISDIR -21 #define EINVAL -22 #define ENFILE -23 #define EMFILE -24 #define ENOTTY -25 #define ETXTBSY -26 #define EFBIG -27 #define ENOSPC -28 #define ESPIPE -29 #define EROFS -30 #define EMLINK -31 #define EPIPE -32 #define EDOM -33 #define ERANGE -34 #define E_LOCKED -101 #define E_BAD_CALL -102 #define E_LONG_STRING -103 #define EOF -104 /* End Of File - used by drivers */ /* The following error codes are generated by the kernel itself. */ #define E_BAD_DEST -1 /* destination address illegal */ #define E_BAD_SRC -2 /* source address illegal */ #define E_TRY_AGAIN -3 /* can't send-- tables full */ #define E_OVERRUN -4 /* interrupt for task that is not waiting */ #define E_BAD_BUF -5 /* message buf outside caller's addr space */ #define E_TASK -6 /* can't send to task */ #define E_NO_MESSAGE -7 /* RECEIVE failed: no message present */ #define E_NO_PERM -8 /* ordinary users can't send to tasks */ #define E_BAD_FCN -9 /* only valid fcns are SEND, RECEIVE, BOTH */ #define E_BAD_ADDR -10 /* bad address given to utility routine */ #define E_BAD_PROC -11 /* bad proc number given to utility */ struct group { char *name; char *passwd; int gid; }; #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "../h/callnr.h" extern message M; #define MM 0 #define FS 1 extern int callm1(), callm3(), callx(), len(); extern int errno; extern int begsig(); /* interrupts all vector here */ struct passwd { char *pw_name; char *pw_passwd; int pw_uid; int pw_gid; char *pw_gecos; char *pw_dir; char *pw_shell; }; /* * Definitions etc. for regexp(3) routines. * * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], * not the System V one. */ #define void int #define CHARBITS 0377 #define strchr index #define NSUBEXP 10 typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; char regstart; /* Internal use only. */ char reganch; /* Internal use only. */ char *regmust; /* Internal use only. */ int regmlen; /* Internal use only. */ char program[1]; /* Unwarranted chumminess with compiler. */ } regexp; extern regexp *regcomp(); extern int regexec(); extern void regsub(); extern void regerror(); #define _JBLEN 3 typedef int jmp_buf[_JBLEN]; /* Data structures for IOCTL. */ struct sgttyb { char sg_ispeed; /* input speed (not used) */ char sg_ospeed; /* output speed (not used) */ char sg_erase; /* erase character */ char sg_kill; /* kill character */ int sg_flags; /* mode flags */ }; struct tchars { char t_intrc; /* SIGINT char */ char t_quitc; /* SIGQUIT char */ char t_startc; /* start output (initially CTRL-Q) */ char t_stopc; /* stop output (initially CTRL-S) */ char t_eofc; /* EOF (initially CTRL-D) */ char t_brkc; /* input delimiter (like nl) */ }; /* Fields in t_flags. */ #define XTABS 0006000 /* do tab expansion */ #define RAW 0000040 /* enable raw mode */ #define CRMOD 0000020 /* map lf to cr + lf */ #define ECHO 0000010 /* echo input */ #define CBREAK 0000002 /* enable cbreak mode */ #define COOKED 0000000 /* neither CBREAK nor RAW */ #define TIOCGETP (('t'<<8) | 8) #define TIOCSETP (('t'<<8) | 9) #define TIOCGETC (('t'<<8) | 18) #define TIOCSETC (('t'<<8) | 17) #define NR_SIGS 16 /* number of signals used */ #define NSIG 16 /* number of signals used */ #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt (DEL) */ #define SIGQUIT 3 /* quit (ASCII FS) */ #define SIGILL 4 /* illegal instruction (not reset when caught)*/ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGIOT 6 /* IOT instruction */ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #define STACK_FAULT 16 /* used by kernel to signal stack fault */ int (*signal())(); #define SIG_DFL (int (*)())0 #define SIG_IGN (int (*)())1 struct stat { short int st_dev; unsigned short st_ino; unsigned short st_mode; short int st_nlink; short int st_uid; short int st_gid; short int st_rdev; long st_size; long st_atime; long st_mtime; long st_ctime; }; /* Some common definitions. */ #define S_IFMT 0170000 /* type of file */ #define S_IFDIR 0040000 /* directory */ #define S_IFCHR 0020000 /* character special */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_ISUID 04000 /* set user id on execution */ #define S_ISGID 02000 /* set group id on execution */ #define S_ISVTX 01000 /* save swapped text even after use */ #define S_IREAD 00400 /* read permission, owner */ #define S_IWRITE 00200 /* write permission, owner */ #define S_IEXEC 00100 /* execute/search permission, owner */ #define BUFSIZ 1024 #define NFILES 20 #define NULL 0 #define EOF (-1) #define CMASK 0377 #define READMODE 1 #define WRITEMODE 2 #define UNBUFF 4 #define _EOF 8 #define _ERR 16 #define IOMYBUF 32 #define PERPRINTF 64 #define STRINGS 128 #ifndef FILE extern struct _io_buf { int _fd; int _count; int _flags; char *_buf; char *_ptr; } *_io_table[NFILES]; #endif /* FILE */ #define FILE struct _io_buf #define stdin (_io_table[0]) #define stdout (_io_table[1]) #define stderr (_io_table[2]) #define getchar() getc(stdin) #define putchar(c) putc(c,stdout) #define fgetc(f) getc(f) #define fputc(c,f) putc(c,f) #define feof(p) (((p)->_flags & _EOF) != 0) #define ferror(p) (((p)->_flags & _ERR) != 0) #define fileno(p) ((p)->_fd) #define rewind(f) fseek(f, 0L, 0) #define testflag(p,x) ((p)->_flags & (x)) /* If you want a stream to be flushed after each printf use: * * perprintf(stream); * * If you want to stop with this kind of buffering use: * * noperprintf(stream); */ #define noperprintf(p) ((p)->_flags &= ~PERPRINTF) #define perprintf(p) ((p)->_flags |= PERPRINTF) /* Macros */ #define MAX(a,b) (a > b ? a : b) #define MIN(a,b) (a < b ? a : b) /* Type definitions */ typedef unsigned short unshort; /* must be 16-bit unsigned */ typedef unshort block_nr; /* block number */ #define NO_BLOCK (block_nr) 0 /* indicates the absence of a block number */ #define MAX_BLOCK_NR (block_nr) 0177777 typedef unshort inode_nr; /* inode number */ #define NO_ENTRY (inode_nr) 0 /* indicates the absence of a dir entry */ #define MAX_INODE_NR (inode_nr) 0177777 typedef unshort zone_nr; /* zone number */ #define NO_ZONE (zone_nr) 0 /* indicates the absence of a zone number */ #define HIGHEST_ZONE (zone_nr) 0177777 typedef unshort bit_nr; /* if inode_nr & zone_nr both unshort, then also unshort, else long */ typedef long zone_type; /* zone size */ typedef unshort mask_bits; /* mode bits */ typedef unshort dev_nr; /* major | minor device number */ #define NO_DEV (dev_nr) ~0 /* indicates absence of a device number */ typedef char links; /* number of links to an inode */ #define MAX_LINKS 0177 typedef long real_time; /* real time in seconds since Jan 1, 1980 */ typedef long file_pos; /* position in, or length of, a file */ #define MAX_FILE_POS 017777777777L typedef short int uid; /* user id */ typedef char gid; /* group id */ typedef unsigned vir_bytes; /* virtual addresses and lengths in bytes */ typedef unsigned vir_clicks; /* virtual addresses and lengths in clicks */ typedef long phys_bytes; /* physical addresses and lengths in bytes */ typedef unsigned phys_clicks; /* physical addresses and lengths in clicks */ typedef int signed_clicks; /* same length as phys_clicks, but signed */ /* Types relating to messages. */ #define M1 1 #define M3 3 #define M4 4 #define M3_STRING 14 typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1; typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;} mess_2; typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_STRING];} mess_3; typedef struct {long m4l1, m4l2, m4l3, m4l4;} mess_4; typedef struct {char m5c1, m5c2; int m5i1, m5i2; long m5l1, m5l2, m5l3;} mess_5; typedef struct {int m6i1, m6i2, m6i3; long m6l1; int (*m6f1)();} mess_6; typedef struct { int m_source; /* who sent the message */ int m_type; /* what kind of message is it */ union { mess_1 m_m1; mess_2 m_m2; mess_3 m_m3; mess_4 m_m4; mess_5 m_m5; mess_6 m_m6; } m_u; } message; #define MESS_SIZE (sizeof(message)) #define NIL_MESS (message *) 0 /* The following defines provide names for useful members. */ #define m1_i1 m_u.m_m1.m1i1 #define m1_i2 m_u.m_m1.m1i2 #define m1_i3 m_u.m_m1.m1i3 #define m1_p1 m_u.m_m1.m1p1 #define m1_p2 m_u.m_m1.m1p2 #define m1_p3 m_u.m_m1.m1p3 #define m2_i1 m_u.m_m2.m2i1 #define m2_i2 m_u.m_m2.m2i2 #define m2_i3 m_u.m_m2.m2i3 #define m2_l1 m_u.m_m2.m2l1 #define m2_l2 m_u.m_m2.m2l2 #define m2_p1 m_u.m_m2.m2p1 #define m3_i1 m_u.m_m3.m3i1 #define m3_i2 m_u.m_m3.m3i2 #define m3_p1 m_u.m_m3.m3p1 #define m3_ca1 m_u.m_m3.m3ca1 #define m4_l1 m_u.m_m4.m4l1 #define m4_l2 m_u.m_m4.m4l2 #define m4_l3 m_u.m_m4.m4l3 #define m4_l4 m_u.m_m4.m4l4 #define m5_c1 m_u.m_m5.m5c1 #define m5_c2 m_u.m_m5.m5c2 #define m5_i1 m_u.m_m5.m5i1 #define m5_i2 m_u.m_m5.m5i2 #define m5_l1 m_u.m_m5.m5l1 #define m5_l2 m_u.m_m5.m5l2 #define m5_l3 m_u.m_m5.m5l3 #define m6_i1 m_u.m_m6.m6i1 #define m6_i2 m_u.m_m6.m6i2 #define m6_i3 m_u.m_m6.m6i3 #define m6_l1 m_u.m_m6.m6l1 #define m6_f1 m_u.m_m6.m6f1 struct mem_map { vir_clicks mem_vir; /* virtual address */ phys_clicks mem_phys; /* physical address */ vir_clicks mem_len; /* length */ }; struct copy_info { /* used by sys_copy(src, dst, bytes) */ int cp_src_proc; int cp_src_space; vir_bytes cp_src_vir; int cp_dst_proc; int cp_dst_space; vir_bytes cp_dst_vir; vir_bytes cp_bytes; }; #define NCALLS 69 /* number of system calls allowed */ #define EXIT 1 #define FORK 2 #define READ 3 #define WRITE 4 #define OPEN 5 #define CLOSE 6 #define WAIT 7 #define CREAT 8 #define LINK 9 #define UNLINK 10 #define CHDIR 12 #define TIME 13 #define MKNOD 14 #define CHMOD 15 #define CHOWN 16 #define BRK 17 #define STAT 18 #define LSEEK 19 #define GETPID 20 #define MOUNT 21 #define UMOUNT 22 #define SETUID 23 #define GETUID 24 #define STIME 25 #define ALARM 27 #define FSTAT 28 #define PAUSE 29 #define UTIME 30 #define ACCESS 33 #define SYNC 36 #define KILL 37 #define DUP 41 #define PIPE 42 #define TIMES 43 #define SETGID 46 #define GETGID 47 #define SIGNAL 48 #define IOCTL 54 #define EXEC 59 #define UMASK 60 #define CHROOT 61 /* The following are not system calls, but are processed like them. */ #define KSIG 64 /* kernel detected a signal */ #define UNPAUSE 65 /* to MM or FS: check for EINTR */ #define BRK2 66 /* to MM: used to say how big FS & INIT are */ #define REVIVE 67 /* to FS: revive a sleeping process */ #define TASK_REPLY 68 /* to FS: reply code from tty task */ /* System calls. */ #define SEND 1 /* function code for sending messages */ #define RECEIVE 2 /* function code for receiving messages */ #define BOTH 3 /* function code for SEND + RECEIVE */ #define ANY (NR_PROCS+100) /* receive(ANY, buf) accepts from any source */ /* Task numbers, function codes and reply codes. */ #define HARDWARE -1 /* used as source on interrupt generated msgs */ #define SYSTASK -2 /* internal functions */ # define SYS_XIT 1 /* fcn code for sys_xit(parent, proc) */ # define SYS_GETSP 2 /* fcn code for sys_sp(proc, &new_sp) */ # define SYS_SIG 3 /* fcn code for sys_sig(proc, sig) */ # define SYS_FORK 4 /* fcn code for sys_fork(parent, child) */ # define SYS_NEWMAP 5 /* fcn code for sys_newmap(procno, map_ptr) */ # define SYS_COPY 6 /* fcn code for sys_copy(ptr) */ # define SYS_EXEC 7 /* fcn code for sys_exec(procno, new_sp) */ # define SYS_TIMES 8 /* fcn code for sys_times(procno, bufptr) */ # define SYS_ABORT 9 /* fcn code for sys_abort() */ #define CLOCK -3 /* clock class */ # define SET_ALARM 1 /* fcn code to CLOCK, set up alarm */ # define CLOCK_TICK 2 /* fcn code for clock tick */ # define GET_TIME 3 /* fcn code to CLOCK, get real time */ # define SET_TIME 4 /* fcn code to CLOCK, set real time */ # define REAL_TIME 1 /* reply from CLOCK: here is real time */ #define MEM -4 /* /dev/ram, /dev/(k)mem and /dev/null class */ # define RAM_DEV 0 /* minor device for /dev/ram */ # define MEM_DEV 1 /* minor device for /dev/mem */ # define KMEM_DEV 2 /* minor device for /dev/kmem */ # define NULL_DEV 3 /* minor device for /dev/null */ #define FLOPPY -5 /* floppy disk class */ #define WINCHESTER -6 /* winchester (hard) disk class */ # define DISKINT 1 /* fcn code for disk interupt */ # define DISK_READ 3 /* fcn code to DISK (must equal TTY_READ) */ # define DISK_WRITE 4 /* fcn code to DISK (must equal TTY_WRITE) */ # define DISK_IOCTL 5 /* fcn code for setting up RAM disk */ #define TTY -7 /* terminal I/O class */ #define PRINTER -8 /* printer I/O class */ # define TTY_CHAR_INT 1 /* fcn code for tty input interrupt */ # define TTY_O_DONE 2 /* fcn code for tty output done */ # define TTY_READ 3 /* fcn code for reading from tty */ # define TTY_WRITE 4 /* fcn code for writing to tty */ # define TTY_IOCTL 5 /* fcn code for ioctl */ # define SUSPEND -998 /* used in interrupts when tty has no data */ /* Names of message fields for messages to CLOCK task. */ #define DELTA_TICKS m6_l1 /* alarm interval in clock ticks */ #define FUNC_TO_CALL m6_f1 /* pointer to function to call */ #define NEW_TIME m6_l1 /* value to set clock to (SET_TIME) */ #define CLOCK_PROC_NR m6_i1 /* which proc (or task) wants the alarm? */ #define SECONDS_LEFT m6_l1 /* how many seconds were remaining */ /* Names of message fields used for messages to block and character tasks. */ #define DEVICE m2_i1 /* major-minor device */ #define PROC_NR m2_i2 /* which (proc) wants I/O? */ #define COUNT m2_i3 /* how many bytes to transfer */ #define POSITION m2_l1 /* file offset */ #define ADDRESS m2_p1 /* core buffer address */ /* Names of message fields for messages to TTY task. */ #define TTY_LINE m2_i1 /* message parameter: terminal line */ #define TTY_REQUEST m2_i3 /* message parameter: ioctl request code */ #define TTY_SPEK m2_l1 /* message parameter: ioctl speed, erasing */ #define TTY_FLAGS m2_l2 /* message parameter: ioctl tty mode */ /* Names of messages fields used in reply messages from tasks. */ #define REP_PROC_NR m2_i1 /* # of proc on whose behalf I/O was done */ #define REP_STATUS m2_i2 /* bytes transferred or error number */ /* Names of fields for copy message to SYSTASK. */ #define SRC_SPACE m5_c1 /* T or D space (stack is also D) */ #define SRC_PROC_NR m5_i1 /* process to copy from */ #define SRC_BUFFER m5_l1 /* virtual address where data come from */ #define DST_SPACE m5_c2 /* T or D space (stack is also D) */ #define DST_PROC_NR m5_i2 /* process to copy to */ #define DST_BUFFER m5_l2 /* virtual address where data go to */ #define COPY_BYTES m5_l3 /* number of bytes to copy */ /* Field names for accounting, SYSTASK and miscellaneous. */ #define USER_TIME m4_l1 /* user time consumed by process */ #define SYSTEM_TIME m4_l2 /* system time consumed by process */ #define CHILD_UTIME m4_l3 /* user time consumed by process' children */ #define CHILD_STIME m4_l4 /* system time consumed by proces children */ #define PROC1 m1_i1 /* indicates a process */ #define PROC2 m1_i2 /* indicates a process */ #define PID m1_i3 /* process id passed from MM to kernel */ #define STACK_PTR m1_p1 /* used for stack ptr in sys_exec, sys_getsp */ #define PR m6_i1 /* process number for sys_sig */ #define SIGNUM m6_i2 /* signal number for sys_sig */ #define FUNC m6_f1 /* function pointer for sys_sig */ #define MEM_PTR m1_p1 /* tells where memory map is for sys_newmap */ #define CANCEL 0 /* general request to force a task to cancel */ #define SIG_MAP m1_i2 /* used by kernel for passing signal bit map */ /* Copyright (C) 1987 by Prentice-Hall, Inc. Permission is hereby granted to * private individuals and educational institutions to modify and * redistribute the binary and source programs of this system to other * private individuals and educational institutions for educational and * research purposes. For corporate or commercial use, permission from * Prentice-Hall is required. In general, such permission will be granted, * subject to a few conditions. */ #define EXTERN extern /* used in *.h files */ #define PRIVATE static /* PRIVATE x limits the scope of x */ #define PUBLIC /* PUBLIC is the opposite of PRIVATE */ #define FORWARD /* some compilers require this to be 'static' */ #define TRUE 1 /* used for turning integers into Booleans */ #define FALSE 0 /* used for turning integers into Booleans */ #define HZ 60 /* clock freq (software settable on IBM-PC) */ #define BLOCK_SIZE 1024 /* # bytes in a disk block */ #define SUPER_USER (uid) 0 /* uid of superuser */ #define MAJOR 8 /* major device = (dev>>MAJOR) & 0377 */ #define MINOR 0 /* minor device = (dev>>MINOR) & 0377 */ #define NR_TASKS 8 /* number of tasks in the transfer vector */ #define NR_PROCS 16 /* number of slots in proc table */ #define NR_SEGS 3 /* # segments per process */ #define T 0 /* proc[i].mem_map[T] is for text */ #define D 1 /* proc[i].mem_map[D] is for data */ #define S 2 /* proc[i].mem_map[S] is for stack */ #define MAX_P_LONG 2147483647 /* maximum positive long, i.e. 2**31 - 1 */ /* Memory is allocated in clicks. */ #define CLICK_SIZE 0020 /* unit in which memory is allocated */ #define CLICK_SHIFT 4 /* log2 of CLICK_SIZE */ /* Process numbers of some important processes */ #define MM_PROC_NR 0 /* process number of memory manager */ #define FS_PROC_NR 1 /* process number of file system */ #define INIT_PROC_NR 2 /* init -- the process that goes multiuser */ #define LOW_USER 2 /* first user not part of operating system */ /* Miscellaneous */ #define BYTE 0377 /* mask for 8 bits */ #define TO_USER 0 /* flag telling to copy from fs to user */ #define FROM_USER 1 /* flag telling to copy from user to fs */ #define READING 0 /* copy data to user */ #define WRITING 1 /* copy data from user */ #define ABS -999 /* this process means absolute memory */ #define WORD_SIZE 2 /* number of bytes per word */ #define NIL_PTR (char *) 0 /* generally useful expression */ #define NO_NUM 0x8000 /* used as numerical argument to panic() */ #define MAX_PATH 128 /* max length of path names */ #define SIG_PUSH_BYTES 8 /* how many bytes pushed by signal */ #define MAX_ISTACK_BYTES 1024 /* maximum initial stack size for EXEC */ /* Device numbers of root (RAM) and boot (fd0) devices. */ #define ROOT_DEV (dev_nr) 256 /* major-minor device number of root dev */ #define BOOT_DEV (dev_nr) 512 /* major-minor device number of boot diskette */ /* Flag bits for i_mode in the inode. */ #define I_TYPE 0170000 /* this field gives inode type */ #define I_REGULAR 0100000 /* regular file, not dir or special */ #define I_BLOCK_SPECIAL 0060000 /* block special file */ #define I_DIRECTORY 0040000 /* file is a directory */ #define I_CHAR_SPECIAL 0020000 /* character special file */ #define I_SET_UID_BIT 0004000 /* set effective uid on exec */ #define I_SET_GID_BIT 0002000 /* set effective gid on exec */ #define ALL_MODES 0006777 /* all bits for user, group and others */ #define RWX_MODES 0000777 /* mode bits for RWX only */ #define R_BIT 0000004 /* Rwx protection bit */ #define W_BIT 0000002 /* rWx protection bit */ #define X_BIT 0000001 /* rwX protection bit */ #define I_NOT_ALLOC 0000000 /* this inode is free */ /* Error codes. They are negative since a few system calls, such as READ, can * either return a positive number indicating success, or an error code. */ #define NERROR 34 #define OK 0 #define ERROR -1 #define EPERM -1 #define ENOENT -2 #define ESRCH -3 #define EINTR -4 #define EIO -5 #define ENXIO -6 #define E2BIG -7 #define ENOEXEC -8 #define EBADF -9 #define ECHILD -10 #define EAGAIN -11 #define ENOMEM -12 #define EACCES -13 #define EFAULT -14 #define ENOTBLK -15 #define EBUSY -16 #define EEXIST -17 #define EXDEV -18 #define ENODEV -19 #define ENOTDIR -20 #define EISDIR -21 #define EINVAL -22 #define ENFILE -23 #define EMFILE -24 #define ENOTTY -25 #define ETXTBSY -26 #define EFBIG -27 #define ENOSPC -28 #define ESPIPE -29 #define EROFS -30 #define EMLINK -31 #define EPIPE -32 #define EDOM -33 #define ERANGE -34 #define E_LOCKED -101 #define E_BAD_CALL -102 #define E_LONG_STRING -103 #define EOF -104 /* End Of File - used by drivers */ /* The following error codes are generated by the kernel itself. */ #define E_BAD_DEST -1 /* destination address illegal */ #define E_BAD_SRC -2 /* source address illegal */ #define E_TRY_AGAIN -3 /* can't send-- tables full */ #define E_OVERRUN -4 /* interrupt for task that is not waiting */ #define E_BAD_BUF -5 /* message buf outside caller's addr space */ #define E_TASK -6 /* can't send to task */ #define E_NO_MESSAGE -7 /* RECEIVE failed: no message present */ #define E_NO_PERM -8 /* ordinary users can't send to tasks */ #define E_BAD_FCN -9 /* only valid fcns are SEND, RECEIVE, BOTH */ #define E_BAD_ADDR -10 /* bad address given to utility routine */ #define E_BAD_PROC -11 /* bad proc number given to utility */ /* Data structures for IOCTL. */ struct sgttyb { char sg_ispeed; /* input speed (not used) */ char sg_ospeed; /* output speed (not used) */ char sg_erase; /* erase character */ char sg_kill; /* kill character */ int sg_flags; /* mode flags */ }; struct tchars { char t_intrc; /* SIGINT char */ char t_quitc; /* SIGQUIT char */ char t_startc; /* start output (initially CTRL-Q) */ char t_stopc; /* stop output (initially CTRL-S) */ char t_eofc; /* EOF (initially CTRL-D) */ char t_brkc; /* input delimiter (like nl) */ }; /* Fields in t_flags. */ #define XTABS 0006000 /* do tab expansion */ #define RAW 0000040 /* enable raw mode */ #define CRMOD 0000020 /* map lf to cr + lf */ #define ECHO 0000010 /* echo input */ #define CBREAK 0000002 /* enable cbreak mode */ #define COOKED 0000000 /* neither CBREAK nor RAW */ #define TIOCGETP (('t'<<8) | 8) #define TIOCSETP (('t'<<8) | 9) #define TIOCGETC (('t'<<8) | 18) #define TIOCSETC (('t'<<8) | 17) #define NR_SIGS 16 /* number of signals used */ #define NSIG 16 /* number of signals used */ #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt (DEL) */ #define SIGQUIT 3 /* quit (ASCII FS) */ #define SIGILL 4 /* illegal instruction (not reset when caught)*/ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGIOT 6 /* IOT instruction */ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #define STACK_FAULT 16 /* used by kernel to signal stack fault */ int (*signal())(); #define SIG_DFL (int (*)())0 #define SIG_IGN (int (*)())1 struct stat { short int st_dev; unsigned short st_ino; unsigned short st_mode; short int st_nlink; short int st_uid; short int st_gid; short int st_rdev; long st_size; long st_atime; long st_mtime; long st_ctime; }; /* Some common definitions. */ #define S_IFMT 0170000 /* type of file */ #define S_IFDIR 0040000 /* directory */ #define S_IFCHR 0020000 /* character special */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_ISUID 04000 /* set user id on execution */ #define S_ISGID 02000 /* set group id on execution */ #define S_ISVTX 01000 /* save swapped text even after use */ #define S_IREAD 00400 /* read permission, owner */ #define S_IWRITE 00200 /* write permission, owner */ #define S_IEXEC 00100 /* execute/search permission, owner */ /* Macros */ #define MAX(a,b) (a > b ? a : b) #define MIN(a,b) (a < b ? a : b) /* Type definitions */ typedef unsigned short unshort; /* must be 16-bit unsigned */ typedef unshort block_nr; /* block number */ #define NO_BLOCK (block_nr) 0 /* indicates the absence of a block number */ #define MAX_BLOCK_NR (block_nr) 0177777 typedef unshort inode_nr; /* inode number */ #define NO_ENTRY (inode_nr) 0 /* indicates the absence of a dir entry */ #define MAX_INODE_NR (inode_nr) 0177777 typedef unshort zone_nr; /* zone number */ #define NO_ZONE (zone_nr) 0 /* indicates the absence of a zone number */ #define HIGHEST_ZONE (zone_nr) 0177777 typedef unshort bit_nr; /* if inode_nr & zone_nr both unshort, then also unshort, else long */ typedef long zone_type; /* zone size */ typedef unshort mask_bits; /* mode bits */ typedef unshort dev_nr; /* major | minor device number */ #define NO_DEV (dev_nr) ~0 /* indicates absence of a device number */ typedef char links; /* number of links to an inode */ #define MAX_LINKS 0177 typedef long real_time; /* real time in seconds since Jan 1, 1980 */ typedef long file_pos; /* position in, or length of, a file */ #define MAX_FILE_POS 017777777777L typedef short int uid; /* user id */ typedef char gid; /* group id */ typedef unsigned vir_bytes; /* virtual addresses and lengths in bytes */ typedef unsigned vir_clicks; /* virtual addresses and lengths in clicks */ typedef long phys_bytes; /* physical addresses and lengths in bytes */ typedef unsigned phys_clicks; /* physical addresses and lengths in clicks */ typedef int signed_clicks; /* same length as phys_clicks, but signed */ /* Types relating to messages. */ #define M1 1 #define M3 3 #define M4 4 #define M3_STRING 14 typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1; typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;} mess_2; typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_STRING];} mess_3; typedef struct {long m4l1, m4l2, m4l3, m4l4;} mess_4; typedef struct {char m5c1, m5c2; int m5i1, m5i2; long m5l1, m5l2, m5l3;} mess_5; typedef struct {int m6i1, m6i2, m6i3; long m6l1; int (*m6f1)();} mess_6; typedef struct { int m_source; /* who sent the message */ int m_type; /* what kind of message is it */ union { mess_1 m_m1; mess_2 m_m2; mess_3 m_m3; mess_4 m_m4; mess_5 m_m5; mess_6 m_m6; } m_u; } message; #define MESS_SIZE (sizeof(message)) #define NIL_MESS (message *) 0 /* The following defines provide names for useful members. */ #define m1_i1 m_u.m_m1.m1i1 #define m1_i2 m_u.m_m1.m1i2 #define m1_i3 m_u.m_m1.m1i3 #define m1_p1 m_u.m_m1.m1p1 #define m1_p2 m_u.m_m1.m1p2 #define m1_p3 m_u.m_m1.m1p3 #define m2_i1 m_u.m_m2.m2i1 #define m2_i2 m_u.m_m2.m2i2 #define m2_i3 m_u.m_m2.m2i3 #define m2_l1 m_u.m_m2.m2l1 #define m2_l2 m_u.m_m2.m2l2 #define m2_p1 m_u.m_m2.m2p1 #define m3_i1 m_u.m_m3.m3i1 #define m3_i2 m_u.m_m3.m3i2 #define m3_p1 m_u.m_m3.m3p1 #define m3_ca1 m_u.m_m3.m3ca1 #define m4_l1 m_u.m_m4.m4l1 #define m4_l2 m_u.m_m4.m4l2 #define m4_l3 m_u.m_m4.m4l3 #define m4_l4 m_u.m_m4.m4l4 #define m5_c1 m_u.m_m5.m5c1 #define m5_c2 m_u.m_m5.m5c2 #define m5_i1 m_u.m_m5.m5i1 #define m5_i2 m_u.m_m5.m5i2 #define m5_l1 m_u.m_m5.m5l1 #define m5_l2 m_u.m_m5.m5l2 #define m5_l3 m_u.m_m5.m5l3 #define m6_i1 m_u.m_m6.m6i1 #define m6_i2 m_u.m_m6.m6i2 #define m6_i3 m_u.m_m6.m6i3 #define m6_l1 m_u.m_m6.m6l1 #define m6_f1 m_u.m_m6.m6f1 struct mem_map { vir_clicks mem_vir; /* virtual address */ phys_clicks mem_phys; /* physical address */ vir_clicks mem_len; /* length */ }; struct copy_info { /* used by sys_copy(src, dst, bytes) */ int cp_src_proc; int cp_src_space; vir_bytes cp_src_vir; int cp_dst_proc; int cp_dst_space; vir_bytes cp_dst_vir; vir_bytes cp_bytes; }; do { for (i=0, j=0; i < zone_size; i++, j+=ct ) { for (k = 0; k < BLOCK_SIZE; k++) buf[k] = 0; if ((ct=read(f,buf, BLOCK_SIZE)) > 0) { if (i==0) z = alloc_zone(); put_block ( (z << zone_shift) + i, buf); } } if (ct) add_zone (inode, z, (long) j, file_time(f) ); } while (ct == BLOCK_SIZE); close(f); } /*================================================================ * directory & inode management assist group *===============================================================*/ enter_dir(parent, name, child) int parent, child; /* inode nums */ char *name; { /* enter child in parent directory */ /* works for dir > 1 block and zone > block */ int i, j, k, l, b, z, off; char *p1, *p2; struct { short inumb; char name[14]; } dir_entry[NR_DIR_ENTRIES]; d_inode ino[INODES_PER_BLOCK]; b = ((parent-1) / INODES_PER_BLOCK) + inode_offset; off = (parent-1) % INODES_PER_BLOCK ; get_block ( b, ino); for ( k=0; ki_size += bytes; p->i_modtime = cur_time; for (i=0; i < NR_DZONE_NUM; i++) if (p->i_zone[i] == 0) { p->i_zone[i] = z; put_block(b, inode); return; } put_block(b, inode); /* File has grown beyond a small file. */ if (p->i_zone[NR_DZONE_NUM] == 0) p->i_zone[NR_DZONE_NUM] = alloc_zone(); indir = p->i_zone[NR_DZONE_NUM]; put_block(b, inode); b = indir << zone_shift; get_block(b, blk); for (i = 0; i < INTS_PER_BLOCK; i++) if (blk[i] == 0) { blk[i] = z; put_block(b, blk); return; } pexit("File has grown beyond single indirect"); } incr_link(n) int n; { /* increment the link count to inode n */ int b, off; d_inode inode[INODES_PER_BLOCK]; b = ((n-1)/INODES_PER_BLOCK) + inode_offset; off = (n-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_nlinks++; put_block(b, inode); } incr_size(n,count) int n; long count; { /* increment the file-size in inode n */ int b, off; d_inode inode[INODES_PER_BLOCK]; b = ((n-1)/INODES_PER_BLOCK) + inode_offset; off = (n-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_size += count; put_block(b, inode); } /*================================================================ * allocation assist group *===============================================================*/ int alloc_inode(mode, usrid, grpid) int mode, usrid, grpid; { int num, b, off; d_inode inode[INODES_PER_BLOCK]; num = next_inode++; if (num >= nrinodes) pexit("File system does not have enough inodes"); b = ((num-1) / INODES_PER_BLOCK) + inode_offset; off = (num-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_mode = mode; inode[off].i_uid = usrid; inode[off].i_gid = grpid; put_block(b, inode); /* Set the bit in the bit map. */ insert_bit(INODE_MAP, num, 1); return(num); } int alloc_zone() { /* allocate a new zone */ /* works for zone > block */ int b,z,i; z = next_zone++; b = z << zone_shift; if ( (b+zone_size) > nrblocks) pexit("File system not big enough for all the files"); for ( i=0; i < zone_size; i++) put_block ( b+i, zero ); /* give an empty zone */ insert_bit(ZONE_MAP, z - zoff, 1); return(z); } insert_bit(block, bit, count) int block, bit, count; { /* insert 'count' bits in the bitmap */ int w,s, i; char buf[BLOCK_SIZE]; get_block(block, buf); for (i = bit; i < bit + count; i++) { w = i/8; s = i % 8; buf[w] |= (1 << s); } put_block(block, buf); } /*================================================================ * proto-file processing assist group *===============================================================*/ int mode_con(p) char *p; { /* convert string to mode */ int o1, o2, o3, mode; char c1, c2, c3; c1 = *p++; c2 = *p++; c3 = *p++; o1 = *p++ - '0'; o2 = *p++ - '0'; o3 = *p++ - '0'; mode = (o1 << 6) | (o2 << 3) | o3; if (c1 == 'd') mode += I_DIRECTORY; if (c1 == 'b') mode += I_BLOCK_SPECIAL; if (c1 == 'c') mode += I_CHAR_SPECIAL; if (c1 == '-') mode += I_REGULAR; if (c2 == 'u') mode += I_SET_UID_BIT; if (c3 == 'g') mode += I_SET_GID_BIT; return(mode); } getline(line, parse) char *parse[MAX_TOKENS]; char line[LINE_LEN]; { /* read a line and break it up in tokens */ int k; char c, *p; for (k = 0; k < MAX_TOKEN; k++) parse[k] = 0; for (k = 0; k < LINE_LEN; k++) line[k] = 0; k = 0; parse[0] = 0; p = line; while (1) { *p = fgetc(proto); if (*p == '\n') lct++; if (*p <= 0) pexit("Unexpected end-of-file\n"); if (*p == ' ' || *p == '\t') *p = 0; if (*p == '\n') {*p++ = 0; *p = '\n'; break;} p++; } p = line; lastp = line; while (1) { c = *p++; if (c == '\n') return; if (c == 0) continue; parse[k++] = p - 1; do { c = *p++; } while (c != 0 && c != '\n'); } } /*================================================================ * other stuff *===============================================================*/ long file_time(f) int f; { #ifdef UNIX struct stat statbuf; fstat(f, & statbuf); return (statbuf.st_mtime); #else /* fstat not supported by DOS */ return( 0L ); #endif } pexit(s) char *s; { char *s0; s0 = s; while (*s0 != 0) s0++; write (2,"Error: ", 7); write (2, s, s0-s ); write(2, "\n", 1); printf("Line %d being processed when error detected.\n", lct); flush(); exit(2); } copy (from, to, count) char *from, *to; int count; { while (count--) *to++ = *from++; } print_fs() { int i, j, k; d_inode inode[INODES_PER_BLOCK]; int ibuf[INTS_PER_BLOCK], b; struct { short inum; char name[14]; } dir[NR_DIR_ENTRIES]; get_block(1, ibuf); printf("\nSuperblock: "); for (i= 0; i<8; i++) printf("%06o ",ibuf[i]); get_block(2, ibuf); printf("\nInode map: "); for (i = 0; i < 9; i++) printf("%06o ", ibuf[i]); get_block(3, ibuf); printf("\nZone map: "); for (i = 0; i < 9; i++) printf("%06o ", ibuf[i]); printf("\n"); for (b = 4; b < 8; b++) { get_block(b, inode); for (i = 0; i < INODES_PER_BLOCK; i++) { k = INODES_PER_BLOCK * (b - 4) + i + 1; if (k > nrinodes) break; if (inode[i].i_mode != 0) { printf("Inode %2d: mode=",k, inode[i].i_mode); printf(mode_fmt, inode[i].i_mode); printf(" uid=%2d gid=%2d size=", inode[i].i_uid, inode[i].i_gid); printf(size_fmt, inode[i].i_size); printf(" zone[0]=%d\n", inode[i].i_zone[0]); } if ( (inode[i].i_mode & I_TYPE) == I_DIRECTORY) { /* This is a directory */ get_block(inode[i].i_zone[0], dir); for (j = 0; j < NR_DIR_ENTRIES; j++) if (dir[j].inum) printf("\tInode %2d: %s\n",dir[j].inum,dir[j].name); } } } printf("%d inodes used. %d zones used.\n",next_inode-1, next_zone); } int read_and_set(n) int n; { /* The first time a block is read, it returns alls 0s, unless there has * been a write. This routine checks to see if a block has been accessed. */ int w, s, mask, r; w = n/8; s = n%8; mask = 1 << s; r = (umap[w] & mask ? 1 : 0); umap[w] |= mask; return(r); } /*================================================================ * get_block & put_block for MS-DOS *===============================================================*/ #ifdef DOS /* * These are the get_block and put_block routines * when compiling & running mkfs.c under MS-DOS. * * It requires the (asembler) routines absread & abswrite * from the file diskio.asm. Since these routines just do * as they are told (read & write the sector specified), * a local cache is used to minimize the i/o-overhead for * frequently used blocks. * * The global variable "file" determines whether the output * is to a disk-device or to a binary file. */ #define PH_SECTSIZE 512 /* size of a physical disk-sector */ char *derrtab[14] = { "no error", "disk is read-only", "unknown unit", "device not ready", "bad command", "data error", "internal error: bad request structure length", "seek error", "unknown media type", "sector not found", "printer out of paper (??)", "write fault", "read error", "general error" }; #define CACHE_SIZE 20 /* 20 block-buffers */ struct cache { char blockbuf[BLOCK_SIZE]; int blocknum; int dirty; int usecnt; } cache[CACHE_SIZE]; special (string) char *string; { if (string[1] == ':' && string[2]==0) { /* format: d: or d:fname */ disk = (string[0] & ~32) - 'A'; if (disk>1 && !override) /* safety precaution */ pexit ("Bad drive specifier for special"); } else { file=1; if ((fd=creat(string,BWRITE)) == 0) pexit ("Can't open special file"); } } get_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* get a block to the user */ struct cache *bp,*fp; /* First access returns a zero block */ if (read_and_set(n) == 0) { copy(zero, buf, BLOCK_SIZE); return; } /* look for block in cache */ fp=0; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) { if (bp->blocknum==n) { copy (bp,buf,BLOCK_SIZE); bp->usecnt++; return; } /* remember clean block */ if (bp->dirty == 0) if (fp) {if (fp->usecnt > bp->usecnt) fp=bp;} else fp=bp; } /* block not in cache, get it */ if (!fp) { /* no clean buf, flush one */ for (bp=cache,fp=cache; bp<&cache[CACHE_SIZE]; bp++) if (fp->usecnt > bp->usecnt) fp=bp; mx_write (fp->blocknum, fp); } mx_read (n, fp); fp->dirty=0; fp->usecnt=0; fp->blocknum=n; copy (fp, buf, BLOCK_SIZE); } put_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Accept block from user */ struct cache *fp, *bp; read_and_set(n); /* look for block in cache */ fp=0; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) { if (bp->blocknum==n) { copy (buf,bp,BLOCK_SIZE); bp->dirty=1; return; } /* remember clean block */ if (bp->dirty == 0) if (fp) {if (fp->usecnt > bp->usecnt) fp=bp;} else fp=bp; } /* block not in cache */ if (!fp) { /* no clean buf, flush one */ for (bp=cache,fp=cache; bp<&cache[CACHE_SIZE]; bp++) if (fp->usecnt > bp->usecnt) fp=bp; mx_write (fp->blocknum, fp); } fp->dirty=1; fp->usecnt=1; fp->blocknum=n; copy (buf,fp,BLOCK_SIZE); } cache_init() { struct cache *bp; for (bp=cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1; } flush () { /* flush all dirty blocks to disk */ struct cache *bp; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) if (bp->dirty) { mx_write (bp->blocknum, bp); bp->dirty=0; } } /*================================================================== * hard read & write etc. *=================================================================*/ #define MAX_RETRIES 5 mx_read (blocknr,buf) int blocknr; char buf[BLOCK_SIZE]; { /* read the requested MINIX-block in core */ char (*bp)[PH_SECTSIZE]; int sectnum,retries,err; if (file) { lseek (fd, (long) blocknr * BLOCK_SIZE, 0); if (read (fd, buf, BLOCK_SIZE) != BLOCK_SIZE) pexit ("mx_read: error reading file"); } else { sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE); for (bp=buf; bp<&buf[BLOCK_SIZE]; bp++) { retries = MAX_RETRIES; do err=absread (disk,sectnum,bp); while (err && --retries); if (retries) { sectnum++; } else { dexit ("mx_read",sectnum,err); } } } } mx_write (blocknr,buf) int blocknr; char buf[BLOCK_SIZE]; { /* write the MINIX-block to disk */ char (*bp)[PH_SECTSIZE]; int retries,sectnum,err; if (file) { lseek (fd, blocknr * BLOCK_SIZE, 0); if (write (fd, buf, BLOCK_SIZE) != BLOCK_SIZE) { pexit ("mx_write: error writing file"); } } else { sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE); for (bp=buf; bp<&buf[BLOCK_SIZE]; bp++) { retries = MAX_RETRIES; do { err=abswrite (disk,sectnum,bp); } while (err && --retries); if (retries) { sectnum++; } else { dexit ("mx_write",sectnum,err); } } } } dexit (s,sectnum,err) int sectnum, err; char *s; { printf ("Error: %s, sector: %d, code: %d, meaning: %s\n", s, sectnum, err, derrtab[err] ); exit (2); } #endif /*================================================================ * get_block & put_block for UNIX *===============================================================*/ #ifdef UNIX special (string) char *string; { fd = creat(string, 0777); close(fd); fd = open(string, 2); if (fd < 0) pexit("Can't open special file"); } get_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Read a block. */ int k; /* First access returns a zero block */ if (read_and_set(n) == 0) { copy(zero, buf, BLOCK_SIZE); return; } lseek(fd, (long) n*BLOCK_SIZE, 0); k = read(fd, buf, BLOCK_SIZE); if (k != BLOCK_SIZE) { pexit("get_block couldn't read"); } } put_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Write a block. */ read_and_set(n); if (lseek(fd, (long)n*BLOCK_SIZE, 0) < 0L) { pexit("put_block couldn't seek"); } if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) { pexit("put_block couldn't write"); } } /* dummy routines to keep source file clean from #ifdefs */ flush() { return; } cache_init() { return; } #endif E2