summaryrefslogblamecommitdiffstats
path: root/libfdisk/src/label.c
blob: 625a8749d7987e8eb8dc5169d5ed59bb088d4efa (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                   
  





                                                                          
                          
 
                                            
                                                        

                                                     

                                   
                                 



                                                                                
                                                                 

                                
                                        


                                 



                                                                      
 
                                                      


                         
                                               



                                 







                                                      
                                 










                                                                             
                                                        













                                                          
                                   

                               
                                          

 


                                                     
 

                                                                              



                                                     

               
                    
 
                                            

                                                                




                                                                    

 
   


















































                                                                           










                                                     
                                    
                               

                                        
 
                                           


   























                                                                     


                        




                                                                             













                                                          


















































































                                                                              

                       

                                                                  
                                               


             
                                                  

                                                 




                           

                                
                                      
                               

                                        
 





                                                                     

                                                                         











                                                          
                                                                     


                                
                                         

                               
                                                               
                                                            
                                                         
 












                                                                       
                         
                               
 


                               

                                                     
                             
     
                             
      

         
                         
                                               

                             
 
                                                
                                
                               
                            

                               


                                              
                                                   

                                                                
                                           
 
 













                                                                               













                                                                
                                                                        

                                               
















                                                                     







                                               

                                                                          
 
                                                                  

                            

                                                                  









                                      

                                                       

                                                      
                                
                               

                                           
 

                                                                  














                                                                    
 







                                                          


                                                         
 

               




                                             

                                                                   




                                                                                             
















                                                                      




















                                                                                           
                  


 


                                                        
                                               
 
                   
 


                                       
 



                                                                 







                                                  















                                                                    

#include "fdiskP.h"

/*
 * Don't use this function derectly, use fdisk_new_context_from_filename()
 */
int fdisk_probe_labels(struct fdisk_context *cxt)
{
	size_t i;

	cxt->label = NULL;

	for (i = 0; i < cxt->nlabels; i++) {
		struct fdisk_label *lb = cxt->labels[i];
		struct fdisk_label *org = cxt->label;
		int rc;

		if (!lb->op->probe)
			continue;
		if (lb->disabled) {
			DBG(LABEL, dbgprint("%s disabled -- ignore", lb->name));
			continue;
		}
		DBG(LABEL, dbgprint("probing for %s", lb->name));

		cxt->label = lb;
		rc = lb->op->probe(cxt);
		cxt->label = org;

		if (rc != 1) {
			if (lb->op->deinit)
				lb->op->deinit(lb);	/* for sure */
			continue;
		}

		__fdisk_context_switch_label(cxt, lb);
		return 0;
	}

	DBG(LABEL, dbgprint("no label found"));
	return 1; /* not found */
}


/**
 * fdisk_dev_has_disklabel:
 * @cxt: fdisk context
 *
 * Returns: return 1 if there is label on the device.
 */
int fdisk_dev_has_disklabel(struct fdisk_context *cxt)
{
	return cxt && cxt->label;
}

/**
 * fdisk_dev_is_disklabel:
 * @cxt: fdisk context
 * @l: disklabel type
 *
 * Returns: return 1 if there is @l disklabel on the device.
 */
int fdisk_dev_is_disklabel(struct fdisk_context *cxt, enum fdisk_labeltype l)
{
	return cxt && cxt->label && cxt->label->id == l;
}

/**
 * fdisk_write_disklabel:
 * @cxt: fdisk context
 *
 * Write in-memory changes to disk
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_write_disklabel(struct fdisk_context *cxt)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->write)
		return -ENOSYS;

	return cxt->label->op->write(cxt);
}

int fdisk_require_geometry(struct fdisk_context *cxt)
{
	assert(cxt);

	return cxt->label
	       && cxt->label->flags & FDISK_LABEL_FL_REQUIRE_GEOMETRY ? 1 : 0;
}

int fdisk_missing_geometry(struct fdisk_context *cxt)
{
	int rc;

	assert(cxt);

	rc = (fdisk_require_geometry(cxt) &&
		    (!cxt->geom.heads || !cxt->geom.sectors
				      || !cxt->geom.cylinders));

	if (rc && !fdisk_context_listonly(cxt))
		fdisk_warnx(cxt, _("Incomplete geometry setting."));

	return rc;
}

/**
 * fdisk_get_columns:
 * @cxt: fdisk context
 * @cols: returns allocated array with FDISK_COL_*
 * @ncols: returns number of items in cols
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_get_columns(struct fdisk_context *cxt, int **cols, size_t *ncols)
{
	size_t i, n;
	int *c;

	assert(cxt);

	if (!cxt->label)
		return -EINVAL;
	if (!cxt->label->columns || !cxt->label->ncolumns)
		return -ENOSYS;
	c = calloc(cxt->label->ncolumns, sizeof(int));
	if (!c)
		return -ENOMEM;
	for (n = 0, i = 0; i < cxt->label->ncolumns; i++) {
		if (cxt->label->columns[i].detail
		    && !fdisk_context_display_details(cxt))
			continue;
		c[n++] = cxt->label->columns[i].id;
	}
	if (cols)
		*cols = c;
	if (ncols)
		*ncols = n;
	return 0;
}

static const struct fdisk_column *fdisk_label_get_column(
					struct fdisk_label *lb, int id)
{
	size_t i;

	assert(lb);
	assert(id > 0);

	for (i = 0; i < lb->ncolumns; i++) {
		if (lb->columns[i].id == id)
			return &lb->columns[i];
	}

	return NULL;
}

/**
 * fdisk_verify_disklabel:
 * @cxt: fdisk context
 *
 * Verifies the partition table.
 *
 * Returns 0.
 */
int fdisk_verify_disklabel(struct fdisk_context *cxt)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->verify)
		return -ENOSYS;
	if (fdisk_missing_geometry(cxt))
		return -EINVAL;

	return cxt->label->op->verify(cxt);
}

