5 A part of the extended file system 2 disk editor.
11 This file mostly contains:
13 1. A list of global variables used through the entire program.
14 2. The parser, which asks the command line from the user.
15 3. The dispatcher, which analyzes the command line and calls the appropriate handler function.
16 4. A command pattern matcher which is used along with the readline completion feature.
17 5. A function which tells the user that an internal error has occured.
19 First written on: March 30 1995
21 Copyright (C) 1995 Gadi Oxman
44 /* Global variables */
48 Configuration file options
50 The following variables will be set by init.c to the values selected in the user configuration file.
51 They are initialized below to some logical defaults.
56 char Ext2Descriptors [200]="ext2.descriptors"; /* The location of the ext2 filesystem object definition */
57 char AlternateDescriptors [200]=""; /* We allow the user to define additional structures */
58 char LogFile [200]="ext2ed.log"; /* The location of the log file - Each write will be logged there */
59 int LogChanges=1; /* 1 enables logging, 0 diables logging */
60 int AllowChanges=0; /* When set, the enablewrite command will fail */
61 int AllowMountedRead=0; /* Behavior when trying to open a mounted filesystem read-only */
62 int ForceExt2=0; /* When set, ext2 autodetection is overridden */
63 int DefaultBlockSize=1024;
64 unsigned long DefaultTotalBlocks=2097151;
65 unsigned long DefaultBlocksInGroup=8192; /* The default values are used when an ext2 filesystem is not */
66 int ForceDefault=0; /* detected, or ForceDefault is set */
68 char last_command_line [80]; /* A simple one command cache, in addition to the readline history */
70 char device_name [80]; /* The location of the filesystem */
71 FILE *device_handle=NULL; /* This is passed to the fopen / fread ... commands */
72 long device_offset; /* The current position in the filesystem */
73 /* Note that we have a 2 GB limitation */
75 int mounted=0; /* This is set when we find that the filesystem is mounted */
77 struct struct_commands general_commands,ext2_commands; /* Used to define the general and ext2 commands */
78 struct struct_descriptor *first_type,*last_type,*current_type; /* Used to access the double linked list */
79 struct struct_type_data type_data; /* The current data is sometimes stored here */
80 struct struct_file_system_info file_system_info; /* Essential information on the filesystem */
81 struct struct_file_info file_info,first_file_info; /* Used by file_com.c to access files */
82 struct struct_group_info group_info; /* Used by group_com.c */
83 struct struct_super_info super_info; /* Used by super_com.c */
84 struct struct_remember_lifo remember_lifo; /* A circular memory of objects */
85 struct struct_block_bitmap_info block_bitmap_info; /* Used by blockbitmap_com.c */
86 struct struct_inode_bitmap_info inode_bitmap_info; /* Used by inodebitmap_com.c */
88 int redraw_request=0; /* Is set by a signal handler to handle terminal */
89 /* screen size change. */
93 * We just call the parser to get commands from the user. We quit when
96 int main (int argc, char **argv)
104 while ((c = getopt (argc, argv, "w")) != EOF) {
112 buf = malloc(strlen(argv[optind]) + 32);
114 fprintf(stderr, "Couldn't allocate filename buffer\n");
117 strcpy(buf, "set_device ");
118 strcat(buf, argv[optind]);
122 wprintw (command_win,"\n");
123 enable_write("enable_write");
126 parser (); /* Get and parse user commands */
127 prepare_to_close(); /* Do some cleanup */
128 printf("Quitting ...\n");
134 * Read a character from the command window
136 int command_read_key()
141 if (redraw_request) {
145 key = wgetch(command_win);
149 kill(getpid(), SIGTSTP);
154 refresh_command_win ();
159 refresh_command_win ();
168 if ((key < 32 && key != '\b' && key != '\n') ||
176 int rl_getc_replacement(FILE *f)
178 int key = command_read_key();
182 wprintw(command_win, "\b \b");
184 wprintw(command_win, "%c", key);
189 * This function asks the user for a command and calls the dispatcher
190 * function, dispatch, to analyze it. We use the readline library
191 * function readline to read the command, hence all the usual readline
192 * keys are available. The new command is saved both in the
193 * readline's history and in our tiny one-command cache, so that only
194 * the enter key is needed to retype it.
198 char *ptr,command_line [80];
204 keypad(command_win, 1);
205 wtimeout(command_win, 100);
207 rl_getc_function = rl_getc_replacement;
211 /* Terminal screen size has changed */
212 if (redraw_request) {
217 wmove (command_win,0,0);
218 wclrtoeol (command_win);
219 wprintw (command_win,"ext2ed > ");
220 refresh_command_win ();
223 * The ncurses library optimizes cursor movement by
224 * keeping track of the cursor position. However, by
225 * using the readline library I'm breaking its
226 * assumptions. The double -1 arguments tell ncurses
227 * to disable cursor movement optimization this
230 mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0);
233 ptr=readline ("ext2ed > ");
237 * Readline allocated the buffer - Copy the string
238 * and free the allocated buffer
241 strcpy (command_line,ptr);
244 if (*command_line != 0)
245 add_history (command_line);
247 /* If only enter was pressed, recall the last command */
248 if (*command_line==0)
249 strcpy (command_line,last_command_line);
251 /* Emulate readline's actions for ncurses */
252 mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0);
253 werase (command_win);
254 wprintw (command_win,"ext2ed > ");
255 wprintw (command_win,command_line);
256 wprintw (command_win,"\n");
257 refresh_command_win ();
259 /* Save this command in our tiny cache */
260 strcpy (last_command_line,command_line);
262 /* And call dispatch to do the actual job */
263 quit=dispatch (command_line);
267 void read_line(char * foo) {
272 while (!done && (ch = command_read_key())) {
280 wprintw(command_win, "\b \b");
288 if (ch == '\n') break;
290 wprintw(command_win, "%c", ch);
299 char command_line [80];
304 wtimeout(command_win, 100);
305 keypad(command_win, 1);
308 /* Terminal screen size has changed */
309 if (redraw_request) {
314 wmove (command_win,0,0);wclrtoeol (command_win);
316 wmove(command_win, 0, 0);
317 wprintw(command_win, "ext2ed > ");
318 read_line(command_line);
320 /* If only enter was pressed, recall the last command */
321 if (*command_line==0)
322 strcpy (command_line,last_command_line);
324 mvcur (-1,-1,LINES-COMMAND_WIN_LINES + 1,0);
326 strcpy (last_command_line,command_line); /* Save this command in our tiny cache */
328 /* And call dispatch to do the actual job */
329 quit=dispatch (command_line);
336 * This is a very important function. Its task is to recieve a command
337 * name and link it to a C function. There are three types of commands:
339 * 1. General commands - Always available and accessed through
341 * 2. Ext2 specific commands - Available when editing an ext2
342 * filesystem, accessed through ext2_commands.
343 * 3. Type specific commands - Those are changing according to the
344 * current type. The global variable current_type points to the
345 * current object definition (of type struct_descriptor). In it, the
346 * struct_commands entry contains the type specific commands links.
348 * Overriding is an important feature - Much like in C++ : The same
349 * command name can dispatch to different functions. The overriding
350 * priority is 3,2,1; That is - A type specific command will always
351 * override a general command. This is used through the program to
352 * allow fine tuned operation.
354 * When an handling function is found, it is called along with the
355 * command line that was passed to us. The handling function is then
356 * free to interpert the arguments in its own style.
358 int dispatch (char *command_line)
364 parse_word (command_line,command);
366 if (strcasecmp (command,"quit")==0) return (1);
368 /* 1. Search for type specific commands FIRST - Allows
369 overriding of a general command */
371 if (current_type != NULL)
373 i<=current_type->type_commands.last_command && !found;
375 if (strcasecmp (command,current_type->type_commands.names [i])==0) {
376 (*current_type->type_commands.callback [i]) (command_line);
381 /* 2. Now search for ext2 filesystem general commands */
384 for (i=0;i<=ext2_commands.last_command && !found;i++) {
385 if (strcasecmp (command,ext2_commands.names [i])==0) {
386 (*ext2_commands.callback [i]) (command_line);
392 /* 3. If not found, search the general commands */
395 for (i=0;i<=general_commands.last_command && !found;i++) {
396 if (strcasecmp (command,general_commands.names [i])==0) {
397 (*general_commands.callback [i]) (command_line);
402 /* 4. If not found, issue an error message and return */
405 wprintw (command_win,"Error: Unknown command\n");
406 refresh_command_win ();
415 * This function copies the next word in source to the variable dest,
416 * ignoring whitespaces. It returns a pointer to the next word in
417 * source. It is used to split the command line into command and arguments.
419 char *parse_word (char *source,char *dest)
421 char ch,*source_ptr,*target_ptr;
428 source_ptr=source;target_ptr=dest;
431 } while (! (ch>' ' && ch<='z') && ch!=0);
433 while (ch>' ' && ch<='z') {
443 } while (! (ch>' ' && ch<='z') && ch!=0);
445 return (--source_ptr);
449 * text is the partial command entered by the user; We assume that it
450 * is a part of a command - I didn't write code for smarter completion.
452 * The state variable is an index which tells us how many possible
453 * completions we already returned to readline.
455 * We return only one possible completion or (char *) NULL if there
456 * are no more completions. This function will be called by readline
457 * over and over until we tell it to stop.
459 * While scanning for possible completions, we use the same priority
460 * definition which was used in dispatch.
463 char *complete_command (char *text,int state)
470 /* Is the command type specific ? */
472 if (current_type != NULL)
473 for (i=0;i<=current_type->type_commands.last_command;i++) {
474 if (strncmp (current_type->type_commands.names [i],text,len)==0) {
476 if (state==state_index) {
477 return (dupstr (current_type->type_commands.names [i]));
482 /* No, pehaps ext2 specific command then ? */
484 for (i=0;i<=ext2_commands.last_command;i++) {
485 if (strncmp (ext2_commands.names [i],text,len)==0) {
487 if (state==state_index)
488 return (dupstr (ext2_commands.names [i]));
493 /* Check for a general command */
495 for (i=0;i<=general_commands.last_command;i++) {
496 if (strncmp (general_commands.names [i],text,len)==0) {
498 if (state==state_index)
499 return (dupstr (general_commands.names [i]));
503 /* quit is handled differently */
505 if (strncmp ("quit",text,len)==0) {
507 if (state==state_index)
508 return (dupstr ("quit"));
511 /* No more completions */
513 return ((char *) NULL);
519 * Nothing special - Just allocates enough space and copy the string.
521 char *dupstr (char *src)
525 ptr=(char *) malloc (strlen (src)+1);
532 * This function reports an internal error. It is almost not used. One
533 * place in which I do check for internal errors is disk.c.
535 * We just report the error, and try to continue ...
537 void internal_error (char *description,char *source_name,char *function_name)
539 wprintw (command_win,"Internal error - Found by source: %s.c , function: %s\n",source_name,function_name);
540 wprintw (command_win,"\t%s\n",description);
541 wprintw (command_win,"Press enter to (hopefully) continue\n");
542 refresh_command_win ();getch ();werase (command_win);