blob: 50a3f07f84e72c48bbc54368eeb48e89e848199d [file] [log] [blame]
Theodore Ts'o583a1ce2002-05-11 13:00:22 -04001/*
2
3/usr/src/ext2ed/main.c
4
5A part of the extended file system 2 disk editor.
6
7------------
8Main program
9------------
10
11This file mostly contains:
12
131. A list of global variables used through the entire program.
142. The parser, which asks the command line from the user.
153. The dispatcher, which analyzes the command line and calls the appropriate handler function.
164. A command pattern matcher which is used along with the readline completion feature.
175. A function which tells the user that an internal error has occured.
18
19First written on: March 30 1995
20
21Copyright (C) 1995 Gadi Oxman
22
23*/
Theodore Ts'o5e941d22002-05-13 07:53:11 -040024
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Theodore Ts'o5e941d22002-05-13 07:53:11 -040028#include <signal.h>
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040029
Theodore Ts'o5e941d22002-05-13 07:53:11 -040030#ifdef HAVE_READLINE
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040031#include <readline.h>
32#include <history.h>
Theodore Ts'o5e941d22002-05-13 07:53:11 -040033#endif
34
35#ifdef HAVE_GETOPT_H
36#include <getopt.h>
37#else
38extern int optind;
39extern char *optarg;
40#endif
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040041
42#include "ext2ed.h"
43
44/* Global variables */
45
46/*
47
48Configuration file options
49
50The following variables will be set by init.c to the values selected in the user configuration file.
51They are initialized below to some logical defaults.
52
53*/
54
55
56char Ext2Descriptors [200]="ext2.descriptors"; /* The location of the ext2 filesystem object definition */
57char AlternateDescriptors [200]=""; /* We allow the user to define additional structures */
58char LogFile [200]="ext2ed.log"; /* The location of the log file - Each write will be logged there */
59int LogChanges=1; /* 1 enables logging, 0 diables logging */
60int AllowChanges=0; /* When set, the enablewrite command will fail */
61int AllowMountedRead=0; /* Behavior when trying to open a mounted filesystem read-only */
62int ForceExt2=0; /* When set, ext2 autodetection is overridden */
63int DefaultBlockSize=1024;
64unsigned long DefaultTotalBlocks=2097151;
65unsigned long DefaultBlocksInGroup=8192; /* The default values are used when an ext2 filesystem is not */
66int ForceDefault=0; /* detected, or ForceDefault is set */
67
68char last_command_line [80]; /* A simple one command cache, in addition to the readline history */
69
70char device_name [80]; /* The location of the filesystem */
71FILE *device_handle=NULL; /* This is passed to the fopen / fread ... commands */
72long device_offset; /* The current position in the filesystem */
73 /* Note that we have a 2 GB limitation */
Theodore Ts'oefc6f622008-08-27 23:07:54 -040074
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040075int mounted=0; /* This is set when we find that the filesystem is mounted */
76
77struct struct_commands general_commands,ext2_commands; /* Used to define the general and ext2 commands */
78struct struct_descriptor *first_type,*last_type,*current_type; /* Used to access the double linked list */
79struct struct_type_data type_data; /* The current data is sometimes stored here */
80struct struct_file_system_info file_system_info; /* Essential information on the filesystem */
81struct struct_file_info file_info,first_file_info; /* Used by file_com.c to access files */
82struct struct_group_info group_info; /* Used by group_com.c */
83struct struct_super_info super_info; /* Used by super_com.c */
84struct struct_remember_lifo remember_lifo; /* A circular memory of objects */
85struct struct_block_bitmap_info block_bitmap_info; /* Used by blockbitmap_com.c */
86struct struct_inode_bitmap_info inode_bitmap_info; /* Used by inodebitmap_com.c */
87
88int redraw_request=0; /* Is set by a signal handler to handle terminal */
89 /* screen size change. */
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040090
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040091
Theodore Ts'o5e941d22002-05-13 07:53:11 -040092/*
93 * We just call the parser to get commands from the user. We quit when
94 * parser returns.
95 */
96int main (int argc, char **argv)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -040097{
Theodore Ts'o5e941d22002-05-13 07:53:11 -040098 int write_priv = 0;
99 int c;
100 char *buf;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400101
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400102 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'oefc6f622008-08-27 23:07:54 -0400122 wprintw (command_win,"\n");
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400123 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'o583a1ce2002-05-11 13:00:22 -0400130}
131
132
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400133/*
134 * Read a character from the command window
135 */
136int 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'oefc6f622008-08-27 23:07:54 -0400151
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400152 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'oefc6f622008-08-27 23:07:54 -0400164
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400165 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
176int 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'o583a1ce2002-05-11 13:00:22 -0400187
188/*
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400189 * 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 */
196void parser (void)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400197{
198 char *ptr,command_line [80];
199 int quit=0;
200
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400201#if 0
202 noecho();
203 cbreak();
204 keypad(command_win, 1);
205 wtimeout(command_win, 100);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400206
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400207 rl_getc_function = rl_getc_replacement;
208#endif
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400209
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400210 while (!quit) {
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400211 /* Terminal screen size has changed */
212 if (redraw_request) {
213 redraw_all();
214 redraw_request=0;
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400215 }
216
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400217 wmove (command_win,0,0);
218 wclrtoeol (command_win);
219 wprintw (command_win,"ext2ed > ");
220 refresh_command_win ();
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400221
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400222 /*
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'oefc6f622008-08-27 23:07:54 -0400231
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400232 /* echo (); */
233 ptr=readline ("ext2ed > ");
234 /* noecho (); */
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400235
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400236 /*
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'oefc6f622008-08-27 23:07:54 -0400242 free (ptr);
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400243
244 if (*command_line != 0)
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400245 add_history (command_line);
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400246
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400247 /* If only enter was pressed, recall the last command */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400248 if (*command_line==0)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400249 strcpy (command_line,last_command_line);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400250
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400251 /* Emulate readline's actions for ncurses */
252 mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0);
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400253 werase (command_win);
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400254 wprintw (command_win,"ext2ed > ");
255 wprintw (command_win,command_line);
256 wprintw (command_win,"\n");
257 refresh_command_win ();
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400258
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400259 /* Save this command in our tiny cache */
260 strcpy (last_command_line,command_line);
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400261
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400262 /* And call dispatch to do the actual job */
263 quit=dispatch (command_line);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400264 }
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400265}
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400266#else
267void read_line(char * foo) {
268 char * chptr = foo;
269 int ch;
270 int done = 0;
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400271
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400272 while (!done && (ch = command_read_key())) {
273 switch (ch) {
274 case '\n':
275 done = 1;
276 break;
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400277
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400278 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
297void 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'oefc6f622008-08-27 23:07:54 -0400324 mvcur (-1,-1,LINES-COMMAND_WIN_LINES + 1,0);
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400325
326 strcpy (last_command_line,command_line); /* Save this command in our tiny cache */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400327
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400328 /* And call dispatch to do the actual job */
329 quit=dispatch (command_line);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400330 }
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400331}
332#endif
333
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400334
335/*
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400336 * 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'oefc6f622008-08-27 23:07:54 -0400338 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400339 * 1. General commands - Always available and accessed through
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400340 * general_commands.
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400341 * 2. Ext2 specific commands - Available when editing an ext2
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400342 * filesystem, accessed through ext2_commands.
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400343 * 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'oefc6f622008-08-27 23:07:54 -0400346 * struct_commands entry contains the type specific commands links.
347 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400348 * 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'oefc6f622008-08-27 23:07:54 -0400352 * allow fine tuned operation.
353 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400354 * 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'oefc6f622008-08-27 23:07:54 -0400356 * free to interpert the arguments in its own style.
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400357 */
358int dispatch (char *command_line)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400359{
360 int i,found=0;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400361
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400362 char command [80];
363
364 parse_word (command_line,command);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400365
366 if (strcasecmp (command,"quit")==0) return (1);
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400367
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400368 /* 1. Search for type specific commands FIRST - Allows
369 overriding of a general command */
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400370
371 if (current_type != NULL)
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400372 for (i=0;
373 i<=current_type->type_commands.last_command && !found;
374 i++) {
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400375 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'oefc6f622008-08-27 23:07:54 -0400391
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400392 /* 3. If not found, search the general commands */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400393
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400394 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'oefc6f622008-08-27 23:07:54 -0400403
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400404 if (!found) {
405 wprintw (command_win,"Error: Unknown command\n");
406 refresh_command_win ();
407 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400408
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400409 return (0);
410}
411
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400412
413/*
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400414 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400415 * 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 */
419char *parse_word (char *source,char *dest)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400420{
421 char ch,*source_ptr,*target_ptr;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400422
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400423 if (*source==0) {
424 *dest=0;
425 return (source);
426 };
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400427
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400428 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'oefc6f622008-08-27 23:07:54 -0400435 ch=*source_ptr++;
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400436 }
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'o583a1ce2002-05-11 13:00:22 -0400448/*
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400449 * 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'oefc6f622008-08-27 23:07:54 -0400451 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400452 * The state variable is an index which tells us how many possible
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400453 * completions we already returned to readline.
454 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400455 * 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'oefc6f622008-08-27 23:07:54 -0400457 * over and over until we tell it to stop.
458 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400459 * While scanning for possible completions, we use the same priority
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400460 * definition which was used in dispatch.
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400461 */
462#if HAVE_READLINE
463char *complete_command (char *text,int state)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400464{
465 int state_index=-1;
466 int i,len;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400467
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400468 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'oefc6f622008-08-27 23:07:54 -0400483
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400484 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'oefc6f622008-08-27 23:07:54 -0400492
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400493 /* Check for a general command */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400494
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400495 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'oefc6f622008-08-27 23:07:54 -0400504
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400505 if (strncmp ("quit",text,len)==0) {
506 state_index++;
507 if (state==state_index)
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400508 return (dupstr ("quit"));
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400509 }
510
511 /* No more completions */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400512
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400513 return ((char *) NULL);
514}
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400515#endif
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400516
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400517
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400518/*
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400519 * Nothing special - Just allocates enough space and copy the string.
520 */
521char *dupstr (char *src)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400522{
523 char *ptr;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400524
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400525 ptr=(char *) malloc (strlen (src)+1);
526 strcpy (ptr,src);
527 return (ptr);
528}
529
530#ifdef DEBUG
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400531/*
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400532 * 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'oefc6f622008-08-27 23:07:54 -0400534 *
Theodore Ts'o5e941d22002-05-13 07:53:11 -0400535 * We just report the error, and try to continue ...
536 */
537void internal_error (char *description,char *source_name,char *function_name)
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400538{
539 wprintw (command_win,"Internal error - Found by source: %s.c , function: %s\n",source_name,function_name);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400540 wprintw (command_win,"\t%s\n",description);
Theodore Ts'o583a1ce2002-05-11 13:00:22 -0400541 wprintw (command_win,"Press enter to (hopefully) continue\n");
542 refresh_command_win ();getch ();werase (command_win);
543}
544
Theodore Ts'o0f31c732002-05-11 13:03:25 -0400545#endif