/**
 * fdisk_partition_get_data:
 * @cxt: fdisk context
 * @id: column (FDISK_COL_*)
 * @partnum: partition number
 * @data: return allocated data
 *
 * For exmaple
 *	fdisk_partition_get_data(cxt, FDISK_COL_UUID, 0, &data);
 * returns UUID for the first partition.
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_partition_get_data(struct fdisk_context *cxt, int id,
			     size_t partnum, char **data)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_get_data)
		return -ENOSYS;

	return cxt->label->op->part_get_data(cxt, id, partnum, data);
}

/**
 * fdisk_list_disklabel:
 * @cxt: fdisk context
 *
 * Lists in-memory partition table and all related details.
 *
 * This function uses libfdisk ASK interface to print data. The details about
 * partitions table are printed by FDISK_ASKTYPE_INFO and partitions by
 * FDISK_ASKTYPE_TABLE. The default columns are printed.
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_list_disklabel(struct fdisk_context *cxt)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->list)
		return -ENOSYS;

	return cxt->label->op->list(cxt);
}

/**
 * fdisk_list_partitions
 * @cxt: fdisk context
 * @cols: array with wanted FDISK_COL_* columns
 * @ncols: number of items in the cols array
 *
 * This is subset of fdisk_list_disklabel(), this function lists really
 * only partitons by FDISK_ASKTYPE_TABLE interface.
 *
 * If no @cols are specified then the default is printed (see
 * fdisk_label_get_columns() for the default columns).

 * Returns 0 on success, otherwise, a corresponding error.
 */

