1170 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1170 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	de_stdout.c						*/
 | |
| /*								*/
 | |
| /*		Displaying information from the "Disk editor".	*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| /*  origination         1989-Jan-15        Terrence W. Holm	*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| #include <minix/config.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <limits.h>
 | |
| #include <grp.h>
 | |
| #include <pwd.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <termcap.h>
 | |
| #include <time.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <minix/const.h>
 | |
| #include <minix/type.h>
 | |
| #include "../../servers/fs/const.h"
 | |
| #include "../../servers/fs/type.h"
 | |
| #include "../../servers/fs/inode.h"
 | |
| #include <minix/fslib.h>
 | |
| 
 | |
| #include "de.h"
 | |
| 
 | |
| #define major(x) ( (x>>8) & 0377)
 | |
| #define minor(x) (x & 0377)
 | |
| 
 | |
| /****************************************************************/
 | |
| /*   		Code for handling termcap			*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| #define  TC_BUFFER  1024	/* Size of termcap(3) buffer	*/
 | |
| #define  TC_STRINGS  200	/* Enough room for cm,cl,so,se	*/
 | |
| 
 | |
| 
 | |
| static  char  *Tmove;		/* (cm) - Format for tgoto	*/
 | |
| static  char  *Tclr_all;	/* (cl) - Clear screen  	*/
 | |
| static  char  *Treverse;	/* (so) - Start reverse mode 	*/
 | |
| static  char  *Tnormal;		/* (se) - End reverse mode	*/
 | |
| 
 | |
| char   Kup    = 0;		/* (ku) - Up arrow key		*/
 | |
| char   Kdown  = 0;		/* (kd) - Down arrow key	*/
 | |
| char   Kleft  = 0;		/* (kl) - Left arrow key	*/
 | |
| char   Kright = 0;		/* (kr) - Right arrow key	*/
 | |
| 
 | |
| _PROTOTYPE(void Goto , (int column , int line ));
 | |
| _PROTOTYPE(void Block_Type , (de_state *s ));
 | |
| _PROTOTYPE(void Draw_Words , (de_state *s ));
 | |
| _PROTOTYPE(void Draw_Info , (de_state *s ));
 | |
| _PROTOTYPE(void Draw_Block , (char *block ));
 | |
| _PROTOTYPE(void Draw_Map , (char *block , int max_bits ));
 | |
| _PROTOTYPE(void Draw_Offset , (de_state *s ));
 | |
| _PROTOTYPE(void Word_Pointers , (off_t old_addr , off_t new_addr ));
 | |
| _PROTOTYPE(void Block_Pointers , (off_t old_addr , off_t new_addr ));
 | |
| _PROTOTYPE(void Map_Pointers , (off_t old_addr , off_t new_addr ));
 | |
| _PROTOTYPE(void Print_Number , (Word_t number , int output_base ));
 | |
| _PROTOTYPE(void Draw_Zone_Numbers , (de_state *s , struct inode *inode ,
 | |
| 						int zindex , int zrow ));
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Init_Termcap()						*/
 | |
| /*								*/
 | |
| /*		Initializes the external variables for the	*/
 | |
| /*		current terminal.				*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| int Init_Termcap()
 | |
| 
 | |
|   {
 | |
|   char  *term;
 | |
|   char   buffer[ TC_BUFFER ];
 | |
|   static char strings[ TC_STRINGS ];
 | |
|   char  *s = &strings[0];
 | |
|   char  *Kcode;
 | |
| 
 | |
| 
 | |
|   term = getenv( "TERM" );
 | |
| 
 | |
|   if ( term == NULL )
 | |
|     return( 0 );
 | |
| 
 | |
|   if ( tgetent( buffer, term ) != 1 )
 | |
|     return( 0 );
 | |
| 
 | |
| 
 | |
|   if ( (Tmove = tgetstr( "cm", &s )) == NULL )
 | |
|     return( 0 );
 | |
| 
 | |
|   if ( (Tclr_all = tgetstr( "cl", &s )) == NULL )
 | |
|     return( 0 );
 | |
| 
 | |
|   if ( (Treverse = tgetstr( "so", &s )) == NULL )
 | |
|     {
 | |
|     Treverse = Tnormal = s;
 | |
|     *s = '\0';
 | |
|     ++s;
 | |
|     }
 | |
|   else if ( (Tnormal = tgetstr( "se", &s )) == NULL )
 | |
|     return( 0 );
 | |
| 
 | |
| 
 | |
|   /*  See if there are single character arrow key codes  */
 | |
| 
 | |
|   if ( (Kcode = tgetstr( "ku", &s )) != NULL  &&  strlen( Kcode ) == 1 )
 | |
|     Kup = Kcode[0];
 | |
| 
 | |
