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 | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 25 | #include <stdio.h> |
| 26 | #include <stdlib.h> |
| 27 | #include <string.h> |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 28 | #include <signal.h> |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 29 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 30 | #ifdef HAVE_READLINE |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 31 | #include <readline.h> |
| 32 | #include <history.h> |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 33 | #endif |
| 34 | |
| 35 | #ifdef HAVE_GETOPT_H |
| 36 | #include <getopt.h> |
| 37 | #else |
| 38 | extern int optind; |
| 39 | extern char *optarg; |
| 40 | #endif |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 41 | |
| 42 | #include "ext2ed.h" |
| 43 | |
| 44 | /* Global variables */ |
| 45 | |
| 46 | /* |
| 47 | |
| 48 | Configuration file options |
| 49 | |
| 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. |
| 52 | |
| 53 | */ |
| 54 | |
| 55 | |
| 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 */ |
| 67 | |
| 68 | char last_command_line [80]; /* A simple one command cache, in addition to the readline history */ |
| 69 | |
| 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 */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 74 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 75 | int mounted=0; /* This is set when we find that the filesystem is mounted */ |
| 76 | |
| 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 */ |
| 87 | |
| 88 | int redraw_request=0; /* Is set by a signal handler to handle terminal */ |
| 89 | /* screen size change. */ |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 90 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 91 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 92 | /* |
| 93 | * We just call the parser to get commands from the user. We quit when |
| 94 | * parser returns. |
| 95 | */ |
| 96 | int main (int argc, char **argv) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 97 | { |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 98 | int write_priv = 0; |
| 99 | int c; |
| 100 | char *buf; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 101 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 102 | if (!init ()) |
| 103 | return (1); |
| 104 | while ((c = getopt (argc, argv, "w")) != EOF) { |
| 105 | switch (c) { |
| 106 | case 'w': |
| 107 | write_priv++; |
| 108 | break; |
| 109 | } |
| 110 | } |
| 111 | if (optind < argc) { |
| 112 | buf = malloc(strlen(argv[optind]) + 32); |
| 113 | if (!buf) { |
| 114 | fprintf(stderr, "Couldn't allocate filename buffer\n"); |
| 115 | exit(1); |
| 116 | } |
| 117 | strcpy(buf, "set_device "); |
| 118 | strcat(buf, argv[optind]); |
| 119 | set_device(buf); |
| 120 | free(buf); |
| 121 | if (write_priv) { |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 122 | wprintw (command_win,"\n"); |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 123 | enable_write("enable_write"); |
| 124 | } |
| 125 | } |
| 126 | parser (); /* Get and parse user commands */ |
| 127 | prepare_to_close(); /* Do some cleanup */ |
| 128 | printf("Quitting ...\n"); |
| 129 | return(0); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 133 | /* |
| 134 | * Read a character from the command window |
| 135 | */ |
| 136 | int command_read_key() |
| 137 | { |
| 138 | int key = 0; |
| 139 | |
| 140 | while (!key) { |
| 141 | if (redraw_request) { |
| 142 | redraw_all(); |
| 143 | redraw_request=0; |
| 144 | } |
| 145 | key = wgetch(command_win); |
| 146 | switch (key) { |
| 147 | case 0x1A: |
| 148 | key = 0; |
| 149 | kill(getpid(), SIGTSTP); |
| 150 | break; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 151 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 152 | case KEY_NPAGE: |
| 153 | pgdn(""); |
| 154 | refresh_command_win (); |
| 155 | break; |
| 156 | |
| 157 | case KEY_PPAGE: |
| 158 | pgup(""); |
| 159 | refresh_command_win (); |
| 160 | break; |
| 161 | case ERR: |
| 162 | key = 0; |
| 163 | break; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 164 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 165 | case KEY_BACKSPACE: |
| 166 | key = '\b'; |
| 167 | } |
| 168 | if ((key < 32 && key != '\b' && key != '\n') || |
| 169 | (key > 127)) |
| 170 | key = 0; |
| 171 | } |
| 172 | return key; |
| 173 | } |
| 174 | |
| 175 | #ifdef HAVE_READLINE |
| 176 | int rl_getc_replacement(FILE *f) |
| 177 | { |
| 178 | int key = command_read_key(); |
| 179 | |
| 180 | if (key == '\b') { |
| 181 | if (rl_point > 0) |
| 182 | wprintw(command_win, "\b \b"); |
| 183 | } else |
| 184 | wprintw(command_win, "%c", key); |
| 185 | return key; |
| 186 | } |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 187 | |
| 188 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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. |
| 195 | */ |
| 196 | void parser (void) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 197 | { |
| 198 | char *ptr,command_line [80]; |
| 199 | int quit=0; |
| 200 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 201 | #if 0 |
| 202 | noecho(); |
| 203 | cbreak(); |
| 204 | keypad(command_win, 1); |
| 205 | wtimeout(command_win, 100); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 206 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 207 | rl_getc_function = rl_getc_replacement; |
| 208 | #endif |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 209 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 210 | while (!quit) { |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 211 | /* Terminal screen size has changed */ |
| 212 | if (redraw_request) { |
| 213 | redraw_all(); |
| 214 | redraw_request=0; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 215 | } |
| 216 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 217 | wmove (command_win,0,0); |
| 218 | wclrtoeol (command_win); |
| 219 | wprintw (command_win,"ext2ed > "); |
| 220 | refresh_command_win (); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 221 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 222 | /* |
| 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 |
| 228 | * time. |
| 229 | */ |
| 230 | mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 231 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 232 | /* echo (); */ |
| 233 | ptr=readline ("ext2ed > "); |
| 234 | /* noecho (); */ |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 235 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 236 | /* |
| 237 | * Readline allocated the buffer - Copy the string |
| 238 | * and free the allocated buffer |
| 239 | * XXX WHY??? |
| 240 | */ |
| 241 | strcpy (command_line,ptr); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 242 | free (ptr); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 243 | |
| 244 | if (*command_line != 0) |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 245 | add_history (command_line); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 246 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 247 | /* If only enter was pressed, recall the last command */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 248 | if (*command_line==0) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 249 | strcpy (command_line,last_command_line); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 250 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 251 | /* Emulate readline's actions for ncurses */ |
| 252 | mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 253 | werase (command_win); |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 254 | wprintw (command_win,"ext2ed > "); |
| 255 | wprintw (command_win,command_line); |
| 256 | wprintw (command_win,"\n"); |
| 257 | refresh_command_win (); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 258 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 259 | /* Save this command in our tiny cache */ |
| 260 | strcpy (last_command_line,command_line); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 261 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 262 | /* And call dispatch to do the actual job */ |
| 263 | quit=dispatch (command_line); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 264 | } |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 265 | } |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 266 | #else |
| 267 | void read_line(char * foo) { |
| 268 | char * chptr = foo; |
| 269 | int ch; |
| 270 | int done = 0; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 271 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 272 | while (!done && (ch = command_read_key())) { |
| 273 | switch (ch) { |
| 274 | case '\n': |
| 275 | done = 1; |
| 276 | break; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 277 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 278 | case '\b': |
| 279 | if (chptr > foo) { |
| 280 | wprintw(command_win, "\b \b"); |
| 281 | chptr--; |
| 282 | } |
| 283 | break; |
| 284 | |
| 285 | default: |
| 286 | if (ch > 256) |
| 287 | break; |
| 288 | if (ch == '\n') break; |
| 289 | *chptr++ = ch; |
| 290 | wprintw(command_win, "%c", ch); |
| 291 | break; |
| 292 | } |
| 293 | } |
| 294 | *chptr = '\0'; |
| 295 | } |
| 296 | |
| 297 | void parser (void) |
| 298 | { |
| 299 | char command_line [80]; |
| 300 | int quit=0; |
| 301 | |
| 302 | noecho(); |
| 303 | cbreak(); |
| 304 | wtimeout(command_win, 100); |
| 305 | keypad(command_win, 1); |
| 306 | |
| 307 | while (!quit) { |
| 308 | /* Terminal screen size has changed */ |
| 309 | if (redraw_request) { |
| 310 | redraw_all(); |
| 311 | redraw_request=0; |
| 312 | } |
| 313 | |
| 314 | wmove (command_win,0,0);wclrtoeol (command_win); |
| 315 | |
| 316 | wmove(command_win, 0, 0); |
| 317 | wprintw(command_win, "ext2ed > "); |
| 318 | read_line(command_line); |
| 319 | |
| 320 | /* If only enter was pressed, recall the last command */ |
| 321 | if (*command_line==0) |
| 322 | strcpy (command_line,last_command_line); |
| 323 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 324 | mvcur (-1,-1,LINES-COMMAND_WIN_LINES + 1,0); |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 325 | |
| 326 | 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] | 327 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 328 | /* And call dispatch to do the actual job */ |
| 329 | quit=dispatch (command_line); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 330 | } |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 331 | } |
| 332 | #endif |
| 333 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 334 | |
| 335 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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: |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 338 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 339 | * 1. General commands - Always available and accessed through |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 340 | * general_commands. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 341 | * 2. Ext2 specific commands - Available when editing an ext2 |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 342 | * filesystem, accessed through ext2_commands. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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 |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 346 | * struct_commands entry contains the type specific commands links. |
| 347 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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 |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 352 | * allow fine tuned operation. |
| 353 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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 |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 356 | * free to interpert the arguments in its own style. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 357 | */ |
| 358 | int dispatch (char *command_line) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 359 | { |
| 360 | int i,found=0; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 361 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 362 | char command [80]; |
| 363 | |
| 364 | parse_word (command_line,command); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 365 | |
| 366 | if (strcasecmp (command,"quit")==0) return (1); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 367 | |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 368 | /* 1. Search for type specific commands FIRST - Allows |
| 369 | overriding of a general command */ |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 370 | |
| 371 | if (current_type != NULL) |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 372 | for (i=0; |
| 373 | i<=current_type->type_commands.last_command && !found; |
| 374 | i++) { |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 375 | if (strcasecmp (command,current_type->type_commands.names [i])==0) { |
| 376 | (*current_type->type_commands.callback [i]) (command_line); |
| 377 | found=1; |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | /* 2. Now search for ext2 filesystem general commands */ |
| 382 | |
| 383 | if (!found) |
| 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); |
| 387 | found=1; |
| 388 | } |
| 389 | } |
| 390 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 391 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 392 | /* 3. If not found, search the general commands */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 393 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 394 | if (!found) |
| 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); |
| 398 | found=1; |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | /* 4. If not found, issue an error message and return */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 403 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 404 | if (!found) { |
| 405 | wprintw (command_win,"Error: Unknown command\n"); |
| 406 | refresh_command_win (); |
| 407 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 408 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 409 | return (0); |
| 410 | } |
| 411 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 412 | |
| 413 | /* |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 414 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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. |
| 418 | */ |
| 419 | char *parse_word (char *source,char *dest) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 420 | { |
| 421 | char ch,*source_ptr,*target_ptr; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 422 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 423 | if (*source==0) { |
| 424 | *dest=0; |
| 425 | return (source); |
| 426 | }; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 427 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 428 | source_ptr=source;target_ptr=dest; |
| 429 | do { |
| 430 | ch=*source_ptr++; |
| 431 | } while (! (ch>' ' && ch<='z') && ch!=0); |
| 432 | |
| 433 | while (ch>' ' && ch<='z') { |
| 434 | *target_ptr++=ch; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 435 | ch=*source_ptr++; |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 436 | } |
| 437 | |
| 438 | *target_ptr=0; |
| 439 | |
| 440 | source_ptr--; |
| 441 | do { |
| 442 | ch=*source_ptr++; |
| 443 | } while (! (ch>' ' && ch<='z') && ch!=0); |
| 444 | |
| 445 | return (--source_ptr); |
| 446 | } |
| 447 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 448 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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. |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 451 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 452 | * 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] | 453 | * completions we already returned to readline. |
| 454 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 455 | * We return only one possible completion or (char *) NULL if there |
| 456 | * are no more completions. This function will be called by readline |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 457 | * over and over until we tell it to stop. |
| 458 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 459 | * While scanning for possible completions, we use the same priority |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 460 | * definition which was used in dispatch. |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 461 | */ |
| 462 | #if HAVE_READLINE |
| 463 | char *complete_command (char *text,int state) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 464 | { |
| 465 | int state_index=-1; |
| 466 | int i,len; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 467 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 468 | len=strlen (text); |
| 469 | |
| 470 | /* Is the command type specific ? */ |
| 471 | |
| 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) { |
| 475 | state_index++; |
| 476 | if (state==state_index) { |
| 477 | return (dupstr (current_type->type_commands.names [i])); |
| 478 | } |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | /* No, pehaps ext2 specific command then ? */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 483 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 484 | for (i=0;i<=ext2_commands.last_command;i++) { |
| 485 | if (strncmp (ext2_commands.names [i],text,len)==0) { |
| 486 | state_index++; |
| 487 | if (state==state_index) |
| 488 | return (dupstr (ext2_commands.names [i])); |
| 489 | } |
| 490 | } |
| 491 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 492 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 493 | /* Check for a general command */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 494 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 495 | for (i=0;i<=general_commands.last_command;i++) { |
| 496 | if (strncmp (general_commands.names [i],text,len)==0) { |
| 497 | state_index++; |
| 498 | if (state==state_index) |
| 499 | return (dupstr (general_commands.names [i])); |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | /* quit is handled differently */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 504 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 505 | if (strncmp ("quit",text,len)==0) { |
| 506 | state_index++; |
| 507 | if (state==state_index) |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 508 | return (dupstr ("quit")); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 509 | } |
| 510 | |
| 511 | /* No more completions */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 512 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 513 | return ((char *) NULL); |
| 514 | } |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 515 | #endif |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 516 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 517 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 518 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 519 | * Nothing special - Just allocates enough space and copy the string. |
| 520 | */ |
| 521 | char *dupstr (char *src) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 522 | { |
| 523 | char *ptr; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 524 | |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 525 | ptr=(char *) malloc (strlen (src)+1); |
| 526 | strcpy (ptr,src); |
| 527 | return (ptr); |
| 528 | } |
| 529 | |
| 530 | #ifdef DEBUG |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 531 | /* |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 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. |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 534 | * |
Theodore Ts'o | 5e941d2 | 2002-05-13 07:53:11 -0400 | [diff] [blame] | 535 | * We just report the error, and try to continue ... |
| 536 | */ |
| 537 | void internal_error (char *description,char *source_name,char *function_name) |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 538 | { |
| 539 | 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] | 540 | wprintw (command_win,"\t%s\n",description); |
Theodore Ts'o | 583a1ce | 2002-05-11 13:00:22 -0400 | [diff] [blame] | 541 | wprintw (command_win,"Press enter to (hopefully) continue\n"); |
| 542 | refresh_command_win ();getch ();werase (command_win); |
| 543 | } |
| 544 | |
Theodore Ts'o | 0f31c73 | 2002-05-11 13:03:25 -0400 | [diff] [blame] | 545 | #endif |