int fdisk_list_partitions(struct fdisk_context *cxt, int *cols, size_t ncols)
{
	int *org = cols, rc = 0;
	struct tt *tb = NULL;
	const struct fdisk_column *col;
	size_t i, j;

	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_get_data)
		return -ENOSYS;

	if (!cols || !ncols) {
		rc = fdisk_get_columns(cxt, &cols, &ncols);
		if (rc)
			return rc;
	}

	tb = tt_new_table(TT_FL_FREEDATA);
	if (!tb) {
		rc = -ENOMEM;
		goto done;
	}

	/* define table columns */
	for (j = 0; j < ncols; j++) {
		col = fdisk_label_get_column(cxt->label, cols[j]);
		if (!col)
			continue;
		tt_define_column(tb, col->name, col->width, col->flags);
	}

	/* generate per-partition lines into table */
	for (i = 0; i < cxt->label->nparts_max; i++) {
		int status = 0;
		struct tt_line *ln;

		rc = fdisk_partition_get_status(cxt, i, &status);
		if (rc || !(status & FDISK_PARTSTAT_USED))
			continue;

		ln = tt_add_line(tb, NULL);
		if (!ln)
			continue;

		/* set data for the columns */
		for (j = 0; j < ncols; j++) {
			char *data = NULL;

			col = fdisk_label_get_column(cxt->label, cols[j]);
			if (!col)
				continue;
			rc = fdisk_partition_get_data(cxt, col->id, i, &data);
			if (rc)
				goto done;
			tt_line_set_data(ln, j, data);
		}
	}

	if (!tt_is_empty(tb))
		rc = fdisk_print_table(cxt, tb);
done:
	if (org != cols)
		free(cols);
	tt_free_table(tb);
	return rc;
}

/**
 * fdisk_add_partition:
 * @cxt: fdisk context
 * @t: partition type to create or NULL for label-specific default
 *
 * Creates a new partition with type @parttype.
 *
 * Returns 0.
 */
int fdisk_add_partition(struct fdisk_context *cxt,
			struct fdisk_parttype *t)
{
	size_t partnum = 0;

	assert(cxt);
	assert(cxt->label);

	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_add)
		return -ENOSYS;
	if (fdisk_missing_geometry(cxt))
		return -EINVAL;

	if (!(cxt->label->flags & FDISK_LABEL_FL_ADDPART_NOPARTNO)) {
		int rc = fdisk_ask_partnum(cxt, &partnum, 1);
		if (rc)
			return rc;
	}

	DBG(LABEL, dbgprint("adding new partition number %zd", partnum));
	cxt->label->op->part_add(cxt, partnum, t);
	return 0;
}

/**
 * fdisk_delete_partition:
 * @cxt: fdisk context
 * @partnum: partition number to delete
 *
 * Deletes a @partnum partition.
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_delete_partition(struct fdisk_context *cxt, size_t partnum)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_delete)
		return -ENOSYS;

	DBG(LABEL, dbgprint("deleting %s partition number %zd",
				cxt->label->name, partnum));
	return cxt->label->op->part_delete(cxt, partnum);
}

/**
 * fdisk_create_disklabel:
 * @cxt: fdisk context
 * @name: label name
 *
 * Creates a new disk label of type @name. If @name is NULL, then it
 * will create a default system label type, either SUN or DOS.
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
{
	int haslabel = 0;
	struct fdisk_label *lb;

	if (!cxt)
		return -EINVAL;

	if (!name) { /* use default label creation */
#ifdef __sparc__
		name = "sun";
#else
		name = "dos";
#endif
	}

	if (cxt->label) {
		fdisk_deinit_label(cxt->label);
		haslabel = 1;
	}

	lb = fdisk_context_get_label(cxt, name);
	if (!lb || lb->disabled)
		return -EINVAL;
	if (!lb->op->create)
		return -ENOSYS;

	__fdisk_context_switch_label(cxt, lb);

	if (haslabel && !cxt->parent)
		fdisk_reset_device_properties(cxt);

	DBG(LABEL, dbgprint("create a new %s label", lb->name));
	return cxt->label->op->create(cxt);
}


int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name,
			   off_t *offset, size_t *size)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->locate)
		return -ENOSYS;

	DBG(LABEL, dbgprint("locating %d chunk of %s.", n, cxt->label->name));
	return cxt->label->op->locate(cxt, n, name, offset, size);
}


/**
 * fdisk_get_disklabel_id:
 * @cxt: fdisk context
 * @id: returns pointer to allocated string
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->get_id)
		return -ENOSYS;

	DBG(LABEL, dbgprint("asking for disk %s ID", cxt->label->name));
	return cxt->label->op->get_id(cxt, id);
}

/**
 * fdisk_get_disklabel_id:
 * @cxt: fdisk context
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_set_disklabel_id(struct fdisk_context *cxt)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->set_id)
		return -ENOSYS;

	DBG(LABEL, dbgprint("setting %s disk ID", cxt->label->name));
	return cxt->label->op->set_id(cxt);
}

/**
 * fdisk_get_partition_type:
 * @cxt: fdisk context
 * @partnum: partition number
 *
 * Returns partition type or NULL upon failure.
 */
