2004-01-20 21:32:43 +03:00
/*
* Guillaume Cottenceau ( gc @ mandrakesoft . com )
*
* Copyright 2000 MandrakeSoft
*
* This software may be freely redistributed under the terms of the GNU
* public license .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*/
/*
* Portions from Erik Troan ( ewt @ redhat . com )
*
* Copyright 1996 Red Hat Software
*
*/
# include <stdlib.h>
# include <unistd.h>
# include <stdio.h>
# include <string.h>
# include <sys/mount.h>
# include <sys/stat.h>
# include <fcntl.h>
2004-12-13 01:22:50 +03:00
# include <errno.h>
2004-01-20 21:32:43 +03:00
# include "stage1.h"
# include "frontend.h"
# include "modules.h"
# include "probing.h"
# include "log.h"
# include "mount.h"
# include "lomount.h"
# include "automatic.h"
# include "disk.h"
2007-08-02 20:45:59 +04:00
extern char version [ ] ;
2004-01-20 21:32:43 +03:00
struct partition_detection_anchor {
off_t offset ;
const char * anchor ;
} ;
static int seek_and_compare ( int fd , struct partition_detection_anchor anch )
{
char buf [ 500 ] ;
int count ;
if ( lseek ( fd , anch . offset , SEEK_SET ) = = ( off_t ) - 1 ) {
log_perror ( " seek failed " ) ;
return - 1 ;
}
count = read ( fd , buf , strlen ( anch . anchor ) ) ;
if ( count ! = strlen ( anch . anchor ) ) {
log_perror ( " read failed " ) ;
return - 1 ;
}
buf [ count ] = ' \0 ' ;
if ( strcmp ( anch . anchor , buf ) )
return 1 ;
return 0 ;
}
static const char * detect_partition_type ( char * dev )
{
struct partition_detection_info {
const char * name ;
struct partition_detection_anchor anchor0 ;
struct partition_detection_anchor anchor1 ;
struct partition_detection_anchor anchor2 ;
2007-03-03 00:48:18 +03:00
} partitions_signatures [ ] = {
{ " Linux Swap " , { 4086 , " SWAP-SPACE " } , { 0 , NULL } , { 0 , NULL } } ,
{ " Linux Swap " , { 4086 , " SWAPSPACE2 " } , { 0 , NULL } , { 0 , NULL } } ,
{ " Ext2 " , { 0x438 , " \x53 \xEF " } , { 0 , NULL } , { 0 , NULL } } ,
{ " ReiserFS " , { 0x10034 , " ReIsErFs " } , { 0 , NULL } , { 0 , NULL } } ,
{ " ReiserFS " , { 0x10034 , " ReIsEr2Fs " } , { 0 , NULL } , { 0 , NULL } } ,
2004-01-20 21:32:43 +03:00
{ " XFS " , { 0 , " XFSB " } , { 0x200 , " XAGF " } , { 0x400 , " XAGI " } } ,
2007-03-03 00:48:18 +03:00
{ " JFS " , { 0x8000 , " JFS1 " } , { 0 , NULL } , { 0 , NULL } } ,
2004-01-20 21:32:43 +03:00
{ " NTFS " , { 0x1FE , " \x55 \xAA " } , { 0x3 , " NTFS " } , { 0 , NULL } } ,
{ " FAT32 " , { 0x1FE , " \x55 \xAA " } , { 0x52 , " FAT32 " } , { 0 , NULL } } ,
{ " FAT " , { 0x1FE , " \x55 \xAA " } , { 0x36 , " FAT " } , { 0 , NULL } } ,
{ " Linux LVM " , { 0 , " HM \1 \0 " } , { 0 , NULL } , { 0 , NULL } }
} ;
int partitions_signatures_nb = sizeof ( partitions_signatures ) / sizeof ( struct partition_detection_info ) ;
int i ;
int fd ;
char device_fullname [ 50 ] ;
strcpy ( device_fullname , " /dev/ " ) ;
strcat ( device_fullname , dev ) ;
if ( ensure_dev_exists ( device_fullname ) )
return NULL ;
log_message ( " guessing type of %s " , device_fullname ) ;
if ( ( fd = open ( device_fullname , O_RDONLY , 0 ) ) < 0 ) {
log_perror ( " open " ) ;
return NULL ;
}
for ( i = 0 ; i < partitions_signatures_nb ; i + + ) {
int results = seek_and_compare ( fd , partitions_signatures [ i ] . anchor0 ) ;
if ( results = = - 1 )
goto detect_partition_type_end ;
if ( results = = 1 )
continue ;
if ( ! partitions_signatures [ i ] . anchor1 . anchor )
goto detect_partition_found_it ;
results = seek_and_compare ( fd , partitions_signatures [ i ] . anchor1 ) ;
if ( results = = - 1 )
goto detect_partition_type_end ;
if ( results = = 1 )
continue ;
if ( ! partitions_signatures [ i ] . anchor2 . anchor )
goto detect_partition_found_it ;
results = seek_and_compare ( fd , partitions_signatures [ i ] . anchor2 ) ;
if ( results = = - 1 )
goto detect_partition_type_end ;
if ( results = = 1 )
continue ;
detect_partition_found_it :
return partitions_signatures [ i ] . name ;
}
detect_partition_type_end :
close ( fd ) ;
return NULL ;
}
static char * disk_extract_list_directory ( char * direct )
{
char * * full = list_directory ( direct ) ;
char tmp [ 2000 ] = " " ;
int i ;
for ( i = 0 ; i < 5 ; i + + ) {
if ( ! full | | ! * full )
break ;
strcat ( tmp , * full ) ;
strcat ( tmp , " \n " ) ;
full + + ;
}
return strdup ( tmp ) ;
}
2008-05-07 20:41:57 +04:00
static enum return_type try_with_partition ( char * choice ) ;
static enum return_type try_with_uuidlabel ( )
2004-01-20 21:32:43 +03:00
{
2008-05-07 20:41:57 +04:00
char device_fullname [ 64 ] ;
char devname [ 50 ] ;
struct stat statbuf ;
int len ;
strcpy ( device_fullname , " /dev/disk/by-uuid/ " ) ;
strcat ( device_fullname , get_auto_value ( " uuid " ) ) ;
if ( stat ( device_fullname , & statbuf ) = = 0 & & S_ISBLK ( statbuf . st_mode ) & &
( len = readlink ( device_fullname , devname , sizeof ( devname ) ) ) ! = - 1 ) {
devname [ len ] = 0 ;
return try_with_partition ( strrchr ( devname , ' / ' ) + 1 ) ;
}
strcpy ( device_fullname , " /dev/disk/by-label/ " ) ;
strcat ( device_fullname , get_auto_value ( " label " ) ) ;
if ( stat ( device_fullname , & statbuf ) = = 0 & & S_ISBLK ( statbuf . st_mode ) & &
( len = readlink ( device_fullname , devname , sizeof ( devname ) ) ) ! = - 1 ) {
devname [ len ] = 0 ;
return try_with_partition ( strrchr ( devname , ' / ' ) + 1 ) ;
}
return RETURN_ERROR ;
}
2004-01-20 21:32:43 +03:00
2008-05-07 20:41:57 +04:00
static enum return_type try_with_device ( char * dev_name )
{
2004-01-20 21:32:43 +03:00
int major , minor , blocks ;
char name [ 100 ] ;
char buf [ 512 ] ;
FILE * f ;
char * parts [ 50 ] ;
char * parts_comments [ 50 ] ;
int i = 0 ;
enum return_type results ;
char * choice ;
if ( ! ( f = fopen ( " /proc/partitions " , " rb " ) ) | | ! fgets ( buf , sizeof ( buf ) , f ) | | ! fgets ( buf , sizeof ( buf ) , f ) ) {
log_perror ( dev_name ) ;
stg1_error_message ( " Could not read partitions information. " ) ;
return RETURN_ERROR ;
}
while ( fgets ( buf , sizeof ( buf ) , f ) ) {
2008-03-15 23:59:16 +03:00
memset ( name , 0 , sizeof ( name ) ) ;
2004-01-20 21:32:43 +03:00
sscanf ( buf , " %d %d %d %s " , & major , & minor , & blocks , name ) ;
if ( ( strstr ( name , dev_name ) = = name ) & & ( blocks > 1 ) & & ( name [ strlen ( dev_name ) ] ! = ' \0 ' ) ) {
const char * partition_type = detect_partition_type ( name ) ;
parts [ i ] = strdup ( name ) ;
parts_comments [ i ] = ( char * ) malloc ( sizeof ( char ) * 100 ) ;
sprintf ( parts_comments [ i ] , " size: %d Mbytes " , blocks > > 10 ) ;
if ( partition_type ) {
strcat ( parts_comments [ i ] , " , type: " ) ;
strcat ( parts_comments [ i ] , partition_type ) ;
}
i + + ;
}
}
parts [ i ] = NULL ;
fclose ( f ) ;
if ( parts [ 0 ] = = NULL ) {
stg1_error_message ( " No partitions found. " ) ;
return RETURN_ERROR ;
}
2007-08-02 20:45:59 +04:00
snprintf ( buf , sizeof ( buf ) , " Please choose the partition where is copied the %s Distribution. " , version ) ;
results = ask_from_list_comments_auto ( buf , parts , parts_comments , & choice , " partition " , parts ) ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK )
return results ;
2008-05-07 20:41:57 +04:00
if ( try_with_partition ( choice ) ! = RETURN_OK )
return try_with_device ( dev_name ) ;
else
return RETURN_OK ;
}
static enum return_type try_with_partition ( char * choice )
{
char * questions_location [ ] = { " Directory or ISO image " , NULL } ;
char * questions_location_auto [ ] = { " directory " , NULL } ;
static char * * answers_location = NULL ;
char device_fullname [ 50 ] ;
char location_full [ 500 ] ;
char buf [ 512 ] ;
struct stat statbuf ;
int iso = 0 ;
2004-01-20 21:32:43 +03:00
strcpy ( device_fullname , " /dev/ " ) ;
strcat ( device_fullname , choice ) ;
2004-12-13 01:22:50 +03:00
if ( my_mount ( device_fullname , IMAGE_LOCATION , " ext2 " , 0 ) = = - 1 & &
2010-09-24 17:31:26 +04:00
my_mount ( device_fullname , IMAGE_LOCATION , " ext3 " , 0 ) = = - 1 & &
2004-12-13 01:22:50 +03:00
my_mount ( device_fullname , IMAGE_LOCATION , " vfat " , 0 ) = = - 1 & &
2005-03-02 20:48:28 +03:00
my_mount ( device_fullname , IMAGE_LOCATION , " ntfs " , 0 ) = = - 1 & &
2010-05-26 23:08:35 +04:00
my_mount ( device_fullname , IMAGE_LOCATION , " iso9660 " , 0 ) = = - 1 & &
2004-12-13 01:22:50 +03:00
my_mount ( device_fullname , IMAGE_LOCATION , " reiserfs " , 0 ) = = - 1 ) {
2010-09-24 17:31:26 +04:00
stg1_error_message ( " I can't find a valid filesystem (tried: ext2, ext3, vfat, ntfs, iso9660, reiserfs). " ) ;
2008-05-07 20:41:57 +04:00
return RETURN_ERROR ;
2004-01-20 21:32:43 +03:00
}
2007-08-02 20:45:59 +04:00
snprintf ( buf , sizeof ( buf ) , " Please enter the directory (or ISO image file) containing the %s Distribution. " , version ) ;
if ( ask_from_entries_auto ( buf , questions_location , & answers_location , 24 , questions_location_auto , NULL ) ! = RETURN_OK ) {
2004-12-13 01:22:50 +03:00
umount ( IMAGE_LOCATION ) ;
2008-05-07 20:41:57 +04:00
return RETURN_ERROR ;
2004-01-20 21:32:43 +03:00
}
2004-12-13 01:22:50 +03:00
strcpy ( location_full , IMAGE_LOCATION ) ;
2004-01-20 21:32:43 +03:00
strcat ( location_full , " / " ) ;
strcat ( location_full , answers_location [ 0 ] ) ;
if ( access ( location_full , R_OK ) ) {
stg1_error_message ( " Directory or ISO image file could not be found on partition. \n "
" Here's a short extract of the files in the root of the partition: \n "
2004-12-13 01:22:50 +03:00
" %s " , disk_extract_list_directory ( IMAGE_LOCATION ) ) ;
umount ( IMAGE_LOCATION ) ;
2008-05-07 20:41:57 +04:00
return RETURN_ERROR ;
2004-01-20 21:32:43 +03:00
}
if ( ! stat ( location_full , & statbuf ) & & ! S_ISDIR ( statbuf . st_mode ) ) {
log_message ( " %s exists and is not a directory, assuming this is an ISO image " , location_full ) ;
if ( lomount ( location_full , IMAGE_LOCATION ) ) {
2007-08-02 20:45:59 +04:00
stg1_error_message ( " Could not mount file %s as an ISO image of the %s Distribution. " , answers_location [ 0 ] , version ) ;
2004-12-13 01:22:50 +03:00
umount ( IMAGE_LOCATION ) ;
2008-05-07 20:41:57 +04:00
return RETURN_ERROR ;
2004-01-20 21:32:43 +03:00
}
2005-01-25 20:22:18 +03:00
iso = 1 ;
2005-03-02 20:48:28 +03:00
add_to_env ( " PIGGYBACK " , " 1 " ) ;
2004-04-04 01:19:34 +04:00
}
2004-01-20 21:32:43 +03:00
2005-03-05 18:26:22 +03:00
if ( access ( get_ramdisk_path ( iso ? NULL : location_full ) , R_OK ) ) {
2007-08-02 20:45:59 +04:00
stg1_error_message ( " I can't find the %s Distribution in the specified directory. "
2005-03-05 18:26:22 +03:00
" Here's a short extract of the files in the directory: \n "
2007-08-02 20:45:59 +04:00
" %s " , version , disk_extract_list_directory ( IMAGE_LOCATION ) ) ;
2004-01-20 21:32:43 +03:00
loumount ( ) ;
2004-12-13 01:22:50 +03:00
umount ( IMAGE_LOCATION ) ;
2008-05-07 20:41:57 +04:00
return RETURN_ERROR ;
2005-03-05 18:26:22 +03:00
}
2007-08-02 20:45:59 +04:00
log_message ( " found the %s Installation, good news! " , version ) ;
2005-03-05 18:26:22 +03:00
if ( ! IS_LOWMEM & & ramdisk_possible ( ) ) {
if ( load_ramdisk ( iso ? NULL : location_full ) ! = RETURN_OK ) {
2004-01-20 21:32:43 +03:00
stg1_error_message ( " Could not load program into memory. " ) ;
loumount ( ) ;
2004-12-13 01:22:50 +03:00
umount ( IMAGE_LOCATION ) ;
2008-05-07 20:41:57 +04:00
return RETURN_ERROR ;
2004-01-20 21:32:43 +03:00
}
} else {
2005-03-05 18:26:22 +03:00
do_losetup ( LIVE_DEVICE , get_ramdisk_path ( iso ? NULL : location_full ) ) ;
my_mount ( LIVE_DEVICE , STAGE2_LOCATION , ( IS_LIVE ) ? LIVEFS : STAGE2FS , 0 ) ;
2004-01-20 21:32:43 +03:00
}
2005-01-26 16:43:53 +03:00
2005-03-02 20:48:28 +03:00
add_to_env ( " DEVICE " , choice ) ;
2008-05-07 20:41:57 +04:00
add_to_env ( " METHOD " , strdup ( " disk " ) ) ;
2005-03-02 20:48:28 +03:00
add_to_env ( " PREFIX " , answers_location [ 0 ] ) ;
2005-01-25 20:22:18 +03:00
2004-01-20 21:32:43 +03:00
return RETURN_OK ;
}
enum return_type disk_prepare ( void )
{
char * * medias , * * ptr , * * medias_models ;
char * choice ;
2007-08-02 20:45:59 +04:00
char msg [ 256 ] ;
2004-01-20 21:32:43 +03:00
int i , count = 0 ;
enum return_type results ;
get_medias ( DISK , & medias , & medias_models ) ;
ptr = medias ;
while ( ptr & & * ptr ) {
count + + ;
ptr + + ;
}
if ( count = = 0 ) {
stg1_error_message ( " No DISK drive found. " ) ;
2008-05-07 20:41:57 +04:00
return RETURN_BACK ;
2004-01-20 21:32:43 +03:00
}
2008-05-07 20:41:57 +04:00
if ( try_with_uuidlabel ( ) = = RETURN_OK )
return RETURN_OK ;
2004-01-20 21:32:43 +03:00
if ( count = = 1 ) {
results = try_with_device ( * medias ) ;
2008-05-07 20:41:57 +04:00
return ( results = = RETURN_OK ) ? RETURN_OK : RETURN_BACK ;
2004-01-20 21:32:43 +03:00
}
2007-08-02 20:45:59 +04:00
snprintf ( msg , sizeof ( msg ) , " Please choose the DISK drive on which you copied the %s Distribution. " , version ) ;
results = ask_from_list_comments_auto ( msg , medias , medias_models , & choice , " disk " , medias ) ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK )
return results ;
results = try_with_device ( choice ) ;
if ( results = = RETURN_OK )
return RETURN_OK ;
2008-02-29 20:05:35 +03:00
i = ask_insmod ( ) ;
2004-01-20 21:32:43 +03:00
if ( i = = RETURN_BACK )
return RETURN_BACK ;
return disk_prepare ( ) ;
}