|   if ( (Kcode = tgetstr( "kd", &s )) != NULL  &&  strlen( Kcode ) == 1 )
 | |
|     Kdown = Kcode[0];
 | |
| 
 | |
|   if ( (Kcode = tgetstr( "kl", &s )) != NULL  &&  strlen( Kcode ) == 1 )
 | |
|     Kleft = Kcode[0];
 | |
| 
 | |
|   if ( (Kcode = tgetstr( "kr", &s )) != NULL  &&  strlen( Kcode ) == 1 )
 | |
|     Kright = Kcode[0];
 | |
| 
 | |
| 
 | |
|   return( 1 );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Goto( column, line )					*/
 | |
| /*								*/
 | |
| /*		Use the termcap string to move the cursor.	*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Goto( column, line )
 | |
|   int  column;
 | |
|   int  line;
 | |
| 
 | |
|   {
 | |
|   fputs( tgoto( Tmove, column, line ), stdout );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*   		       Output routines				*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Help_Screen()					*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Help_Screen( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   int down;
 | |
|   int right;
 | |
| 
 | |
|   switch ( s->mode )
 | |
|     {
 | |
|     case WORD  :   down = 2;    right = 32;  break;
 | |
|     case BLOCK :   down = 64;   right = 1;   break;
 | |
|     case MAP   :   down = 256;  right = 4;   break;
 | |
|     }
 | |
| 
 | |
|   printf( "%s                             ", Tclr_all );
 | |
|   printf( "%sDE  COMMANDS%s\r\n\n\n", Treverse, Tnormal );
 | |
| 
 | |
| 
 | |
|   printf( "   PGUP   b   Back one block              h   Help\r\n" );
 | |
|   printf( "   PGDN   f   Forward one block           q   Quit\r\n" );
 | |
|   printf( "   HOME   B   Goto first block            m   Minix shell\r\n" );
 | |
|   printf( "   END    F   Goto last block\r\n" );
 | |
|   printf( "                                          v   Visual mode (w b m)\r\n" );
 | |
|   printf( "          g   Goto specified block        o   Output base (h d o b)\r\n" );
 | |
|   printf( "          G   Goto block indirectly\r\n" );
 | |
|   printf( "          i   Goto i-node                 c   Change file name\r\n" );
 | |
|   printf( "          I   Filename to i-node          w   Write ASCII block\r\n" );
 | |
|   printf( "                                          W   Write block exactly\r\n" );
 | |
|   printf( "          /   Search\r\n" );
 | |
|   printf( "          n   Next occurrence             x   Extract lost entry\r\n" );
 | |
|   printf( "          p   Previous address            X   Extract lost blocks\r\n" );
 | |
|   printf( "                                          s   Store word\r\n" );
 | |
|   printf( "   UP     u   Move back %d bytes\r\n", down );
 | |
|   printf( "   DOWN   d   Move forward %d bytes\r\n", down );
 | |
|   printf( "   LEFT   l   Move back %d byte%s\r\n", right,
 | |
| 					right == 1 ? "" : "s" );
 | |
|   printf( "   RIGHT  r   Move forward %d byte%s\r\n\n\n", right,
 | |
| 					right == 1 ? "" : "s" );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Wait_For_Key()						*/
 | |
| /*								*/
 | |
| /*		The user must press a key to continue.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Wait_For_Key()
 | |
| 
 | |
|   {
 | |
|   Draw_Prompt( "Press a key to continue..." );
 | |
| 
 | |
|   Get_Char();
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Prompt( string )					*/
 | |
| /*								*/
 | |
| /*		Write a message in the "prompt" area.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Prompt( string )
 | |
|   char  *string;
 | |
| 
 | |
|   {
 | |
|   Goto( PROMPT_COLUMN, PROMPT_LINE );
 | |
| 
 | |
|   printf( "%s%s%s ", Treverse, string, Tnormal );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Erase_Prompt()						*/
 | |
| /*								*/
 | |
| /*		Erase the message in the "prompt" area.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Erase_Prompt()
 | |
| 
 | |
|   {
 | |
|   Goto( PROMPT_COLUMN, PROMPT_LINE );
 | |
| 
 | |
|   printf( "%77c", ' ' );
 | |
| 
 | |
|   Goto( PROMPT_COLUMN, PROMPT_LINE );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Screen( state )					*/
 | |
| /*								*/
 | |
| /*		Redraw everything, except pointers.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Screen( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   fputs( Tclr_all, stdout );
 | |
| 
 | |
|   Draw_Strings( s );
 | |
|   Block_Type( s );
 | |
| 
 | |
|   switch ( s->mode )
 | |
|     {
 | |
|     case WORD :   Draw_Words( s );
 | |
| 		  Draw_Info( s );
 | |
| 		  break;
 | |
| 
 | |
|     case BLOCK :  Draw_Block( s->buffer );
 | |
| 		  break;
 | |
| 
 | |
|     case MAP :	  {
 | |
| 		  int max_bits = 2 * K;
 | |
| 
 | |
| 		  /*  Don't display the bits after the end  */
 | |
