Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 1 | /* |
| 2 | |
| 3 | /usr/src/ext2ed/main.c |
| 4 | |
| 5 | A part of the extended file system 2 disk editor. |
| 6 | |
| 7 | ------------ |
| 8 | Main program |
| 9 | ------------ |
| 10 | |
| 11 | This file mostly contains: |
| 12 | |
| 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. |
| 18 | |
| 19 | First written on: March 30 1995 |
| 20 | |
| 21 | Copyright (C) 1995 Gadi Oxman |
| 22 | |
| 23 | */ |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 24 | |
Theodore Ts'o | d1154eb | 2011-09-18 17:34:37 -0400 | [diff] [blame] | 25 | #include "config.h" |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 26 | #include <stdio.h> |
| 27 | #include <stdlib.h> |
| 28 | #include <string.h> |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 29 | #include <signal.h> |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 30 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 31 | #ifdef HAVE_READLINE |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 32 | #include <readline.h> |
| 33 | #include <history.h> |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 34 | #endif |
| 35 | |
| 36 | #ifdef HAVE_GETOPT_H |
| 37 | #include <getopt.h> |
| 38 | #else |
| 39 | extern int optind; |
| 40 | extern char *optarg; |
| 41 | #endif |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 42 | |
| 43 | #include "ext2ed.h" |
| 44 | |
| 45 | /* Global variables */ |
| 46 | |
| 47 | /* |
| 48 | |
| 49 | Configuration file options |
| 50 | |
| 51 | The following variables will be set by init.c to the values selected in the user configuration file. |
| 52 | They are initialized below to some logical defaults. |
| 53 | |
| 54 | */ |
| 55 | |
| 56 | |
| 57 | char Ext2Descriptors [200]="ext2.descriptors"; /* The location of the ext2 filesystem object definition */ |
| 58 | char AlternateDescriptors [200]=""; /* We allow the user to define additional structures */ |
| 59 | char LogFile [200]="ext2ed.log"; /* The location of the log file - Each write will be logged there */ |
| 60 | int LogChanges=1; /* 1 enables logging, 0 diables logging */ |
| 61 | int AllowChanges=0; /* When set, the enablewrite command will fail */ |
| 62 | int AllowMountedRead=0; /* Behavior when trying to open a mounted filesystem read-only */ |
| 63 | int ForceExt2=0; /* When set, ext2 autodetection is overridden */ |
| 64 | int DefaultBlockSize=1024; |
| 65 | unsigned long DefaultTotalBlocks=2097151; |
| 66 | unsigned long DefaultBlocksInGroup=8192; /* The default values are used when an ext2 filesystem is not */ |
| 67 | int ForceDefault=0; /* detected, or ForceDefault is set */ |
| 68 | |
| 69 | char last_command_line [80]; /* A simple one command cache, in addition to the readline history */ |
| 70 | |
| 71 | char device_name [80]; /* The location of the filesystem */ |
| 72 | FILE *device_handle=NULL; /* This is passed to the fopen / fread ... commands */ |
| 73 | long device_offset; /* The current position in the filesystem */ |
| 74 | /* Note that we have a 2 GB limitation */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 75 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 76 | int mounted=0; /* This is set when we find that the filesystem is mounted */ |
| 77 | |
| 78 | struct struct_commands general_commands,ext2_commands; /* Used to define the general and ext2 commands */ |
| 79 | struct struct_descriptor *first_type,*last_type,*current_type; /* Used to access the double linked list */ |
| 80 | struct struct_type_data type_data; /* The current data is sometimes stored here */ |
| 81 | struct struct_file_system_info file_system_info; /* Essential information on the filesystem */ |
| 82 | struct struct_file_info file_info,first_file_info; /* Used by file_com.c to access files */ |
| 83 | struct struct_group_info group_info; /* Used by group_com.c */ |
| 84 | struct struct_super_info super_info; /* Used by super_com.c */ |
| 85 | struct struct_remember_lifo remember_lifo; /* A circular memory of objects */ |
| 86 | struct struct_block_bitmap_info block_bitmap_info; /* Used by blockbitmap_com.c */ |
| 87 | struct struct_inode_bitmap_info inode_bitmap_info; /* Used by inodebitmap_com.c */ |
| 88 | |
| 89 | int redraw_request=0; /* Is set by a signal handler to handle terminal */ |
| 90 | /* screen size change. */ |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 91 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 92 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 93 | /* |
| 94 | * We just call the parser to get commands from the user. We quit when |
| 95 | * parser returns. |
| 96 | */ |
| 97 | int main (int argc, char **argv) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 98 | { |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 99 | int write_priv = 0; |
| 100 | int c; |
| 101 | char *buf; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 102 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 103 | if (!init ()) |
| 104 | return (1); |
| 105 | while ((c = getopt (argc, argv, "w")) != EOF) { |
| 106 | switch (c) { |
| 107 | case 'w': |
| 108 | write_priv++; |
| 109 | break; |
| 110 | } |
| 111 | } |
| 112 | if (optind < argc) { |
| 113 | buf = malloc(strlen(argv[optind]) + 32); |
| 114 | if (!buf) { |
| 115 | fprintf(stderr, "Couldn't allocate filename buffer\n"); |
| 116 | exit(1); |
| 117 | } |
| 118 | strcpy(buf, "set_device "); |
| 119 | strcat(buf, argv[optind]); |
| 120 | set_device(buf); |
| 121 | free(buf); |
| 122 | if (write_priv) { |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 123 | wprintw (command_win,"\n"); |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 124 | enable_write("enable_write"); |
| 125 | } |
| 126 | } |
| 127 | parser (); /* Get and parse user commands */ |
| 128 | prepare_to_close(); /* Do some cleanup */ |
| 129 | printf("Quitting ...\n"); |
| 130 | return(0); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 134 | /* |
| 135 | * Read a character from the command window |
| 136 | */ |
| 137 | int command_read_key() |
| 138 | { |
| 139 | int key = 0; |
| 140 | |
| 141 | while (!key) { |
| 142 | if (redraw_request) { |
| 143 | redraw_all(); |
| 144 | redraw_request=0; |
| 145 | } |
| 146 | key = wgetch(command_win); |
| 147 | switch (key) { |
| 148 | case 0x1A: |
| 149 | key = 0; |
| 150 | kill(getpid(), SIGTSTP); |
| 151 | break; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 152 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 153 | case KEY_NPAGE: |
| 154 | pgdn(""); |
| 155 | refresh_command_win (); |
| 156 | break; |
| 157 | |
| 158 | case KEY_PPAGE: |
| 159 | pgup(""); |
| 160 | refresh_command_win (); |
| 161 | break; |
| 162 | case ERR: |
| 163 | key = 0; |
| 164 | break; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 165 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 166 | case KEY_BACKSPACE: |
| 167 | key = '\b'; |
| 168 | } |
| 169 | if ((key < 32 && key != '\b' && key != '\n') || |
| 170 | (key > 127)) |
| 171 | key = 0; |
| 172 | } |
| 173 | return key; |
| 174 | } |
| 175 | |
| 176 | #ifdef HAVE_READLINE |
| 177 | int rl_getc_replacement(FILE *f) |
| 178 | { |
| 179 | int key = command_read_key(); |
| 180 | |
| 181 | if (key == '\b') { |
| 182 | if (rl_point > 0) |
| 183 | wprintw(command_win, "\b \b"); |
| 184 | } else |
| 185 | wprintw(command_win, "%c", key); |
| 186 | return key; |
| 187 | } |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 188 | |
| 189 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 190 | * This function asks the user for a command and calls the dispatcher |
| 191 | * function, dispatch, to analyze it. We use the readline library |
| 192 | * function readline to read the command, hence all the usual readline |
| 193 | * keys are available. The new command is saved both in the |
| 194 | * readline's history and in our tiny one-command cache, so that only |
| 195 | * the enter key is needed to retype it. |
| 196 | */ |
| 197 | void parser (void) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 198 | { |
| 199 | char *ptr,command_line [80]; |
| 200 | int quit=0; |
| 201 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 202 | #if 0 |
| 203 | noecho(); |
| 204 | cbreak(); |
| 205 | keypad(command_win, 1); |
| 206 | wtimeout(command_win, 100); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 207 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 208 | rl_getc_function = rl_getc_replacement; |
| 209 | #endif |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 210 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 211 | while (!quit) { |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 212 | /* Terminal screen size has changed */ |
| 213 | if (redraw_request) { |
| 214 | redraw_all(); |
| 215 | redraw_request=0; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 216 | } |
| 217 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 218 | wmove (command_win,0,0); |
| 219 | wclrtoeol (command_win); |
| 220 | wprintw (command_win,"ext2ed > "); |
| 221 | refresh_command_win (); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 222 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 223 | /* |
| 224 | * The ncurses library optimizes cursor movement by |
| 225 | * keeping track of the cursor position. However, by |
| 226 | * using the readline library I'm breaking its |
| 227 | * assumptions. The double -1 arguments tell ncurses |
| 228 | * to disable cursor movement optimization this |
| 229 | * time. |
| 230 | */ |
| 231 | mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 232 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 233 | /* echo (); */ |
| 234 | ptr=readline ("ext2ed > "); |
| 235 | /* noecho (); */ |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 236 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 237 | /* |
| 238 | * Readline allocated the buffer - Copy the string |
| 239 | * and free the allocated buffer |
| 240 | * XXX WHY??? |
| 241 | */ |
| 242 | strcpy (command_line,ptr); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 243 | free (ptr); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 244 | |
| 245 | if (*command_line != 0) |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 246 | add_history (command_line); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 247 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 248 | /* If only enter was pressed, recall the last command */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 249 | if (*command_line==0) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 250 | strcpy (command_line,last_command_line); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 251 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 252 | /* Emulate readline's actions for ncurses */ |
| 253 | mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 254 | werase (command_win); |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 255 | wprintw (command_win,"ext2ed > "); |
| 256 | wprintw (command_win,command_line); |
| 257 | wprintw (command_win,"\n"); |
| 258 | refresh_command_win (); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 259 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 260 | /* Save this command in our tiny cache */ |
| 261 | strcpy (last_command_line,command_line); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 262 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 263 | /* And call dispatch to do the actual job */ |
| 264 | quit=dispatch (command_line); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 265 | } |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 266 | } |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 267 | #else |
| 268 | void read_line(char * foo) { |
| 269 | char * chptr = foo; |
| 270 | int ch; |
| 271 | int done = 0; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 272 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 273 | while (!done && (ch = command_read_key())) { |
| 274 | switch (ch) { |
| 275 | case '\n': |
| 276 | done = 1; |
| 277 | break; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 278 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 279 | case '\b': |
| 280 | if (chptr > foo) { |
| 281 | wprintw(command_win, "\b \b"); |
| 282 | chptr--; |
| 283 | } |
| 284 | break; |
| 285 | |
| 286 | default: |
| 287 | if (ch > 256) |
| 288 | break; |
| 289 | if (ch == '\n') break; |
| 290 | *chptr++ = ch; |
| 291 | wprintw(command_win, "%c", ch); |
| 292 | break; |
| 293 | } |
| 294 | } |
| 295 | *chptr = '\0'; |
| 296 | } |
| 297 | |
| 298 | void parser (void) |
| 299 | { |
| 300 | char command_line [80]; |
| 301 | int quit=0; |
| 302 | |
| 303 | noecho(); |
| 304 | cbreak(); |
| 305 | wtimeout(command_win, 100); |
| 306 | keypad(command_win, 1); |
| 307 | |
| 308 | while (!quit) { |
| 309 | /* Terminal screen size has changed */ |
| 310 | if (redraw_request) { |
| 311 | redraw_all(); |
| 312 | redraw_request=0; |
| 313 | } |
| 314 | |
| 315 | wmove (command_win,0,0);wclrtoeol (command_win); |
| 316 | |
| 317 | wmove(command_win, 0, 0); |
| 318 | wprintw(command_win, "ext2ed > "); |
| 319 | read_line(command_line); |
| 320 | |
| 321 | /* If only enter was pressed, recall the last command */ |
| 322 | if (*command_line==0) |
| 323 | strcpy (command_line,last_command_line); |
| 324 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 325 | mvcur (-1,-1,LINES-COMMAND_WIN_LINES + 1,0); |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 326 | |
| 327 | strcpy (last_command_line,command_line); /* Save this command in our tiny cache */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 328 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 329 | /* And call dispatch to do the actual job */ |
| 330 | quit=dispatch (command_line); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 331 | } |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 332 | } |
| 333 | #endif |
| 334 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 335 | |
| 336 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 337 | * This is a very important function. Its task is to recieve a command |
| 338 | * name and link it to a C function. There are three types of commands: |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 339 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 340 | * 1. General commands - Always available and accessed through |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 341 | * general_commands. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 342 | * 2. Ext2 specific commands - Available when editing an ext2 |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 343 | * filesystem, accessed through ext2_commands. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 344 | * 3. Type specific commands - Those are changing according to the |
| 345 | * current type. The global variable current_type points to the |
| 346 | * current object definition (of type struct_descriptor). In it, the |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 347 | * struct_commands entry contains the type specific commands links. |
| 348 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 349 | * Overriding is an important feature - Much like in C++ : The same |
| 350 | * command name can dispatch to different functions. The overriding |
| 351 | * priority is 3,2,1; That is - A type specific command will always |
| 352 | * override a general command. This is used through the program to |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 353 | * allow fine tuned operation. |
| 354 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 355 | * When an handling function is found, it is called along with the |
| 356 | * command line that was passed to us. The handling function is then |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 357 | * free to interpert the arguments in its own style. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 358 | */ |
| 359 | int dispatch (char *command_line) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 360 | { |
| 361 | int i,found=0; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 362 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 363 | char command [80]; |
| 364 | |
| 365 | parse_word (command_line,command); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 366 | |
| 367 | if (strcasecmp (command,"quit")==0) return (1); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 368 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 369 | /* 1. Search for type specific commands FIRST - Allows |
| 370 | overriding of a general command */ |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 371 | |
| 372 | if (current_type != NULL) |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 373 | for (i=0; |
| 374 | i<=current_type->type_commands.last_command && !found; |
| 375 | i++) { |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 376 | if (strcasecmp (command,current_type->type_commands.names [i])==0) { |
| 377 | (*current_type->type_commands.callback [i]) (command_line); |
| 378 | found=1; |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | /* 2. Now search for ext2 filesystem general commands */ |
| 383 | |
| 384 | if (!found) |
| 385 | for (i=0;i<=ext2_commands.last_command && !found;i++) { |
| 386 | if (strcasecmp (command,ext2_commands.names [i])==0) { |
| 387 | (*ext2_commands.callback [i]) (command_line); |
| 388 | found=1; |
| 389 | } |
| 390 | } |
| 391 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 392 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 393 | /* 3. If not found, search the general commands */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 394 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 395 | if (!found) |
| 396 | for (i=0;i<=general_commands.last_command && !found;i++) { |
| 397 | if (strcasecmp (command,general_commands.names [i])==0) { |
| 398 | (*general_commands.callback [i]) (command_line); |
| 399 | found=1; |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | /* 4. If not found, issue an error message and return */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 404 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 405 | if (!found) { |
| 406 | wprintw (command_win,"Error: Unknown command\n"); |
| 407 | refresh_command_win (); |
| 408 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 409 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 410 | return (0); |
| 411 | } |
| 412 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 413 | |
| 414 | /* |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 415 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 416 | * This function copies the next word in source to the variable dest, |
| 417 | * ignoring whitespaces. It returns a pointer to the next word in |
| 418 | * source. It is used to split the command line into command and arguments. |
| 419 | */ |
| 420 | char *parse_word (char *source,char *dest) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 421 | { |
| 422 | char ch,*source_ptr,*target_ptr; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 423 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 424 | if (*source==0) { |
| 425 | *dest=0; |
| 426 | return (source); |
| 427 | }; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 428 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 429 | source_ptr=source;target_ptr=dest; |
| 430 | do { |
| 431 | ch=*source_ptr++; |
| 432 | } while (! (ch>' ' && ch<='z') && ch!=0); |
| 433 | |
| 434 | while (ch>' ' && ch<='z') { |
| 435 | *target_ptr++=ch; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 436 | ch=*source_ptr++; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | *target_ptr=0; |
| 440 | |
| 441 | source_ptr--; |
| 442 | do { |
| 443 | ch=*source_ptr++; |
| 444 | } while (! (ch>' ' && ch<='z') && ch!=0); |
| 445 | |
| 446 | return (--source_ptr); |
| 447 | } |
| 448 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 449 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 450 | * text is the partial command entered by the user; We assume that it |
| 451 | * is a part of a command - I didn't write code for smarter completion. |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 452 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 453 | * The state variable is an index which tells us how many possible |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 454 | * completions we already returned to readline. |
| 455 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 456 | * We return only one possible completion or (char *) NULL if there |
| 457 | * are no more completions. This function will be called by readline |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 458 | * over and over until we tell it to stop. |
| 459 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 460 | * While scanning for possible completions, we use the same priority |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 461 | * definition which was used in dispatch. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 462 | */ |
| 463 | #if HAVE_READLINE |
| 464 | char *complete_command (char *text,int state) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 465 | { |
| 466 | int state_index=-1; |
| 467 | int i,len; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 468 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 469 | len=strlen (text); |
| 470 | |
| 471 | /* Is the command type specific ? */ |
| 472 | |
| 473 | if (current_type != NULL) |
| 474 | for (i=0;i<=current_type->type_commands.last_command;i++) { |
| 475 | if (strncmp (current_type->type_commands.names [i],text,len)==0) { |
| 476 | state_index++; |
| 477 | if (state==state_index) { |
| 478 | return (dupstr (current_type->type_commands.names [i])); |
| 479 | } |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | /* No, pehaps ext2 specific command then ? */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 484 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 485 | for (i=0;i<=ext2_commands.last_command;i++) { |
| 486 | if (strncmp (ext2_commands.names [i],text,len)==0) { |
| 487 | state_index++; |
| 488 | if (state==state_index) |
| 489 | return (dupstr (ext2_commands.names [i])); |
| 490 | } |
| 491 | } |
| 492 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 493 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 494 | /* Check for a general command */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 495 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 496 | for (i=0;i<=general_commands.last_command;i++) { |
| 497 | if (strncmp (general_commands.names [i],text,len)==0) { |
| 498 | state_index++; |
| 499 | if (state==state_index) |
| 500 | return (dupstr (general_commands.names [i])); |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | /* quit is handled differently */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 505 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 506 | if (strncmp ("quit",text,len)==0) { |
| 507 | state_index++; |
| 508 | if (state==state_index) |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 509 | return (dupstr ("quit")); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 510 | } |
| 511 | |
| 512 | /* No more completions */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 513 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 514 | return ((char *) NULL); |
| 515 | } |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 516 | #endif |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 517 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 518 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 519 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 520 | * Nothing special - Just allocates enough space and copy the string. |
| 521 | */ |
| 522 | char *dupstr (char *src) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 523 | { |
| 524 | char *ptr; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 525 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 526 | ptr=(char *) malloc (strlen (src)+1); |
| 527 | strcpy (ptr,src); |
| 528 | return (ptr); |
| 529 | } |
| 530 | |
| 531 | #ifdef DEBUG |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 532 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 533 | * This function reports an internal error. It is almost not used. One |
| 534 | * place in which I do check for internal errors is disk.c. |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 535 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 536 | * We just report the error, and try to continue ... |
| 537 | */ |
| 538 | void internal_error (char *description,char *source_name,char *function_name) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 539 | { |
| 540 | wprintw (command_win,"Internal error - Found by source: %s.c , function: %s\n",source_name,function_name); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 541 | wprintw (command_win,"\t%s\n",description); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 542 | wprintw (command_win,"Press enter to (hopefully) continue\n"); |
| 543 | refresh_command_win ();getch ();werase (command_win); |
| 544 | } |
| 545 | |
Theodore Ts'o | 0f31c73 | 2002-05-11 13:03:25 -0400 | [diff] [blame] | 546 | #endif |