1/*
2
3/usr/src/ext2ed/init.c
4
5A part of the extended file system 2 disk editor.
6
7--------------------------------
8Various initialization routines.
9--------------------------------
10
11First written on: April 9 1995
12
13Copyright (C) 1995 Gadi Oxman
14
15*/
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#ifdef HAVE_READLINE
21#include <readline.h>
22#endif
23#include <signal.h>
24#include <unistd.h>
25
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29
30#include "ext2ed.h"
31
32char lines_s [80],cols_s [80];
33
34void signal_handler (void);
35
36void prepare_to_close (void)
37
38{
39	close_windows ();
40	if (device_handle!=NULL)
41		fclose (device_handle);
42	free_user_commands (&general_commands);
43	free_user_commands (&ext2_commands);
44	free_struct_descriptors ();
45}
46
47int init (void)
48
49{
50	printf ("Initializing ...\n");
51
52	if (!process_configuration_file ()) {
53		fprintf (stderr,"Error - Unable to complete configuration. Quitting.\n");
54		return (0);
55	};
56
57	general_commands.last_command=-1;	/* No commands whatsoever meanwhile */
58	ext2_commands.last_command=-1;
59	add_general_commands ();		/* Add the general commands, aviable always */
60	device_handle=NULL;			/* Notice that our device is still not set up */
61	device_offset=-1;
62	current_type=NULL;			/* No filesystem specific types yet */
63
64	remember_lifo.entries_count=0;		/* Object memory is empty */
65
66	init_windows ();			/* Initialize the NCURSES interface */
67	init_readline ();			/* Initialize the READLINE interface */
68	init_signals ();			/* Initialize the signal handlers */
69	write_access=0;				/* Write access disabled */
70
71	strcpy (last_command_line,"help");	/* Show the help screen to the user */
72	dispatch ("help");
73	return (1);				/* Success */
74}
75
76void add_general_commands (void)
77
78{
79	add_user_command (&general_commands,"help","EXT2ED help system",help);
80	add_user_command (&general_commands,"set","Changes a variable in the current object",set);
81	add_user_command (&general_commands,"setdevice","Selects the filesystem block device (e.g. /dev/hda1)",set_device);
82	add_user_command (&general_commands,"setoffset","Moves asynchronicly in the filesystem",set_offset);
83	add_user_command (&general_commands,"settype","Tells EXT2ED how to interpert the current object",set_type);
84	add_user_command (&general_commands,"show","Displays the current object",show);
85	add_user_command (&general_commands,"pgup","Scrolls data one page up",pgup);
86	add_user_command (&general_commands,"pgdn","Scrolls data one page down",pgdn);
87	add_user_command (&general_commands,"redraw","Redisplay the screen",redraw);
88	add_user_command (&general_commands,"remember","Saves the current position and data information",remember);
89	add_user_command (&general_commands,"recall","Gets back to the saved object position",recall);
90	add_user_command (&general_commands,"enablewrite","Enters Read/Write mode - Allows changing the filesystem",enable_write);
91	add_user_command (&general_commands,"disablewrite","Enters read only mode",disable_write);
92	add_user_command (&general_commands,"writedata","Write data back to disk",write_data);
93	add_user_command (&general_commands,"next","Moves to the next byte in hex mode",next);
94	add_user_command (&general_commands,"prev","Moves to the previous byte in hex mode",prev);
95}
96
97void add_ext2_general_commands (void)
98
99{
100	add_user_command (&ext2_commands,"super","Moves to the superblock of the filesystem",type_ext2___super);
101	add_user_command (&ext2_commands,"group","Moves to the first group descriptor",type_ext2___group);
102	add_user_command (&ext2_commands,"cd","Moves to the directory specified",type_ext2___cd);
103}
104
105int set_struct_descriptors (char *file_name)
106
107{
108	FILE *fp;
109	char current_line [500],current_word [50],*ch;
110	char variable_name [50],variable_type [20];
111	struct struct_descriptor *current_descriptor;
112
113	if ( (fp=fopen (file_name,"rt"))==NULL) {
114		wprintw (command_win,"Error - Failed to open descriptors file %s\n",file_name);
115		refresh_command_win ();	return (0);
116	};
117
118	while (!feof (fp)) {
119		fgets (current_line,500,fp);
120		if (feof (fp)) break;
121		ch=parse_word (current_line,current_word);
122		if (strcmp (current_word,"struct")==0) {
123			ch=parse_word (ch,current_word);
124			current_descriptor=add_new_descriptor (current_word);
125
126			while (strchr (current_line,'{')==NULL) {
127				fgets (current_line,500,fp);
128				if (feof (fp)) break;
129			};
130			if (feof (fp)) break;
131
132			fgets (current_line,500,fp);
133
134			while (strchr (current_line,'}')==NULL) {
135				while (strchr (current_line,';')==NULL) {
136					fgets (current_line,500,fp);
137					if (strchr (current_line,'}')!=NULL) break;
138				};
139				if (strchr (current_line,'}') !=NULL) break;
140				ch=parse_word (current_line,variable_type);
141				ch=parse_word (ch,variable_name);
142				while (variable_name [strlen (variable_name)-1]!=';') {
143					strcpy (variable_type,variable_name);
144					ch=parse_word (ch,variable_name);
145				};
146				variable_name [strlen (variable_name)-1]=0;
147				add_new_variable (current_descriptor,variable_type,variable_name);
148				fgets (current_line,500,fp);
149			};
150		};
151	};
152
153	fclose (fp);
154	return (1);
155}
156
157void free_struct_descriptors (void)
158
159{
160	struct struct_descriptor *ptr,*next;
161
162	ptr=first_type;
163	while (ptr!=NULL) {
164		next=ptr->next;
165		free_user_commands (&ptr->type_commands);
166		free (ptr);
167		ptr=next;
168	}
169	first_type=last_type=current_type=NULL;
170}
171
172void free_user_commands (struct struct_commands *ptr)
173
174{
175	int i;
176
177	for (i=0;i<=ptr->last_command;i++) {
178		free (ptr->names [i]);
179		free (ptr->descriptions [i]);
180	}
181
182	ptr->last_command=-1;
183}
184
185struct struct_descriptor *add_new_descriptor (char *name)
186
187{
188	struct struct_descriptor *ptr;
189
190	ptr = malloc (sizeof (struct struct_descriptor));
191	if (ptr == NULL) {
192		printf ("Error - Can not allocate memory - Quitting\n");
193		exit (1);
194	}
195	memset(ptr, 0, sizeof(struct struct_descriptor));
196	ptr->prev = ptr->next = NULL;
197	strcpy (ptr->name,name);
198	ptr->length=0;
199	ptr->fields_num=0;
200	if (first_type==NULL) {
201		first_type = last_type = ptr;
202	} else {
203		ptr->prev = last_type; last_type->next = ptr; last_type=ptr;
204	}
205	ptr->type_commands.last_command=-1;
206	fill_type_commands (ptr);
207	return (ptr);
208}
209
210struct type_table {
211	char 	*name;
212	int	field_type;
213	int	len;
214};
215
216struct type_table type_table[] = {
217	{ "long",   FIELD_TYPE_INT,	4 },
218	{ "short",  FIELD_TYPE_INT,	2 },
219	{ "char",   FIELD_TYPE_CHAR,	1 },
220	{ "__u32",  FIELD_TYPE_UINT,	4 },
221	{ "__s32",  FIELD_TYPE_INT,	4 },
222	{ "__u16",  FIELD_TYPE_UINT,	2 },
223	{ "__s16",  FIELD_TYPE_INT,	2 },
224	{ "__u8",   FIELD_TYPE_UINT,	1 },
225	{ "__s8",   FIELD_TYPE_INT,	1 },
226	{  0,       0,                  0 }
227};
228
229void add_new_variable (struct struct_descriptor *ptr,char *v_type,char *v_name)
230
231{
232	short	len=1;
233	char	field_type=FIELD_TYPE_INT;
234	struct type_table *p;
235
236	strcpy (ptr->field_names [ptr->fields_num],v_name);
237	ptr->field_positions [ptr->fields_num]=ptr->length;
238
239	for (p = type_table; p->name; p++) {
240		if (strcmp(v_type, p->name) == 0) {
241			len = p->len;
242			field_type = p->field_type;
243			break;
244		}
245	}
246	if (p->name == 0) {
247		if (strncmp(v_type, "char[", 5) == 0) {
248			len = atoi(v_type+5);
249			field_type = FIELD_TYPE_CHAR;
250		} else {
251			printf("Unknown type %s for field %s\n", v_type, v_name);
252			exit(1);
253		}
254	}
255
256	ptr->field_lengths [ptr->fields_num] = len;
257	ptr->field_types [ptr->fields_num] = field_type;
258
259	ptr->length+=len;
260	ptr->fields_num++;
261}
262
263void fill_type_commands (struct struct_descriptor *ptr)
264
265/*
266
267Set specific type user commands.
268
269*/
270
271{
272
273	if (strcmp ((ptr->name),"file")==0) {
274		add_user_command (&ptr->type_commands,"show","Shows file data",type_file___show);
275		add_user_command (&ptr->type_commands,"inode","Returns to the inode of the current file",type_file___inode);
276		add_user_command (&ptr->type_commands,"display","Specifies data format - text or hex",type_file___display);
277		add_user_command (&ptr->type_commands,"next","Pass to next byte",type_file___next);
278		add_user_command (&ptr->type_commands,"prev","Pass to the previous byte",type_file___prev);
279		add_user_command (&ptr->type_commands,"offset","Pass to a specified byte in the current block",type_file___offset);
280		add_user_command (&ptr->type_commands,"nextblock","Pass to next file block",type_file___nextblock);
281		add_user_command (&ptr->type_commands,"prevblock","Pass to the previous file block",type_file___prevblock);
282		add_user_command (&ptr->type_commands,"block","Specify which file block to edit",type_file___block);
283		add_user_command (&ptr->type_commands,"remember","Saves the file\'s inode position for later reference",type_file___remember);
284		add_user_command (&ptr->type_commands,"set","Sets the current byte",type_file___set);
285		add_user_command (&ptr->type_commands,"writedata","Writes the current block to the disk",type_file___writedata);
286	}
287
288	if (strcmp ((ptr->name),"ext2_inode")==0) {
289		add_user_command (&ptr->type_commands,"show","Shows inode data",type_ext2_inode___show);
290		add_user_command (&ptr->type_commands,"next","Move to next inode in current block group",type_ext2_inode___next);
291		add_user_command (&ptr->type_commands,"prev","Move to next inode in current block group",type_ext2_inode___prev);
292		add_user_command (&ptr->type_commands,"group","Move to the group descriptors of the current inode table",type_ext2_inode___group);
293		add_user_command (&ptr->type_commands,"entry","Move to a specified entry in the current inode table",type_ext2_inode___entry);
294		add_user_command (&ptr->type_commands,"file","Display file data of the current inode",type_ext2_inode___file);
295		add_user_command (&ptr->type_commands,"dir","Display directory data of the current inode",type_ext2_inode___dir);
296	}
297
298	if (strcmp ((ptr->name),"dir")==0) {
299		add_user_command (&ptr->type_commands,"show","Shows current directory data",type_dir___show);
300		add_user_command (&ptr->type_commands,"inode","Returns to the inode of the current directory",type_dir___inode);
301		add_user_command (&ptr->type_commands,"next","Pass to the next directory entry",type_dir___next);
302		add_user_command (&ptr->type_commands,"prev","Pass to the previous directory entry",type_dir___prev);
303		add_user_command (&ptr->type_commands,"followinode","Follows the inode specified in this directory entry",type_dir___followinode);
304		add_user_command (&ptr->type_commands,"remember","Remember the inode of the current directory entry",type_dir___remember);
305		add_user_command (&ptr->type_commands,"cd","Changes directory relative to the current directory",type_dir___cd);
306		add_user_command (&ptr->type_commands,"entry","Moves to a specified entry in the current directory",type_dir___entry);
307		add_user_command (&ptr->type_commands,"writedata","Writes the current entry to the disk",type_dir___writedata);
308		add_user_command (&ptr->type_commands,"set","Changes a variable in the current directory entry",type_dir___set);
309	}
310
311	if (strcmp ((ptr->name),"ext2_super_block")==0) {
312		add_user_command (&ptr->type_commands,"show","Displays the super block data",type_ext2_super_block___show);
313		add_user_command (&ptr->type_commands,"gocopy","Move to another backup copy of the superblock",type_ext2_super_block___gocopy);
314		add_user_command (&ptr->type_commands,"setactivecopy","Copies the current superblock to the main superblock",type_ext2_super_block___setactivecopy);
315	}
316
317	if (strcmp ((ptr->name),"ext2_group_desc")==0) {
318		add_user_command (&ptr->type_commands,"next","Pass to the next block group decriptor",type_ext2_group_desc___next);
319		add_user_command (&ptr->type_commands,"prev","Pass to the previous group descriptor",type_ext2_group_desc___prev);
320		add_user_command (&ptr->type_commands,"entry","Pass to a specific group descriptor",type_ext2_group_desc___entry);
321		add_user_command (&ptr->type_commands,"show","Shows the current group descriptor",type_ext2_group_desc___show);
322		add_user_command (&ptr->type_commands,"inode","Pass to the inode table of the current group block",type_ext2_group_desc___inode);
323		add_user_command (&ptr->type_commands,"gocopy","Move to another backup copy of the group descriptor",type_ext2_group_desc___gocopy);
324		add_user_command (&ptr->type_commands,"blockbitmap","Show the block allocation bitmap of the current group block",type_ext2_group_desc___blockbitmap);
325		add_user_command (&ptr->type_commands,"inodebitmap","Show the inode allocation bitmap of the current group block",type_ext2_group_desc___inodebitmap);
326		add_user_command (&ptr->type_commands,"setactivecopy","Copies the current group descriptor to the main table",type_ext2_super_block___setactivecopy);
327	}
328
329	if (strcmp ((ptr->name),"block_bitmap")==0) {
330		add_user_command (&ptr->type_commands,"show","Displays the block allocation bitmap",type_ext2_block_bitmap___show);
331		add_user_command (&ptr->type_commands,"entry","Moves to a specific bit",type_ext2_block_bitmap___entry);
332		add_user_command (&ptr->type_commands,"next","Moves to the next bit",type_ext2_block_bitmap___next);
333		add_user_command (&ptr->type_commands,"prev","Moves to the previous bit",type_ext2_block_bitmap___prev);
334		add_user_command (&ptr->type_commands,"allocate","Allocates the current block",type_ext2_block_bitmap___allocate);
335		add_user_command (&ptr->type_commands,"deallocate","Deallocates the current block",type_ext2_block_bitmap___deallocate);
336	}
337
338	if (strcmp ((ptr->name),"inode_bitmap")==0) {
339		add_user_command (&ptr->type_commands,"show","Displays the inode allocation bitmap",type_ext2_inode_bitmap___show);
340		add_user_command (&ptr->type_commands,"entry","Moves to a specific bit",type_ext2_inode_bitmap___entry);
341		add_user_command (&ptr->type_commands,"next","Moves to the next bit",type_ext2_inode_bitmap___next);
342		add_user_command (&ptr->type_commands,"prev","Moves to the previous bit",type_ext2_inode_bitmap___prev);
343		add_user_command (&ptr->type_commands,"allocate","Allocates the current inode",type_ext2_inode_bitmap___allocate);
344		add_user_command (&ptr->type_commands,"deallocate","Deallocates the current inode",type_ext2_inode_bitmap___deallocate);
345	}
346
347}
348
349void add_user_command (struct struct_commands *ptr,char *name,char *description,PF callback)
350
351{
352	int num;
353
354	num=ptr->last_command;
355	if (num+1==MAX_COMMANDS_NUM) {
356		printf ("Internal Error - Can't add command %s\n",name);
357		return;
358	}
359
360	ptr->last_command=++num;
361
362	ptr->names [num]=(char *) malloc (strlen (name)+1);
363	strcpy (ptr->names [num],name);
364
365	if (*description!=0) {
366		ptr->descriptions [num]=(char *) malloc (strlen (description)+1);
367		strcpy (ptr->descriptions [num],description);
368	}
369
370	ptr->callback [num]=callback;
371}
372
373static unsigned int div_ceil(unsigned int a, unsigned int b)
374{
375	if (!a)
376		return 0;
377	return ((a - 1) / b) + 1;
378}
379
380int set_file_system_info (void)
381
382{
383	int ext2_detected=0;
384	struct ext2_super_block *sb;
385
386	file_system_info.super_block_offset=1024;
387	file_system_info.file_system_size=DefaultTotalBlocks*DefaultBlockSize;
388
389	low_read ((char *) &file_system_info.super_block,sizeof (struct ext2_super_block),file_system_info.super_block_offset);
390
391	sb=&file_system_info.super_block;
392
393	if (sb->s_magic == EXT2_SUPER_MAGIC)
394		ext2_detected=1;
395
396	if (ext2_detected)
397		wprintw (command_win,"Detected extended 2 file system on device %s\n",device_name);
398	else
399		wprintw (command_win,"Warning - Extended 2 filesystem not detected on device %s\n",device_name);
400
401	if (!ext2_detected && !ForceExt2)
402		wprintw (command_win,"You may wish to use the configuration option ForceExt2 on\n");
403
404	if (ForceExt2 && !ext2_detected)
405		wprintw (command_win,"Forcing extended 2 filesystem\n");
406
407	if (ForceDefault || !ext2_detected)
408		wprintw (command_win,"Forcing default parameters\n");
409
410	refresh_command_win ();
411
412	if (ext2_detected || ForceExt2) {
413		add_ext2_general_commands ();
414		if (!set_struct_descriptors (Ext2Descriptors))
415			return (0);
416	}
417
418	if (!ForceDefault && ext2_detected) {
419
420		file_system_info.block_size=EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size;
421		if (file_system_info.block_size == EXT2_MIN_BLOCK_SIZE)
422			file_system_info.first_group_desc_offset=2*EXT2_MIN_BLOCK_SIZE;
423		else
424			file_system_info.first_group_desc_offset=file_system_info.block_size;
425		file_system_info.groups_count = div_ceil(sb->s_blocks_count,
426						 sb->s_blocks_per_group);
427
428		file_system_info.inodes_per_block=file_system_info.block_size/sizeof (struct ext2_inode);
429		file_system_info.blocks_per_group=sb->s_inodes_per_group/file_system_info.inodes_per_block;
430		file_system_info.no_blocks_in_group=sb->s_blocks_per_group;
431		file_system_info.file_system_size=(sb->s_blocks_count-1)*file_system_info.block_size;
432	}
433
434	else {
435		file_system_info.file_system_size=DefaultTotalBlocks*DefaultBlockSize;
436		file_system_info.block_size=DefaultBlockSize;
437		file_system_info.no_blocks_in_group=DefaultBlocksInGroup;
438	}
439
440	if (file_system_info.file_system_size > 2147483647) {
441		wprintw (command_win,"Sorry, filesystems bigger than 2 GB are currently not supported\n");
442		return (0);
443	}
444	return (1);
445}
446
447void init_readline (void)
448
449{
450#ifdef HAVE_READLINE
451	rl_completion_entry_function=(Function *) complete_command;
452#endif
453}
454
455void init_signals (void)
456
457{
458	signal (SIGWINCH, signal_SIGWINCH_handler);	/* Catch SIGWINCH */
459	signal (SIGTERM, signal_SIGTERM_handler);
460	signal (SIGSEGV, signal_SIGSEGV_handler);
461
462}
463
464void signal_SIGWINCH_handler (int sig_num)
465
466{
467	redraw_request=1;	/* We will handle it in main.c */
468
469	/* Reset signal handler */
470	signal (SIGWINCH, signal_SIGWINCH_handler);
471
472}
473
474void signal_SIGTERM_handler (int sig_num)
475
476{
477	prepare_to_close ();
478	printf ("Terminated due to signal %d\n",sig_num);
479	exit (1);
480}
481
482void signal_SIGSEGV_handler (int sig_num)
483
484{
485	prepare_to_close ();
486	printf ("Killed by signal %d!\n",sig_num);
487	exit (1);
488}
489
490int process_configuration_file (void)
491
492{
493	char buffer [300];
494	char option [80],value [80];
495	FILE *fp;
496
497	strcpy (buffer, ETC_DIR);
498	strcat (buffer,"/ext2ed.conf");
499
500	if ((fp=fopen (buffer,"rt"))==NULL) {
501		fprintf (stderr,"Error - Unable to open configuration file %s\n",buffer);
502		return (0);
503	}
504
505	while (get_next_option (fp,option,value)) {
506		if (strcasecmp (option,"Ext2Descriptors")==0) {
507			strcpy (Ext2Descriptors,value);
508		}
509
510		else if (strcasecmp (option,"AlternateDescriptors")==0) {
511			strcpy (AlternateDescriptors,value);
512		}
513
514		else if (strcasecmp (option,"LogFile")==0) {
515			strcpy (LogFile,value);
516		}
517
518		else if (strcasecmp (option,"LogChanges")==0) {
519			if (strcasecmp (value,"on")==0)
520				LogChanges = 1;
521			else if (strcasecmp (value,"off")==0)
522				LogChanges = 0;
523			else {
524				fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
525				fclose (fp);return (0);
526			}
527		}
528
529		else if (strcasecmp (option,"AllowChanges")==0) {
530			if (strcasecmp (value,"on")==0)
531				AllowChanges = 1;
532			else if (strcasecmp (value,"off")==0)
533				AllowChanges = 0;
534			else {
535				fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
536				fclose (fp);return (0);
537			}
538		}
539
540		else if (strcasecmp (option,"AllowMountedRead")==0) {
541			if (strcasecmp (value,"on")==0)
542				AllowMountedRead = 1;
543			else if (strcasecmp (value,"off")==0)
544				AllowMountedRead = 0;
545			else {
546				fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
547				fclose (fp);return (0);
548			}
549		}
550
551		else if (strcasecmp (option,"ForceExt2")==0) {
552			if (strcasecmp (value,"on")==0)
553				ForceExt2 = 1;
554			else if (strcasecmp (value,"off")==0)
555				ForceExt2 = 0;
556			else {
557				fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
558				fclose (fp);return (0);
559			}
560		}
561
562		else if (strcasecmp (option,"DefaultBlockSize")==0) {
563			DefaultBlockSize = atoi (value);
564		}
565
566		else if (strcasecmp (option,"DefaultTotalBlocks")==0) {
567			DefaultTotalBlocks = strtoul (value,NULL,10);
568		}
569
570		else if (strcasecmp (option,"DefaultBlocksInGroup")==0) {
571			DefaultBlocksInGroup = strtoul (value,NULL,10);
572		}
573
574		else if (strcasecmp (option,"ForceDefault")==0) {
575			if (strcasecmp (value,"on")==0)
576				ForceDefault = 1;
577			else if (strcasecmp (value,"off")==0)
578				ForceDefault = 0;
579			else {
580				fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
581				fclose (fp);return (0);
582			}
583		}
584
585		else {
586			fprintf (stderr,"Error - Unknown option: %s\n",option);
587			fclose (fp);return (0);
588		}
589	}
590
591	printf ("Configuration completed\n");
592	fclose (fp);
593	return (1);
594}
595
596int get_next_option (FILE *fp,char *option,char *value)
597
598{
599	char *ptr;
600	char buffer [600];
601
602	if (feof (fp)) return (0);
603	do{
604		if (feof (fp)) return (0);
605		fgets (buffer,500,fp);
606	} while (buffer [0]=='#' || buffer [0]=='\n');
607
608	ptr=parse_word (buffer,option);
609	ptr=parse_word (ptr,value);
610	return (1);
611}
612
613void check_mounted (char *name)
614
615{
616	FILE *fp;
617	char *ptr;
618	char current_line [500],current_word [200];
619
620	mounted=0;
621
622	if ( (fp=fopen ("/etc/mtab","rt"))==NULL) {
623		wprintw (command_win,"Error - Failed to open /etc/mtab. Assuming filesystem is mounted.\n");
624		refresh_command_win ();mounted=1;return;
625	};
626
627	while (!feof (fp)) {
628		fgets (current_line,500,fp);
629		if (feof (fp)) break;
630		ptr=parse_word (current_line,current_word);
631		if (strcasecmp (current_word,name)==0) {
632			mounted=1;fclose (fp);return;
633		}
634	};
635
636	fclose (fp);
637
638	return;
639}
640