| 		  /*  of the i-node or zone bit maps.	    */
 | |
| 
 | |
| 		  if ( s->block == 2 + s->inode_maps - 1 )
 | |
| 		    max_bits = (int)
 | |
| 			       (s->inodes_in_map
 | |
| 				- CHAR_BIT * K * (ino_t) (s->inode_maps - 1)
 | |
| 				- CHAR_BIT * (ino_t) (s->offset & ~ MAP_MASK));
 | |
| 
 | |
| 		  else if ( s->block == 2 + s->inode_maps + s->zone_maps - 1 )
 | |
| 		    max_bits = (int)
 | |
| 			       (s->zones_in_map
 | |
| 			        - CHAR_BIT * K * (zone_t) (s->zone_maps - 1)
 | |
| 				- CHAR_BIT * (zone_t) (s->offset & ~ MAP_MASK));
 | |
| 
 | |
| 		  if ( max_bits < 0 )
 | |
| 		      max_bits = 0;
 | |
| 
 | |
| 		  Draw_Map( &s->buffer[ s->offset & ~ MAP_MASK ], max_bits );
 | |
| 		  break;
 | |
| 		  }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Strings( state )					*/
 | |
| /*								*/
 | |
| /*		The first status line contains the device name,	*/
 | |
| /*		the current write file name (if one is open)	*/
 | |
| /*		and the current search string (if one has	*/
 | |
| /*		been defined).					*/
 | |
| /*								*/
 | |
| /*		Long strings are truncated.			*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Strings( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   int len;
 | |
|   int i;
 | |
| 
 | |
|   Goto( STATUS_COLUMN, STATUS_LINE );
 | |
| 
 | |
|   printf( "Device %s= %-14.14s  ",
 | |
| 	     s->device_mode == O_RDONLY ? "" : "(w) ", s->device_name );
 | |
| 
 | |
|   switch ( s->magic )
 | |
|     {
 | |
|     case SUPER_MAGIC :	printf( "V1 file system  ");
 | |
| 			break;
 | |
|     case SUPER_REV :	printf( "V1-bytes-swapped file system (?)  ");
 | |
| 			break;
 | |
|     case SUPER_V2 :	printf( "V2 file system  ");
 | |
| 			break;
 | |
|     case SUPER_V2_REV :	printf( "V2-bytes-swapped file system (?)  ");
 | |
| 			break;
 | |
|     default :		printf( "not a Minix file system  ");
 | |
| 			break;
 | |
|     }
 | |
| 
 | |
|   len = strlen( s->file_name );
 | |
| 
 | |
|   if ( len == 0 )
 | |
|     printf( "%29s", " " );
 | |
|   else if ( len <= 20 )
 | |
|     printf( "File = %-20s  ", s->file_name );
 | |
|   else
 | |
|     printf( "File = ...%17.17s  ", s->file_name + len - 17 );
 | |
| 
 | |
| 
 | |
|   len = strlen( s->search_string );
 | |
| 
 | |
|   if ( len == 0 )
 | |
|     printf( "%20s", " " );
 | |
|   else
 | |
|     {
 | |
|     printf( "Search = " );
 | |
| 
 | |
|     if ( len <= 11 )
 | |
|       {
 | |
|       for ( i = 0;  i < len;  ++i )
 | |
|         Print_Ascii( s->search_string[ i ] );
 | |
| 
 | |
|       for ( ;  i < 11;  ++i )
 | |
| 	putchar( ' ' );
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|       for ( i = 0;  i < 8;  ++i )
 | |
|         Print_Ascii( s->search_string[ i ] );
 | |
| 
 | |
|       printf( "..." );
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Block_Type( state )					*/
 | |
| /*								*/
 | |
| /*		Display the current block type.			*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Block_Type( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   Goto( STATUS_COLUMN, STATUS_LINE + 1 );
 | |
| 
 | |
|   printf( "Block  = %5u of %-5u  ", s->block, s->zones );
 | |
| 
 | |
|   if ( !s->is_fs )
 | |
|     return;
 | |
| 
 | |
|   if ( s->block == BOOT_BLOCK )
 | |
|     printf( "Boot block" );
 | |
| 
 | |
|   else if ( s->block == 1 )
 | |
|     printf( "Super block" );
 | |
| 
 | |
|   else if ( s->block < 2 + s->inode_maps )
 | |
|     printf( "I-node bit map" );
 | |
| 
 | |
|   else if ( s->block < 2 + s->inode_maps + s->zone_maps )
 | |
|     printf( "Zone bit map" );
 | |
| 
 | |
|   else if ( s->block < s->first_data )
 | |
|     printf( "I-nodes" );
 | |
| 
 | |
|   else
 | |
|     printf( "Data block  (%sin use)",
 | |
| 	In_Use( (bit_t) (s->block - (s->first_data - 1)), s->zone_map )
 | |
| 	? "" : "not " );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Words( state )					*/
 | |
