/* /usr/src/ext2ed/init.c A part of the extended file system 2 disk editor. -------------------------------- Various initialization routines. -------------------------------- First written on: April 9 1995 Copyright (C) 1995 Gadi Oxman */ #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_READLINE #include <readline.h> #endif #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "ext2ed.h" char lines_s [80],cols_s [80]; void signal_handler (void); void prepare_to_close (void) { close_windows (); if (device_handle!=NULL) fclose (device_handle); free_user_commands (&general_commands); free_user_commands (&ext2_commands); free_struct_descriptors (); } int init (void) { printf ("Initializing ...\n"); if (!process_configuration_file ()) { fprintf (stderr,"Error - Unable to complete configuration. Quitting.\n"); return (0); }; general_commands.last_command=-1; /* No commands whatsoever meanwhile */ ext2_commands.last_command=-1; add_general_commands (); /* Add the general commands, aviable always */ device_handle=NULL; /* Notice that our device is still not set up */ device_offset=-1; current_type=NULL; /* No filesystem specific types yet */ remember_lifo.entries_count=0; /* Object memory is empty */ init_windows (); /* Initialize the NCURSES interface */ init_readline (); /* Initialize the READLINE interface */ init_signals (); /* Initialize the signal handlers */ write_access=0; /* Write access disabled */ strcpy (last_command_line,"help"); /* Show the help screen to the user */ dispatch ("help"); return (1); /* Success */ } void add_general_commands (void) { add_user_command (&general_commands,"help","EXT2ED help system",help); add_user_command (&general_commands,"set","Changes a variable in the current object",set); add_user_command (&general_commands,"setdevice","Selects the filesystem block device (e.g. /dev/hda1)",set_device); add_user_command (&general_commands,"setoffset","Moves asynchronicly in the filesystem",set_offset); add_user_command (&general_commands,"settype","Tells EXT2ED how to interpert the current object",set_type); add_user_command (&general_commands,"show","Displays the current object",show); add_user_command (&general_commands,"pgup","Scrolls data one page up",pgup); add_user_command (&general_commands,"pgdn","Scrolls data one page down",pgdn); add_user_command (&general_commands,"redraw","Redisplay the screen",redraw); add_user_command (&general_commands,"remember","Saves the current position and data information",remember); add_user_command (&general_commands,"recall","Gets back to the saved object position",recall); add_user_command (&general_commands,"enablewrite","Enters Read/Write mode - Allows changing the filesystem",enable_write); add_user_command (&general_commands,"disablewrite","Enters read only mode",disable_write); add_user_command (&general_commands,"writedata","Write data back to disk",write_data); add_user_command (&general_commands,"next","Moves to the next byte in hex mode",next); add_user_command (&general_commands,"prev","Moves to the previous byte in hex mode",prev); } void add_ext2_general_commands (void) { add_user_command (&ext2_commands,"super","Moves to the superblock of the filesystem",type_ext2___super); add_user_command (&ext2_commands,"group","Moves to the first group descriptor",type_ext2___group); add_user_command (&ext2_commands,"cd","Moves to the directory specified",type_ext2___cd); } int set_struct_descriptors (char *file_name) { FILE *fp; char current_line [500],current_word [50],*ch; char variable_name [50],variable_type [20]; struct struct_descriptor *current_descriptor; if ( (fp=fopen (file_name,"rt"))==NULL) { wprintw (command_win,"Error - Failed to open descriptors file %s\n",file_name); refresh_command_win (); return (0); }; while (!feof (fp)) { fgets (current_line,500,fp); if (feof (fp)) break; ch=parse_word (current_line,current_word); if (strcmp (current_word,"struct")==0) { ch=parse_word (ch,current_word); current_descriptor=add_new_descriptor (current_word); while (strchr (current_line,'{')==NULL) { fgets (current_line,500,fp); if (feof (fp)) break; }; if (feof (fp)) break; fgets (current_line,500,fp); while (strchr (current_line,'}')==NULL) { while (strchr (current_line,';')==NULL) { fgets (current_line,500,fp); if (strchr (current_line,'}')!=NULL) break; }; if (strchr (current_line,'}') !=NULL) break; ch=parse_word (current_line,variable_type); ch=parse_word (ch,variable_name); while (variable_name [strlen (variable_name)-1]!=';') { strcpy (variable_type,variable_name); ch=parse_word (ch,variable_name); }; variable_name [strlen (variable_name)-1]=0; add_new_variable (current_descriptor,variable_type,variable_name); fgets (current_line,500,fp); }; }; }; fclose (fp); return (1); } void free_struct_descriptors (void) { struct struct_descriptor *ptr,*next; ptr=first_type; while (ptr!=NULL) { next=ptr->next; free_user_commands (&ptr->type_commands); free (ptr); ptr=next; } first_type=last_type=current_type=NULL; } void free_user_commands (struct struct_commands *ptr) { int i; for (i=0;i<=ptr->last_command;i++) { free (ptr->names [i]); free (ptr->descriptions [i]); } ptr->last_command=-1; } struct struct_descriptor *add_new_descriptor (char *name) { struct struct_descriptor *ptr; ptr = malloc (sizeof (struct struct_descriptor)); if (ptr == NULL) { printf ("Error - Can not allocate memory - Quitting\n"); exit (1); } memset(ptr, 0, sizeof(struct struct_descriptor)); ptr->prev = ptr->next = NULL; strcpy (ptr->name,name); ptr->length=0; ptr->fields_num=0; if (first_type==NULL) { first_type = last_type = ptr; } else { ptr->prev = last_type; last_type->next = ptr; last_type=ptr; } ptr->type_commands.last_command=-1; fill_type_commands (ptr); return (ptr); } struct type_table { char *name; int field_type; int len; }; struct type_table type_table[] = { { "long", FIELD_TYPE_INT, 4 }, { "short", FIELD_TYPE_INT, 2 }, { "char", FIELD_TYPE_CHAR, 1 }, { "__u32", FIELD_TYPE_UINT, 4 }, { "__s32", FIELD_TYPE_INT, 4 }, { "__u16", FIELD_TYPE_UINT, 2 }, { "__s16", FIELD_TYPE_INT, 2 }, { "__u8", FIELD_TYPE_UINT, 1 }, { "__s8", FIELD_TYPE_INT, 1 }, { 0, 0, 0 } }; void add_new_variable (struct struct_descriptor *ptr,char *v_type,char *v_name) { short len=1; char field_type=FIELD_TYPE_INT; struct type_table *p; strcpy (ptr->field_names [ptr->fields_num],v_name); ptr->field_positions [ptr->fields_num]=ptr->length; for (p = type_table; p->name; p++) { if (strcmp(v_type, p->name) == 0) { len = p->len; field_type = p->field_type; break; } } if (p->name == 0) { if (strncmp(v_type, "char[", 5) == 0) { len = atoi(v_type+5); field_type = FIELD_TYPE_CHAR; } else { printf("Unknown type %s for field %s\n", v_type, v_name); exit(1); } } ptr->field_lengths [ptr->fields_num] = len; ptr->field_types [ptr->fields_num] = field_type; ptr->length+=len; ptr->fields_num++; } void fill_type_commands (struct struct_descriptor *ptr) /* Set specific type user commands. */ { if (strcmp ((ptr->name),"file")==0) { add_user_command (&ptr->type_commands,"show","Shows file data",type_file___show); add_user_command (&ptr->type_commands,"inode","Returns to the inode of the current file",type_file___inode); add_user_command (&ptr->type_commands,"display","Specifies data format - text or hex",type_file___display); add_user_command (&ptr->type_commands,"next","Pass to next byte",type_file___next); add_user_command (&ptr->type_commands,"prev","Pass to the previous byte",type_file___prev); add_user_command (&ptr->type_commands,"offset","Pass to a specified byte in the current block",type_file___offset); add_user_command (&ptr->type_commands,"nextblock","Pass to next file block",type_file___nextblock); add_user_command (&ptr->type_commands,"prevblock","Pass to the previous file block",type_file___prevblock); add_user_command (&ptr->type_commands,"block","Specify which file block to edit",type_file___block); add_user_command (&ptr->type_commands,"remember","Saves the file\'s inode position for later reference",type_file___remember); add_user_command (&ptr->type_commands,"set","Sets the current byte",type_file___set); add_user_command (&ptr->type_commands,"writedata","Writes the current block to the disk",type_file___writedata); } if (strcmp ((ptr->name),"ext2_inode")==0) { add_user_command (&ptr->type_commands,"show","Shows inode data",type_ext2_inode___show); add_user_command (&ptr->type_commands,"next","Move to next inode in current block group",type_ext2_inode___next); add_user_command (&ptr->type_commands,"prev","Move to next inode in current block group",type_ext2_inode___prev); add_user_command (&ptr->type_commands,"group","Move to the group descriptors of the current inode table",type_ext2_inode___group); add_user_command (&ptr->type_commands,"entry","Move to a specified entry in the current inode table",type_ext2_inode___entry); add_user_command (&ptr->type_commands,"file","Display file data of the current inode",type_ext2_inode___file); add_user_command (&ptr->type_commands,"dir","Display directory data of the current inode",type_ext2_inode___dir); } if (strcmp ((ptr->name),"dir")==0) { add_user_command (&ptr->type_commands,"show","Shows current directory data",type_dir___show); add_user_command (&ptr->type_commands,"inode","Returns to the inode of the current directory",type_dir___inode); add_user_command (&ptr->type_commands,"next","Pass to the next directory entry",type_dir___next); add_user_command (&ptr->type_commands,"prev","Pass to the previous directory entry",type_dir___prev); add_user_command (&ptr->type_commands,"followinode","Follows the inode specified in this directory entry",type_dir___followinode); add_user_command (&ptr->type_commands,"remember","Remember the inode of the current directory entry",type_dir___remember); add_user_command (&ptr->type_commands,"cd","Changes directory relative to the current directory",type_dir___cd); add_user_command (&ptr->type_commands,"entry","Moves to a specified entry in the current directory",type_dir___entry); add_user_command (&ptr->type_commands,"writedata","Writes the current entry to the disk",type_dir___writedata); add_user_command (&ptr->type_commands,"set","Changes a variable in the current directory entry",type_dir___set); } if (strcmp ((ptr->name),"ext2_super_block")==0) { add_user_command (&ptr->type_commands,"show","Displays the super block data",type_ext2_super_block___show); add_user_command (&ptr->type_commands,"gocopy","Move to another backup copy of the superblock",type_ext2_super_block___gocopy); add_user_command (&ptr->type_commands,"setactivecopy","Copies the current superblock to the main superblock",type_ext2_super_block___setactivecopy); } if (strcmp ((ptr->name),"ext2_group_desc")==0) { add_user_command (&ptr->type_commands,"next","Pass to the next block group decriptor",type_ext2_group_desc___next); add_user_command (&ptr->type_commands,"prev","Pass to the previous group descriptor",type_ext2_group_desc___prev); add_user_command (&ptr->type_commands,"entry","Pass to a specific group descriptor",type_ext2_group_desc___entry); add_user_command (&ptr->type_commands,"show","Shows the current group descriptor",type_ext2_group_desc___show); add_user_command (&ptr->type_commands,"inode","Pass to the inode table of the current group block",type_ext2_group_desc___inode); add_user_command (&ptr->type_commands,"gocopy","Move to another backup copy of the group descriptor",type_ext2_group_desc___gocopy); add_user_command (&ptr->type_commands,"blockbitmap","Show the block allocation bitmap of the current group block",type_ext2_group_desc___blockbitmap); add_user_command (&ptr->type_commands,"inodebitmap","Show the inode allocation bitmap of the current group block",type_ext2_group_desc___inodebitmap); add_user_command (&ptr->type_commands,"setactivecopy","Copies the current group descriptor to the main table",type_ext2_super_block___setactivecopy); } if (strcmp ((ptr->name),"block_bitmap")==0) { add_user_command (&ptr->type_commands,"show","Displays the block allocation bitmap",type_ext2_block_bitmap___show); add_user_command (&ptr->type_commands,"entry","Moves to a specific bit",type_ext2_block_bitmap___entry); add_user_command (&ptr->type_commands,"next","Moves to the next bit",type_ext2_block_bitmap___next); add_user_command (&ptr->type_commands,"prev","Moves to the previous bit",type_ext2_block_bitmap___prev); add_user_command (&ptr->type_commands,"allocate","Allocates the current block",type_ext2_block_bitmap___allocate); add_user_command (&ptr->type_commands,"deallocate","Deallocates the current block",type_ext2_block_bitmap___deallocate); } if (strcmp ((ptr->name),"inode_bitmap")==0) { add_user_command (&ptr->type_commands,"show","Displays the inode allocation bitmap",type_ext2_inode_bitmap___show); add_user_command (&ptr->type_commands,"entry","Moves to a specific bit",type_ext2_inode_bitmap___entry); add_user_command (&ptr->type_commands,"next","Moves to the next bit",type_ext2_inode_bitmap___next); add_user_command (&ptr->type_commands,"prev","Moves to the previous bit",type_ext2_inode_bitmap___prev); add_user_command (&ptr->type_commands,"allocate","Allocates the current inode",type_ext2_inode_bitmap___allocate); add_user_command (&ptr->type_commands,"deallocate","Deallocates the current inode",type_ext2_inode_bitmap___deallocate); } } void add_user_command (struct struct_commands *ptr,char *name,char *description,PF callback) { int num; num=ptr->last_command; if (num+1==MAX_COMMANDS_NUM) { printf ("Internal Error - Can't add command %s\n",name); return; } ptr->last_command=++num; ptr->names [num]=(char *) malloc (strlen (name)+1); strcpy (ptr->names [num],name); if (*description!=0) { ptr->descriptions [num]=(char *) malloc (strlen (description)+1); strcpy (ptr->descriptions [num],description); } ptr->callback [num]=callback; } static unsigned int div_ceil(unsigned int a, unsigned int b) { if (!a) return 0; return ((a - 1) / b) + 1; } int set_file_system_info (void) { int ext2_detected=0; struct ext2_super_block *sb; file_system_info.super_block_offset=1024; file_system_info.file_system_size=DefaultTotalBlocks*DefaultBlockSize; low_read ((char *) &file_system_info.super_block,sizeof (struct ext2_super_block),file_system_info.super_block_offset); sb=&file_system_info.super_block; if (sb->s_magic == EXT2_SUPER_MAGIC) ext2_detected=1; if (ext2_detected) wprintw (command_win,"Detected extended 2 file system on device %s\n",device_name); else wprintw (command_win,"Warning - Extended 2 filesystem not detected on device %s\n",device_name); if (!ext2_detected && !ForceExt2) wprintw (command_win,"You may wish to use the configuration option ForceExt2 on\n"); if (ForceExt2 && !ext2_detected) wprintw (command_win,"Forcing extended 2 filesystem\n"); if (ForceDefault || !ext2_detected) wprintw (command_win,"Forcing default parameters\n"); refresh_command_win (); if (ext2_detected || ForceExt2) { add_ext2_general_commands (); if (!set_struct_descriptors (Ext2Descriptors)) return (0); } if (!ForceDefault && ext2_detected) { file_system_info.block_size=EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size; if (file_system_info.block_size == EXT2_MIN_BLOCK_SIZE) file_system_info.first_group_desc_offset=2*EXT2_MIN_BLOCK_SIZE; else file_system_info.first_group_desc_offset=file_system_info.block_size; file_system_info.groups_count = div_ceil(sb->s_blocks_count, sb->s_blocks_per_group); file_system_info.inodes_per_block=file_system_info.block_size/sizeof (struct ext2_inode); file_system_info.blocks_per_group=sb->s_inodes_per_group/file_system_info.inodes_per_block; file_system_info.no_blocks_in_group=sb->s_blocks_per_group; file_system_info.file_system_size=(sb->s_blocks_count-1)*file_system_info.block_size; } else { file_system_info.file_system_size=DefaultTotalBlocks*DefaultBlockSize; file_system_info.block_size=DefaultBlockSize; file_system_info.no_blocks_in_group=DefaultBlocksInGroup; } if (file_system_info.file_system_size > 2147483647) { wprintw (command_win,"Sorry, filesystems bigger than 2 GB are currently not supported\n"); return (0); } return (1); } void init_readline (void) { #ifdef HAVE_READLINE rl_completion_entry_function=(Function *) complete_command; #endif } void init_signals (void) { signal (SIGWINCH, signal_SIGWINCH_handler); /* Catch SIGWINCH */ signal (SIGTERM, signal_SIGTERM_handler); signal (SIGSEGV, signal_SIGSEGV_handler); } void signal_SIGWINCH_handler (int sig_num) { redraw_request=1; /* We will handle it in main.c */ /* Reset signal handler */ signal (SIGWINCH, signal_SIGWINCH_handler); } void signal_SIGTERM_handler (int sig_num) { prepare_to_close (); printf ("Terminated due to signal %d\n",sig_num); exit (1); } void signal_SIGSEGV_handler (int sig_num) { prepare_to_close (); printf ("Killed by signal %d!\n",sig_num); exit (1); } int process_configuration_file (void) { char buffer [300]; char option [80],value [80]; FILE *fp; strcpy (buffer, ETC_DIR); strcat (buffer,"/ext2ed.conf"); if ((fp=fopen (buffer,"rt"))==NULL) { fprintf (stderr,"Error - Unable to open configuration file %s\n",buffer); return (0); } while (get_next_option (fp,option,value)) { if (strcasecmp (option,"Ext2Descriptors")==0) { strcpy (Ext2Descriptors,value); } else if (strcasecmp (option,"AlternateDescriptors")==0) { strcpy (AlternateDescriptors,value); } else if (strcasecmp (option,"LogFile")==0) { strcpy (LogFile,value); } else if (strcasecmp (option,"LogChanges")==0) { if (strcasecmp (value,"on")==0) LogChanges = 1; else if (strcasecmp (value,"off")==0) LogChanges = 0; else { fprintf (stderr,"Error - Illegal value: %s %s\n",option,value); fclose (fp);return (0); } } else if (strcasecmp (option,"AllowChanges")==0) { if (strcasecmp (value,"on")==0) AllowChanges = 1; else if (strcasecmp (value,"off")==0) AllowChanges = 0; else { fprintf (stderr,"Error - Illegal value: %s %s\n",option,value); fclose (fp);return (0); } } else if (strcasecmp (option,"AllowMountedRead")==0) { if (strcasecmp (value,"on")==0) AllowMountedRead = 1; else if (strcasecmp (value,"off")==0) AllowMountedRead = 0; else { fprintf (stderr,"Error - Illegal value: %s %s\n",option,value); fclose (fp);return (0); } } else if (strcasecmp (option,"ForceExt2")==0) { if (strcasecmp (value,"on")==0) ForceExt2 = 1; else if (strcasecmp (value,"off")==0) ForceExt2 = 0; else { fprintf (stderr,"Error - Illegal value: %s %s\n",option,value); fclose (fp);return (0); } } else if (strcasecmp (option,"DefaultBlockSize")==0) { DefaultBlockSize = atoi (value); } else if (strcasecmp (option,"DefaultTotalBlocks")==0) { DefaultTotalBlocks = strtoul (value,NULL,10); } else if (strcasecmp (option,"DefaultBlocksInGroup")==0) { DefaultBlocksInGroup = strtoul (value,NULL,10); } else if (strcasecmp (option,"ForceDefault")==0) { if (strcasecmp (value,"on")==0) ForceDefault = 1; else if (strcasecmp (value,"off")==0) ForceDefault = 0; else { fprintf (stderr,"Error - Illegal value: %s %s\n",option,value); fclose (fp);return (0); } } else { fprintf (stderr,"Error - Unknown option: %s\n",option); fclose (fp);return (0); } } printf ("Configuration completed\n"); fclose (fp); return (1); } int get_next_option (FILE *fp,char *option,char *value) { char *ptr; char buffer [600]; if (feof (fp)) return (0); do{ if (feof (fp)) return (0); fgets (buffer,500,fp); } while (buffer [0]=='#' || buffer [0]=='\n'); ptr=parse_word (buffer,option); ptr=parse_word (ptr,value); return (1); } void check_mounted (char *name) { FILE *fp; char *ptr; char current_line [500],current_word [200]; mounted=0; if ( (fp=fopen ("/etc/mtab","rt"))==NULL) { wprintw (command_win,"Error - Failed to open /etc/mtab. Assuming filesystem is mounted.\n"); refresh_command_win ();mounted=1;return; }; while (!feof (fp)) { fgets (current_line,500,fp); if (feof (fp)) break; ptr=parse_word (current_line,current_word); if (strcasecmp (current_word,name)==0) { mounted=1;fclose (fp);return; } }; fclose (fp); return; }