char * do_part_get_name (const char *device, int partnum) { CLEANUP_FREE char *parttype; parttype = do_part_get_parttype (device); if (parttype == NULL) return NULL; if (STREQ (parttype, "gpt")) { CLEANUP_FREE char *out = print_partition_table (device, true); if (!out) return NULL; CLEANUP_FREE_STRING_LIST char **lines = split_lines (out); if (!lines) return NULL; if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) { reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s", lines[0] ? lines[0] : "(signature was null)"); return NULL; } if (lines[1] == NULL) { reply_with_error ("parted didn't return a line describing the device"); return NULL; } size_t row; int pnum; for (row = 2; lines[row] != NULL; ++row) { if (sscanf (lines[row], "%d:", &pnum) != 1) { reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); return NULL; } if (pnum == partnum) break; } if (lines[row] == NULL) { reply_with_error ("partition number %d not found", partnum); return NULL; } char *name = get_table_field (lines[row], 5); if (name == NULL) reply_with_error ("cannot get the name field from '%s'", lines[row]); return name; } else { reply_with_error ("part-get-name can only be used on GUID Partition Tables"); return NULL; } }
int do_part_get_bootable (const char *device, int partnum) { if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } CLEANUP_FREE char *out = print_partition_table (device, true); if (!out) return -1; CLEANUP_FREE_STRING_LIST char **lines = split_lines (out); if (!lines) return -1; /* Partitions may not be in any order, so we have to look for * the matching partition number (RHBZ#602997). */ if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) { reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s", lines[0] ? lines[0] : "(signature was null)"); return -1; } if (lines[1] == NULL) { reply_with_error ("parted didn't return a line describing the device"); return -1; } size_t row; int pnum; for (row = 2; lines[row] != NULL; ++row) { if (sscanf (lines[row], "%d:", &pnum) != 1) { reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); return -1; } if (pnum == partnum) break; } if (lines[row] == NULL) { reply_with_error ("partition number %d not found", partnum); return -1; } CLEANUP_FREE char *boot = get_table_field (lines[row], 6); if (boot == NULL) return -1; return strstr (boot, "boot") != NULL; }
/***************************************************************** Disk housekeeping that must be done for both source and destination disks Open disk get partition table get base address of desired partition deal with errors write record keeping info to log file drive is the disk to open caption is either "source" or "destination" (for log file) log is the log file p is the command line ask_for_partitions = true => do dialog to get partition index px is the partition index (if supplied on command line) return base -- partition base address (LBA) return n -- number of sectors in partition return disk -- disk control pointer to access drive *****************************************************************/ int setup_disk (char* drive, char *caption, FILE *log, char **p, int ask_for_partitions, int px, off_t *base, off_t *n, disk_control_ptr *disk) { int status; static pte_rec pt[4]; *disk = open_disk (drive,&status); if (status) { printf ("%s could not open drive %s, status code %d\n", p[0], drive, status); fprintf (log,"%s could not open drive %s, status code %d\n", p[0], drive, status); return 1; } status = get_partition_table(*disk,pt); if (status) { printf ("Could not read %s partition table on drive %s\n", caption, drive); fprintf (log,"Could not read %s partition table on drive %s\n", caption, drive); return 1; } if (ask_for_partitions) { /* ask if not given on command line */ print_partition_table(stdout, pt, 1, 1); printf("Select partition: "); scanf("%d", &px); printf("\nPartition %d selected.\n", px); } status = get_partition_offset (pt, px, base, n); if (status) { printf ("Could not find %s partition %d\n", caption, px); return 1; } printf ("%s partition %d at %llu for %llu\n", caption, px, *base, *n); /* log information about disk and partition */ log_disk (log, caption, *disk); print_partition_table(log, pt, 1, 1); fprintf (log,"%s partition %d at %llu for %llu\n", caption, px, *base, *n); return 0; }
int main (int np, char **p) { char drive[NAME_LENGTH] = "/dev/hda"; int lname_given = 0, status, i, all, help = 0; static disk_control_block *dd; pte_rec pt[4]; FILE *log; char comment [NAME_LENGTH] = "", log_name[NAME_LENGTH], access[2] = "a"; time_t from; /*_stklen = 2*_stklen;*/ time(&from); printf ("\n%s compiled at %s on %s\n", p[0], __TIME__,__DATE__); /* get command line */ if (np < 6) help = 1; else strncpy(drive, p[4], NAME_LENGTH - 1); for (i = 6; i < np; i++){ if (strcmp(p[i],"-all") == 0) all = 1; else if (strcmp (p[i],"-new_log")== 0) access[0] = 'w'; else if (strcmp (p[i],"-log_name")== 0) { if(++i >= np) { printf("%s: -log_name option requires a logfile name\n", p[0]); help = 1; } else { sprintf (log_name,"%s",p[i]); lname_given = 1; } } else if (strcmp(p[i],"-comment") == 0) { i++; if (i < np) strncpy (comment, p[i], NAME_LENGTH - 1); else help = 1; } else { printf("Invalid parameter: %s\n", p[i]); help = 1; } } if (help) { print_help(p[0]); return 0; } status = 1; printf ("Drive %s\n",drive); /* open log file */ if (lname_given == 0) sprintf (log_name,"pt-%s-log.txt", filename(&p[4][5])); log = log_open (log_name,access,comment,SCCS_ID,np,p); /* open and log disk */ dd = open_disk (drive,&status); if (status) { printf ("%s could not access drive %s, status code %d\n",p[0], drive,status); fprintf (log,"%s could not access drive %s, status code %d\n",p[0], drive,status); return 1; } fprintf (log,"Drive label: %s\n",p[5]); log_disk (log,"Partition table",dd); /* get and print partition table */ status = get_partition_table(dd,pt); if (status == 0) print_partition_table(stdout, pt, 1, all); else if (status == -1) printf ("No partition table signature\n"); else printf ("Error reading partition table, code %d\n",status); if (status == 0) print_partition_table(log, pt, 1, all); if (status)fprintf (log,"Error reading partition table, code %d\n",status); log_close (log,from); return 0; }
int do_part_get_bootable (const char *device, int partnum) { if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } int parted_has_m_opt = test_parted_m_opt (); if (parted_has_m_opt == -1) return -1; char *out = print_partition_table (device, parted_has_m_opt); if (!out) return -1; char **lines = split_lines (out); free (out); if (!lines) return -1; if (parted_has_m_opt) { /* New-style parsing using the "machine-readable" format from * 'parted -m'. * * Partitions may not be in any order, so we have to look for * the matching partition number (RHBZ#602997). */ if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) { reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s", lines[0] ? lines[0] : "(signature was null)"); free_strings (lines); return -1; } if (lines[1] == NULL) { reply_with_error ("parted didn't return a line describing the device"); free_strings (lines); return -1; } size_t row; int pnum; for (row = 2; lines[row] != NULL; ++row) { if (sscanf (lines[row], "%d:", &pnum) != 1) { reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); free_strings (lines); return -1; } if (pnum == partnum) break; } if (lines[row] == NULL) { reply_with_error ("partition number %d not found", partnum); free_strings (lines); return -1; } char *boot = get_table_field (lines[row], 6); if (boot == NULL) { free_strings (lines); return -1; } int r = STREQ (boot, "boot"); free (boot); free_strings (lines); return r; } else { /* Old-style: First look for the line matching "^Number". */ size_t start = 0, header, row; for (row = 0; lines[row] != NULL; ++row) if (STRPREFIX (lines[row], "Number")) { start = row+1; header = row; break; } if (start == 0) { reply_with_error ("parted output has no \"Number\" line"); free_strings (lines); return -1; } /* Now we have to look at the column number of the "Flags" field. * This is because parted's output has no way to represent a * missing field except as whitespace, so we cannot just count * fields from the left. eg. The "File system" field is often * missing in the output. */ char *p = strstr (lines[header], "Flags"); if (!p) { reply_with_error ("parted output has no \"Flags\" field"); free_strings (lines); return -1; } size_t col = p - lines[header]; /* Look for the line corresponding to this partition number. */ row = start + partnum - 1; if (row >= count_strings (lines) || !STRPREFIX (lines[row], " ")) { reply_with_error ("partition number out of range: %d", partnum); free_strings (lines); return -1; } int r = STRPREFIX (&lines[row][col], "boot"); free_strings (lines); return r; } }
guestfs_int_partition_list * do_part_list (const char *device) { int parted_has_m_opt = test_parted_m_opt (); if (parted_has_m_opt == -1) return NULL; char *out = print_partition_table (device, parted_has_m_opt); if (!out) return NULL; char **lines = split_lines (out); free (out); if (!lines) return NULL; guestfs_int_partition_list *r; if (parted_has_m_opt) { /* New-style parsing using the "machine-readable" format from * 'parted -m'. * * lines[0] is "BYT;", lines[1] is the device line which we ignore, * lines[2..] are the partitions themselves. Count how many. */ size_t nr_rows = 0, row; for (row = 2; lines[row] != NULL; ++row) ++nr_rows; r = malloc (sizeof *r); if (r == NULL) { reply_with_perror ("malloc"); goto error1; } r->guestfs_int_partition_list_len = nr_rows; r->guestfs_int_partition_list_val = malloc (nr_rows * sizeof (guestfs_int_partition)); if (r->guestfs_int_partition_list_val == NULL) { reply_with_perror ("malloc"); goto error2; } /* Now parse the lines. */ size_t i; for (i = 0, row = 2; lines[row] != NULL; ++i, ++row) { if (sscanf (lines[row], "%d:%" SCNi64 "B:%" SCNi64 "B:%" SCNi64 "B", &r->guestfs_int_partition_list_val[i].part_num, &r->guestfs_int_partition_list_val[i].part_start, &r->guestfs_int_partition_list_val[i].part_end, &r->guestfs_int_partition_list_val[i].part_size) != 4) { reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); goto error3; } } } else { /* Old-style. Start at the line following "^Number", up to the * next blank line. */ size_t start = 0, end = 0, row; for (row = 0; lines[row] != NULL; ++row) if (STRPREFIX (lines[row], "Number")) { start = row+1; break; } if (start == 0) { reply_with_error ("parted output has no \"Number\" line"); goto error1; } for (row = start; lines[row] != NULL; ++row) if (STREQ (lines[row], "")) { end = row; break; } if (end == 0) { reply_with_error ("parted output has no blank after end of table"); goto error1; } size_t nr_rows = end - start; r = malloc (sizeof *r); if (r == NULL) { reply_with_perror ("malloc"); goto error1; } r->guestfs_int_partition_list_len = nr_rows; r->guestfs_int_partition_list_val = malloc (nr_rows * sizeof (guestfs_int_partition)); if (r->guestfs_int_partition_list_val == NULL) { reply_with_perror ("malloc"); goto error2; } /* Now parse the lines. */ size_t i; for (i = 0, row = start; row < end; ++i, ++row) { if (sscanf (lines[row], " %d %" SCNi64 "B %" SCNi64 "B %" SCNi64 "B", &r->guestfs_int_partition_list_val[i].part_num, &r->guestfs_int_partition_list_val[i].part_start, &r->guestfs_int_partition_list_val[i].part_end, &r->guestfs_int_partition_list_val[i].part_size) != 4) { reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); goto error3; } } } free_strings (lines); return r; error3: free (r->guestfs_int_partition_list_val); error2: free (r); error1: free_strings (lines); return NULL; }
char * do_part_get_parttype (const char *device) { int parted_has_m_opt = test_parted_m_opt (); if (parted_has_m_opt == -1) return NULL; char *out = print_partition_table (device, parted_has_m_opt); if (!out) return NULL; if (parted_has_m_opt) { /* New-style parsing using the "machine-readable" format from * 'parted -m'. */ char **lines = split_lines (out); free (out); if (!lines) return NULL; if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) { reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s", lines[0] ? lines[0] : "(signature was null)"); free_strings (lines); return NULL; } if (lines[1] == NULL) { reply_with_error ("parted didn't return a line describing the device"); free_strings (lines); return NULL; } /* lines[1] is something like: * "/dev/sda:1953525168s:scsi:512:512:msdos:ATA Hitachi HDT72101;" */ char *r = get_table_field (lines[1], 5); if (r == NULL) { free_strings (lines); return NULL; } free_strings (lines); /* If "loop" return an error (RHBZ#634246). */ if (STREQ (r, "loop")) { free (r); reply_with_error ("not a partitioned device"); return NULL; } return r; } else { /* Old-style. Look for "\nPartition Table: <str>\n". */ char *p = strstr (out, "\nPartition Table: "); if (!p) { reply_with_error ("parted didn't return Partition Table line"); free (out); return NULL; } p += 18; char *q = strchr (p, '\n'); if (!q) { reply_with_error ("parted Partition Table has no end of line char"); free (out); return NULL; } *q = '\0'; p = strdup (p); free (out); if (!p) { reply_with_perror ("strdup"); return NULL; } /* If "loop" return an error (RHBZ#634246). */ if (STREQ (p, "loop")) { free (p); reply_with_error ("not a partitioned device"); return NULL; } return p; /* caller frees */ } }
main (int np, char **p) { int help = 0,/* request command line help */ layout_only = 0; /* print disk layout only */ int status,/* disk open or I/O status return */ i; /* loop index */ /* variables to handle fill characters */ unsigned char src_fill = 'S', dst_fill = 'D'; int is_fill, id_fill; /* source disk parameters */ static disk_control_ptr src_dcb; /* drive information */ char src_drive[NAME_LENGTH] = "/dev/hda"; /* source drive, default is Master on Primary IDE */ pte_rec src_pt[4]; /* partition table for source disk */ int src_n_regions = 0; /* number of chunks on the source */ layout_ptr src_layout = (layout_ptr) malloc(MAX_PARTITIONS*sizeof(layout_rec)); /* chunks */ /* destination disk parameters */ static disk_control_ptr dst_dcb; char dst_drive[NAME_LENGTH] = "/dev/hdb"; pte_rec dst_pt[4]; int dst_n_regions = 0; layout_ptr dst_layout = (layout_ptr) malloc(MAX_PARTITIONS*sizeof(layout_rec)); FILE *log; /* log file */ char comment [NAME_LENGTH] = "", log_name[NAME_LENGTH] = "cmpalog.txt", access[2] = "a"; /* tester (user) comment for log file */ static time_t from; /* time program started running */ int assign_regions = 0; /* flag: user wants to assign corresponding chunks */ /* _stklen = 2*_stklen; */ printf ("\n%s Version 3.1 compiled at %s on %s\n", p[0], __TIME__,__DATE__); /****************************************************************************** Get command line ******************************************************************************/ if (np < 8) { printf ("%s: Missing parameters\n",p[0]); help = 1; } else { sscanf (p[5],"%2x",&is_fill); src_fill = is_fill; sscanf (p[7],"%2x",&id_fill); dst_fill = id_fill; strncpy(src_drive, p[4], NAME_LENGTH - 1); strncpy(dst_drive, p[6], NAME_LENGTH - 1); printf ("Src drive %s dst drive %s\n",src_drive,dst_drive); printf ("Src fill 0x%02X dst fill 0x%02X\n",src_fill,dst_fill); } for (i = 8; i < np; i++) { if (strcmp(p[i], "-assign") == 0) assign_regions = 1; else if (strcmp (p[i], "-h") == 0) help = 1; else if (strcmp (p[i], "-layout") == 0) layout_only = 1; else if (strcmp (p[i], "-new_log")== 0) access[0] = 'w'; else if (strcmp (p[i], "-log_name") == 0) { if(++i >= np) { printf("%s: -log_name option requires a logfile name\n", p[0]); help = 1; } else strncpy(log_name, p[i], NAME_LENGTH - 1); } else if (strcmp (p[i],"-comment")== 0) { i++; if (i >= np) { printf ("%s: comment required with -comment\n", p[0]); print_help(p[0]); return 1; } strncpy (comment,p[i], NAME_LENGTH - 1); } else { printf("Invalid parameter: %s\n", p[i]); help = 1; } } if (help) { print_help(p[0]); return 0; } /****************************************************************************** Start log file, open source disk and get partition table ******************************************************************************/ log = log_open (log_name, access, comment, SCCS_ID, np, p); fprintf (log, "Src drive %s dst drive %s\n",src_drive,dst_drive); fprintf (log, "Src fill 0x%02X dst fill 0x%02X\n",src_fill,dst_fill); src_dcb = open_disk (src_drive,&status); if (status) { printf ("Could not access source drive %s status code %d\n",src_drive,status); return 1; } log_disk (log,"Source Disk",src_dcb); status = get_partition_table(src_dcb,src_pt); if (status == 0) { fprintf (log,"Source disk partition table\n"); print_partition_table(log,src_pt,0,1); print_partition_table(stdout,src_pt,1,1); } else { fprintf (log,"Error reading src partition table code %d\n", status); printf ("No partition table signature or error reading partition table (code %d)\n",status); return 1; } time(&from); src_n_regions = layout_disk (src_pt,src_layout,src_dcb); printf ("%d regions\n",src_n_regions); fprintf (log,"Source disk layout: "); fprintf (log," %05llu/%03llu/%02llu ", src_dcb->disk_max.cylinder, src_dcb->disk_max.head, src_dcb->disk_max.sector); fprintf (log,"%llu total sectors on disk\n",src_dcb->n_sectors); fprintf (log,"%4s%10s%10s%10s%23s\n","","Start LBA","End LBA","Length", "Size: MB (binary)"); for (i = 0; i < src_n_regions; i++){ printf ("%2d %c %9llu %9llu %9llu %8.2fMB %8.2fBMB\n", i, src_layout[i].chunk_class, src_layout[i].lba_start, src_layout[i].lba_start + src_layout[i].n_sectors - 1, src_layout[i].n_sectors, BYTES_PER_SECTOR*(float)src_layout[i].n_sectors/1000000.0, BYTES_PER_SECTOR*(float)src_layout[i].n_sectors/1048576.0); fprintf (log,"%2d %c %9llu %9llu %9llu %8.2fMB %8.2fBMB\n", i, src_layout[i].chunk_class, src_layout[i].lba_start, src_layout[i].lba_start + src_layout[i].n_sectors - 1, src_layout[i].n_sectors, BYTES_PER_SECTOR*(float)src_layout[i].n_sectors/1000000.0, BYTES_PER_SECTOR*(float)src_layout[i].n_sectors/1048576.0); } /****************************************************************************** Open destination disk, get partition table ******************************************************************************/ dst_dcb = open_disk (dst_drive,&status); if (status) { printf ("Could not access destination drive %s status code %d\n",dst_drive,status); return 1; } log_disk (log,"Destination Disk",dst_dcb); status = get_partition_table(dst_dcb,dst_pt); if (status == 0){ fprintf (log,"Destination disk partition table\n"); print_partition_table(log,dst_pt,0,1); print_partition_table(stdout,dst_pt,1,1); } else { fprintf (log,"Error reading src partition table code %d\n", status); printf ("No partition table signature or error reading partition table (code %d)\n",status); return 1; } dst_n_regions = layout_disk (dst_pt,dst_layout,dst_dcb); printf ("%d regions on %s\n",dst_n_regions,dst_drive); fprintf (log,"Destination disk layout: "); fprintf (log," %05llu/%03llu/%02llu ", dst_dcb->disk_max.cylinder, dst_dcb->disk_max.head, dst_dcb->disk_max.sector); fprintf (log,"%llu total sectors on disk\n",dst_dcb->n_sectors); fprintf (log,"%4s%10s%10s%10s%23s\n","","Start LBA","End LBA","Length", "Size: MB (binary)"); for (i = 0; i < dst_n_regions; i++){ printf ("%2d %c %9llu %9llu %9llu %8.2fMB %8.2fBMB\n", i, dst_layout[i].chunk_class, dst_layout[i].lba_start, dst_layout[i].lba_start + dst_layout[i].n_sectors - 1, dst_layout[i].n_sectors, BYTES_PER_SECTOR * (double)dst_layout[i].n_sectors/1000000.0, BYTES_PER_SECTOR * (double)dst_layout[i].n_sectors/1048576.0); fprintf (log,"%2d %c %9llu %9llu %9llu %8.2fMB %8.2fBMB\n", i, dst_layout[i].chunk_class, dst_layout[i].lba_start, dst_layout[i].lba_start + dst_layout[i].n_sectors - 1, dst_layout[i].n_sectors, BYTES_PER_SECTOR * (double)dst_layout[i].n_sectors/1000000.0, BYTES_PER_SECTOR * (double)dst_layout[i].n_sectors/1048576.0); } /****************************************************************************** Do the compare ******************************************************************************/ if (layout_only == 0) status = do_compare(src_dcb,src_n_regions,src_layout,dst_dcb,dst_n_regions, dst_layout,src_fill,dst_fill,log,assign_regions,from); /****************************************************************************** Close the log file ******************************************************************************/ log_close(log,from); return 0; }