| /*								*/
 | |
| /*		Draw a page in word format.			*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Words( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   int line;
 | |
|   int addr = s->offset & ~ PAGE_MASK;
 | |
| 
 | |
| 
 | |
|   for ( line = 0;  line < 16;  ++line, addr += 2 )
 | |
|     {
 | |
|     Goto( BLOCK_COLUMN, BLOCK_LINE + line );
 | |
| 
 | |
|     printf( "%5d  ", addr );
 | |
| 
 | |
|     Print_Number( *( (word_t *) &s->buffer[ addr ] ), s->output_base );
 | |
|     }
 | |
| 
 | |
|   Goto( BLOCK_COLUMN + 64, BLOCK_LINE  );
 | |
|   printf( "(base %d)", s->output_base );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Info( state )					*/
 | |
| /*								*/
 | |
| /*		Add information to a page drawn in word format.	*/
 | |
| /*		The routine recognizes the super block, inodes,	*/
 | |
| /*		executables and "ar" archives. If the current	*/
 | |
| /*		page is not one of these, then ASCII characters	*/
 | |
| /*		are printed from the data words.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| char *super_block_info[] =  {	"number of inodes",
 | |
| 				"V1 number of zones",
 | |
| 				"inode bit map blocks",
 | |
| 				"zone bit map blocks",
 | |
| 				"first data zone",
 | |
| 				"blocks per zone shift & flags",
 | |
| 				"maximum file size",
 | |
| 				"",
 | |
| 				"magic number",
 | |
| 				"fsck magic number",
 | |
| 				"V2 number of zones"  };
 | |
| 
 | |
| 
 | |
| void Draw_Info( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   int i;
 | |
|   int page = s->offset >> PAGE_SHIFT;
 | |
|   dev_t dev;
 | |
| 
 | |
| 
 | |
|   if ( s->is_fs  &&  s->block == 1  &&  page == 0 )
 | |
|       for ( i = 0;  i < 11;  ++i )
 | |
|  	{
 | |
| 	Goto( INFO_COLUMN, INFO_LINE + i );
 | |
| 	printf( "%s", super_block_info[ i ] );
 | |
| 	}
 | |
| 
 | |
|   else if ( s->is_fs  &&  s->block >= s->first_data - s->inode_blocks  &&
 | |
| 	    s->block < s->first_data )
 | |
|       {
 | |
|       struct inode core_inode;
 | |
|       d1_inode *dip1;
 | |
|       d2_inode *dip2;
 | |
|       struct inode *inode = &core_inode;
 | |
|       int special = 0;
 | |
|       int m;
 | |
|       struct passwd *user;
 | |
|       struct group *grp;
 | |
| 
 | |
|       dip1 = (d1_inode *) &s->buffer[ s->offset & ~ PAGE_MASK ];
 | |
|       dip2 = (d2_inode *) &s->buffer[ s->offset & ~ PAGE_MASK
 | |
| 						& ~ (V2_INODE_SIZE-1) ];
 | |
|       conv_inode( inode, dip1, dip2, READING, s->magic );
 | |
| 
 | |
|       user = getpwuid( inode->i_uid );
 | |
|       grp  = getgrgid( inode->i_gid );
 | |
| 
 | |
|       if ( s->magic != SUPER_MAGIC  &&  page & 1 )
 | |
| 	{
 | |
| 	Draw_Zone_Numbers( s, inode, 2, 0 );
 | |
| 	return;
 | |
| 	}
 | |
| 
 | |
|       Goto( INFO_COLUMN, INFO_LINE  );
 | |
| 
 | |
|       switch( inode->i_mode & S_IFMT )
 | |
|     	{
 | |
|     	case S_IFDIR :  printf( "directory  " );
 | |
| 		    	break;
 | |
| 
 | |
|     	case S_IFCHR :  printf( "character  " );
 | |
| 		    	special = 1;
 | |
| 		    	break;
 | |
| 
 | |
|     	case S_IFBLK :  printf( "block  " );
 | |
| 		   	special = 1;
 | |
| 		    	break;
 | |
| 
 | |
|     	case S_IFREG :  printf( "regular  " );
 | |
| 		    	break;
 | |
| #ifdef S_IFIFO
 | |
|     	case S_IFIFO :  printf( "fifo  " );
 | |
| 		    	break;
 | |
| #endif
 | |
| #ifdef S_IFLNK
 | |
|     	case S_IFLNK :  printf( "symlink  " );
 | |
| 		    	break;
 | |
| #endif
 | |
| #ifdef S_IFSOCK
 | |
|     	case S_IFSOCK:  printf( "socket  " );
 | |
| 		    	break;
 | |
| #endif
 | |
|     	default      :  printf( "unknown  " );
 | |
|     	}
 | |
| 
 | |
| 	for ( m = 11;  m >= 0;  --m )
 | |
| 	  putchar( (inode->i_mode & (1<<m)) ? "xwrxwrxwrtgu"[m] : '-' );
 | |
| 
 | |
| 	if ( s->magic == SUPER_MAGIC )
 | |
| 	  {
 | |
| 	  /* V1 file system */
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 1 );
 | |