struct fdisk_parttype *fdisk_get_partition_type(struct fdisk_context *cxt,
						size_t partnum)
{
	if (!cxt || !cxt->label || !cxt->label->op->part_get_type)
		return NULL;

	DBG(LABEL, dbgprint("partition: %zd: get type", partnum));
	return cxt->label->op->part_get_type(cxt, partnum);
}

/**
 * fdisk_set_partition_type:
 * @cxt: fdisk context
 * @partnum: partition number
 * @t: new type
 *
 * Returns 0 on success, < 0 on error.
 */
int fdisk_set_partition_type(struct fdisk_context *cxt,
			     size_t partnum,
			     struct fdisk_parttype *t)
{
	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_set_type)
		return -ENOSYS;

	DBG(LABEL, dbgprint("partition: %zd: set type", partnum));
	return cxt->label->op->part_set_type(cxt, partnum, t);
}

/**
 * fdisk_get_nparttypes:
 * @cxt: fdisk context
 *
 * Returns: number of partition types supported by the current label
 */
size_t fdisk_get_nparttypes(struct fdisk_context *cxt)
{
	if (!cxt || !cxt->label)
		return 0;

	return cxt->label->nparttypes;
}

/**
 * fdisk_partition_is_used:
 * @cxt: fdisk context
 * @partnum: partition number
 * @status: returns FDISK_PARTSTAT_* flags
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_partition_get_status(struct fdisk_context *cxt,
			       size_t partnum,
			       int *status)
{
	int rc;

	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_get_status)
		return -ENOSYS;

	rc = cxt->label->op->part_get_status(cxt, partnum, status);

	DBG(LABEL, dbgprint("partition: %zd: status: 0x%04x [rc=%d]", partnum, *status, rc));
	return rc;
}

/**
 * @cxt: fdisk context
 * @partnum: partition number
 *
 * Returns: 1 on success if partition used otherwise 0.
 */
int fdisk_partition_is_used(struct fdisk_context *cxt, size_t partnum)
{
	int status, rc;

	rc = fdisk_partition_get_status(cxt, partnum, &status);
	if (rc)
		return 0;

	return status & FDISK_PARTSTAT_USED;
}

/**
 * fdisk_partition_taggle_flag:
 * @cxt: fdisk context
 * @partnum: partition number
 * @status: flags
 *
 * Returns 0 on success, otherwise, a corresponding error.
 */
int fdisk_partition_toggle_flag(struct fdisk_context *cxt,
			       size_t partnum,
			       unsigned long flag)
{
	int rc;

	if (!cxt || !cxt->label)
		return -EINVAL;
	if (!cxt->label->op->part_toggle_flag)
		return -ENOSYS;

	rc = cxt->label->op->part_toggle_flag(cxt, partnum, flag);

	DBG(LABEL, dbgprint("partition: %zd: toggle: 0x%04lx [rc=%d]", partnum, flag, rc));
	return rc;
}


/*
 * Resets the current used label driver to initial state
 */
void fdisk_deinit_label(struct fdisk_label *lb)
{
	assert(lb);

	/* private label information */
	if (lb->op->deinit)
		lb->op->deinit(lb);
}

void fdisk_label_set_changed(struct fdisk_label *lb, int changed)
{
	assert(lb);
	lb->changed = changed ? 1 : 0;
}

int fdisk_label_is_changed(struct fdisk_label *lb)
{
	assert(lb);
	return lb ? lb->changed : 0;
}

void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled)
{
	assert(lb);

	DBG(LABEL, dbgprint("%s label %s",
				lb->name,
				disabled ? "DISABLED" : "ENABLED"));
	lb->disabled = disabled ? 1 : 0;
}

int fdisk_label_is_disabled(struct fdisk_label *lb)
{
	assert(lb);
	return lb ? lb->disabled : 0;
}