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