| 	  printf( "user %s", user ? user->pw_name : "" );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 2 );
 | |
| 	  printf( "file size %lu", inode->i_size );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 4 );
 | |
| 	  printf( "m_time %s", ctime( &inode->i_mtime ) );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 6 );
 | |
| 	  printf( "links %d, group %s",
 | |
| 		  inode->i_nlinks, grp ? grp->gr_name : "" );
 | |
| 
 | |
| 	  Draw_Zone_Numbers( s, inode, 0, 7 );
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	  /* V2 file system, even page. */
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 1 );
 | |
| 	  printf( "links %d ", inode->i_nlinks);
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 2 );
 | |
| 	  printf( "user %s", user ? user->pw_name : "" );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 3 );
 | |
| 	  printf( "group %s", grp ? grp->gr_name : "" );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 4 );
 | |
| 	  printf( "file size %lu", inode->i_size );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 6 );
 | |
| 	  printf( "a_time %s", ctime( &inode->i_atime ) );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 8 );
 | |
| 	  printf( "m_time %s", ctime( &inode->i_mtime ) );
 | |
| 
 | |
| 	  Goto( INFO_COLUMN, INFO_LINE + 10 );
 | |
| 	  printf( "c_time %s", ctime( &inode->i_ctime ) );
 | |
| 
 | |
| 	  Draw_Zone_Numbers( s, inode, 0, 12 );
 | |
| 	}
 | |
| 
 | |
|       if ( special )
 | |
| 	{
 | |
| 	Goto( INFO_COLUMN, INFO_LINE + 7 );
 | |
| 	dev = (dev_t) inode->i_zone[0];
 | |
| 	printf( "major %d, minor %d", major(dev), minor(dev) );
 | |
| 	}
 | |
|       }
 | |
| 
 | |
|   else  /*  Print ASCII characters for each byte in page  */
 | |
|       {
 | |
|       char *p = &s->buffer[ s->offset & ~ PAGE_MASK ];
 | |
| 
 | |
|       for ( i = 0;  i < 16;  ++i )
 | |
|         {
 | |
|         Goto( INFO_COLUMN, INFO_LINE + i );
 | |
|         Print_Ascii( *p++ );
 | |
|         Print_Ascii( *p++ );
 | |
|         }
 | |
| 
 | |
|       if ( s->block >= s->first_data  &&  page == 0 )
 | |
| 	{
 | |
| 	unsigned magic  = ((s->buffer[1] & 0xff) << 8) | (s->buffer[0] & 0xff);
 | |
| 	unsigned second = ((s->buffer[3] & 0xff) << 8) | (s->buffer[2] & 0xff);
 | |
| 
 | |
| 	/*  Is this block the start of an executable file?  */
 | |
| 
 | |
| 	if ( magic == (unsigned) A_OUT )
 | |
| 	  {
 | |
|           Goto( INFO_COLUMN, INFO_LINE );
 | |
| 	  printf( "executable" );
 | |
| 
 | |
|           Goto( INFO_COLUMN, INFO_LINE + 1 );
 | |
| 
 | |
| 	  if ( second == (unsigned) SPLIT )
 | |
| 	    printf( "separate I & D" );
 | |
| 	  else
 | |
| 	    printf( "combined I & D" );
 | |
| 	  }
 | |
| 	}
 | |
|       }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Block( block )					*/
 | |
| /*								*/
 | |
| /*		Redraw a 1k block in character format.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Block( block )
 | |
|   char *block;
 | |
| 
 | |
|   {
 | |
|   int line;
 | |
|   int column;
 | |
|   int reverse = 0;
 | |
|   int msb_flag = 0;
 | |
| 
 | |
| 
 | |
|   for ( line = 0;  line < 16;  ++line )
 | |
|     {
 | |
|     Goto( BLOCK_COLUMN, BLOCK_LINE + line );
 | |
| 
 | |
|     for ( column = 0;  column < 64;  ++column )
 | |
|       {
 | |
|       char c = *block++;
 | |
| 
 | |
|       if ( c & 0x80 )
 | |
| 	{
 | |
| 	msb_flag = 1;
 | |
| 	c &= 0x7f;
 | |
| 	}
 | |
| 
 | |
|       if ( c >= ' '  &&  c < DEL )
 | |
| 	{
 | |
| 	if ( reverse )
 | |
| 	  { fputs( Tnormal, stdout ); reverse = 0; }
 | |
| 
 | |
|         putchar( c );
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	if ( ! reverse )
 | |
| 	  { fputs( Treverse, stdout ); reverse = 1; }
 | |
| 
 | |
| 	putchar( c == DEL ? '?' : '@' + c );
 | |
| 	}
 | |
|       }  /*  end for ( column )  */
 | |
|     }  /*  end for ( line )  */
 | |
| 
 | |
|   if ( reverse )
 | |
|     { fputs( Tnormal, stdout ); reverse = 0; }
 | |
| 
 | |
|   if ( msb_flag )
 | |
|     {
 | |
|     Goto( BLOCK_COLUMN + 68, BLOCK_LINE + 6 );
 | |
|     fputs( "(MSB)", stdout );
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Map( block, max_bits )				*/
 | |
| /*								*/
 | |
| /*		Redraw a block in a bit map format.		*/
 | |
| /*		Display min( max_bits, 2048 ) bits.		*/
 | |
| /*								*/
 | |
| /*		The 256 bytes in "block" are displayed from	*/
 | |
| /*		top to bottom and left to right. Bit 0 of	*/
 | |
| /*		a byte is towards the top of the screen.	*/
 | |
| /*								*/
 | |
| /*		Special graphic codes are used to generate	*/
 | |
| /*		two "bits" per character position. So a 16	*/
 | |
| /*		line by 64 column display is 32 "bits" by	*/
 | |
| /*		64 "bits". Or 4 bytes by 64 bytes.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Map( block, max_bits )
 | |
|   char *block;
 | |
|   int   max_bits;
 | |
| 
 | |
|   {
 | |
|   int line;
 | |
|   int column;
 | |
|   int bit_count = 0;
 | |
| 
 | |
|   for ( line = 0;  line < 16;  ++line )
 | |
|     {
 | |
|     char *p = &block[ (line & 0xC) >> 2 ];
 | |
|     int shift = (line & 0x3) << 1;
 | |
| 
 | |
|     Goto( BLOCK_COLUMN, BLOCK_LINE + line );
 | |
| 
 | |
|     for ( column = 0;  column < 64;  ++column, p += 4 )
 | |
|       {
 | |
|       char c = (*p >> shift) & 0x3;
 | |
|       int current_bit = ((p - block) << 3) + shift;
 | |
| 
 | |
|       /*  Don't display bits past "max_bits"  */
 | |
| 
 | |
|       if ( current_bit >= max_bits )
 | |
| 	break;
 | |
| 
 | |
|       /*  If "max_bits" occurs in between the two bits  */
 | |
|       /*  I am trying to display as one character, then	*/
 | |
|       /*  zero off the high-order bit.			*/
 | |
| 
 | |
|       if ( current_bit + 1 == max_bits )
 | |
| 	c &= 1;
 | |
| 
 | |
|       switch ( c )
 | |
| 	{
 | |
| 	case 0 :  putchar( BOX_CLR );
 | |
| 		  break;
 | |
| 
 | |
| 	case 1 :  putchar( BOX_TOP );
 | |
| 		  ++bit_count;
 | |
| 		  break;
 | |
| 
 | |
| 	case 2 :  putchar( BOX_BOT );
 | |
| 		  ++bit_count;
 | |
| 		  break;
 | |
| 
 | |
| 	case 3 :  putchar( BOX_ALL );
 | |
| 		  bit_count += 2;
 | |
| 		  break;
 | |
| 	}
 | |
|       }  /*  end for ( column )  */
 | |
|     }  /*  end for ( line )  */
 | |
| 
 | |
| 
 | |
|   Goto( BLOCK_COLUMN + 68, BLOCK_LINE + 6 );
 | |
|   printf( "(%d)", bit_count );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Pointers( state )					*/
 | |
| /*								*/
 | |
| /*		Redraw the pointers and the offset field.	*/
 | |
| /*		The rest of the screen stays intact.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Pointers( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   Draw_Offset( s );
 | |
| 
 | |
|   switch ( s->mode )
 | |
|     {
 | |
|     case WORD :   Word_Pointers( s->last_addr, s->address );
 | |
| 		  break;
 | |
| 
 | |
|     case BLOCK :  Block_Pointers( s->last_addr, s->address );
 | |
| 		  break;
 | |
| 
 | |
|     case MAP :	  Map_Pointers( s->last_addr, s->address );
 | |
| 		  break;
 | |
|     }
 | |
| 
 | |
|   Goto( PROMPT_COLUMN, PROMPT_LINE );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Draw_Offset( state )					*/
 | |
| /*								*/
 | |
| /*		Display the offset in the current buffer	*/
 | |
| /*		and the relative position if within a map	*/
 | |
| /*		or i-node block.				*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Draw_Offset( s )
 | |
|   de_state *s;
 | |
| 
 | |
|   {
 | |
|   Goto( STATUS_COLUMN, STATUS_LINE + 2 );
 | |
| 
 | |
|   printf( "Offset = %5d           ", s->offset );
 | |
| 
 | |
| 
 | |
|   if ( s->block < 2 )
 | |
|     return;
 | |
| 
 | |
|   if ( s->block < 2 + s->inode_maps )
 | |
|     {
 | |
|     long bit = (s->address - 2 * K) * 8;
 | |
| 
 | |
|     if ( bit < s->inodes_in_map )
 | |
| 	printf( "I-node %ld of %d     ", bit, s->inodes );
 | |
|     else
 | |
| 	printf( "(padding)                " );
 | |
|     }
 | |
| 
 | |
|   else if ( s->block < 2 + s->inode_maps + s->zone_maps )
 | |
|     {
 | |
|     long bit = (s->address - (2 + s->inode_maps) * K) * 8;
 | |
| 
 | |
|     if ( bit < s->zones_in_map )
 | |
| 	printf( "Block %ld of %u     ", bit + s->first_data - 1, s->zones );
 | |
|     else
 | |
| 	printf( "(padding)                " );
 | |
|     }
 | |
| 
 | |
|   else if ( s->block < s->first_data )
 | |
|     {
 | |
|     bit_t node = (s->address - (2 + s->inode_maps + s->zone_maps) * K) /
 | |
| 		s->inode_size + 1;
 | |
| 
 | |
|     if ( node <= s->inodes )
 | |
| 	printf( "I-node %lu of %lu  (%sin use)       ",
 | |
| 		(unsigned long) node, (unsigned long) s->inodes,
 | |
| 		In_Use( node, s->inode_map ) ? "" : "not " );
 | |
|     else
 | |
| 	printf( "(padding)                             " );
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Word_Pointers( old_addr, new_addr )			*/
 | |
| /*								*/
 | |
| /*	Block_Pointers( old_addr, new_addr )			*/
 | |
| /*								*/
 | |
| /*	Map_Pointers( old_addr, new_addr )			*/
 | |
| /*								*/
 | |
| /*		Redraw the index pointers for a each type	*/
 | |
| /*		of display. The pointer at "old_addr" is	*/
 | |
| /*		erased and a new pointer is positioned		*/
 | |
| /*		for "new_addr". This makes the screen		*/
 | |
| /*		update faster and more pleasant for the user.	*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Word_Pointers( old_addr, new_addr )
 | |
|   off_t old_addr;
 | |
|   off_t new_addr;
 | |
| 
 | |
|   {
 | |
|   int from = ( (int) old_addr & PAGE_MASK ) >> 1;
 | |
|   int to   = ( (int) new_addr & PAGE_MASK ) >> 1;
 | |
| 
 | |
|   Goto( BLOCK_COLUMN - 2, BLOCK_LINE + from );
 | |
|   putchar( ' ' );
 | |
| 
 | |
|   Goto( BLOCK_COLUMN - 2, BLOCK_LINE + to );
 | |
|   putchar( '>' );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| void Block_Pointers( old_addr, new_addr )
 | |
|   off_t old_addr;
 | |
|   off_t new_addr;
 | |
| 
 | |
|   {
 | |
|   int from = (int) old_addr & ~K_MASK;
 | |
|   int to   = (int) new_addr & ~K_MASK;
 | |
| 
 | |
|   Goto( BLOCK_COLUMN - 2, BLOCK_LINE + from / 64 );
 | |
|   putchar( ' ' );
 | |
| 
 | |
|   Goto( BLOCK_COLUMN - 2, BLOCK_LINE + to / 64 );
 | |
|   putchar( '>' );
 | |
| 
 | |
|   Goto( BLOCK_COLUMN + from % 64, BLOCK_LINE + 17 );
 | |
|   putchar( ' ' );
 | |
| 
 | |
|   Goto( BLOCK_COLUMN + to % 64, BLOCK_LINE + 17 );
 | |
|   putchar( '^' );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| void Map_Pointers( old_addr, new_addr )
 | |
|   off_t old_addr;
 | |
|   off_t new_addr;
 | |
| 
 | |
|   {
 | |
|   int from = ( (int) old_addr & MAP_MASK ) >> 2;
 | |
|   int to   = ( (int) new_addr & MAP_MASK ) >> 2;
 | |
| 
 | |
|   Goto( BLOCK_COLUMN + from, BLOCK_LINE + 17 );
 | |
|   putchar( ' ' );
 | |
| 
 | |
|   Goto( BLOCK_COLUMN + to, BLOCK_LINE + 17 );
 | |
|   putchar( '^' );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Print_Number( number, output_base )			*/
 | |
| /*								*/
 | |
| /*		Output "number" in the output base.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Print_Number( number, output_base )
 | |
|   word_t number;
 | |
|   int output_base;
 | |
| 
 | |
|   {
 | |
|   switch ( output_base )
 | |
|     {
 | |
|     case 16 :	printf( "%5x", number );
 | |
| 		break;
 | |
| 
 | |
|     case 10 :	printf( "%7u", number );
 | |
| 		break;
 | |
| 
 | |
|     case 8 :	printf( "%7o", number );
 | |
| 		break;
 | |
| 
 | |
|     case 2 :	{
 | |
|       		unsigned int mask;
 | |
|       		char pad = ' ';
 | |
| 
 | |
|       		for ( mask = 0x8000;  mask > 1;  mask >>= 1 )
 | |
| 		  putchar( (mask & number) ? (pad = '0', '1') : pad );
 | |
| 
 | |
|       		putchar( (0x01 & number) ? '1' : '0' );
 | |
| 
 | |
| 		break;
 | |
|       		}
 | |
| 
 | |
|     default :	Error( "Internal fault (output_base)" );
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Print_Ascii( char )					*/
 | |
| /*								*/
 | |
| /*		Display a character in reverse mode if it	*/
 | |
| /*		is not a normal printable ASCII character.	*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| void Print_Ascii( c )
 | |
|   char c;
 | |
| 
 | |
|   {
 | |
|   c &= 0x7f;
 | |
| 
 | |
|   if ( c < ' ' )
 | |
|     printf( "%s%c%s", Treverse, '@' + c, Tnormal );
 | |
|   else if ( c == DEL )
 | |
|     printf( "%s?%s", Treverse, Tnormal );
 | |
|   else
 | |
|     putchar( c );
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /****************************************************************/
 | |
| /*								*/
 | |
| /*	Warning( text, arg1, arg2 )				*/
 | |
| /*								*/
 | |
| /*		Display a message for 2 seconds.		*/
 | |
| /*								*/
 | |
| /****************************************************************/
 | |
| 
 | |
| 
 | |
| #if __STDC__
 | |
| void Warning( const char *text, ... )
 | |
| #else
 | |
| void Warning( text )
 | |
|   char *text;
 | |
| #endif  
 | |
| 
 | |
|   {
 | |
|   va_list argp;
 | |
|   
 | |
|   printf( "%c%s", BELL, Tclr_all );
 | |
| 
 | |
|   Goto( WARNING_COLUMN, WARNING_LINE );
 | |
| 
 | |
|   printf( "%s Warning: ", Treverse );
 | |
|   va_start( argp, text );
 | |
|   vprintf( text, argp );
 | |
|   va_end( argp );
 | |
|   printf( " %s", Tnormal );
 | |
| 
 | |
|   fflush(stdout);		/* why does everyone forget this? */
 | |
| 
 | |
|   sleep( 2 );
 | |
|   }
 | |
| 
 | |
| 
 | |
| void Draw_Zone_Numbers( s, inode, zindex, zrow )
 | |
|   de_state *s;
 | |
|   struct inode *inode;
 | |
|   int zindex;
 | |
|   int zrow;
 | |
| 
 | |
|   {
 | |
|   static char *plurals[] = { "", "double ", "triple " };
 | |
|   zone_t zone;
 | |
| 
 | |
|   for ( ; zrow < 16;
 | |
| 	++zindex, zrow += s->zone_num_size / sizeof (word_t) )
 | |
|     {
 | |
|     Goto( INFO_COLUMN, INFO_LINE + zrow );
 | |
|     if ( zindex < s->ndzones )
 | |
|       printf( "zone %d", zindex );
 | |
|     else
 | |
|       printf( "%sindirect", plurals[ zindex - s->ndzones ] );
 | |
|     if ( s->magic != SUPER_MAGIC )
 | |
|       {
 | |
|       zone = inode->i_zone[ zindex ];
 | |
|       if ( zone != (word_t) zone )
 | |
| 	{
 | |
| 	Goto( INFO_COLUMN + 16, INFO_LINE + zrow );
 | |
| 	printf("%ld", (long) zone );
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | 
