Hi Dominik,
Dominik Taborsky wrote:
> On a side note, would it be a good idea to merge libmbr's error codes into
> errno.h?
Short answer: no.
Long answer: Obviously the errno.h approach does not scale. Every function
has its own set of ways it can fail and so it could have its own set of
error codes - that would be one extreme case. The other extreme case would
be to put all these error codes into a single header/enum, with none or some
unification.
Since in case of most functions we don't really feel the need to distinguish
betweem a whole lot of failure reasons, we usually use the lazy approach
where we try to map the one or two failure reasons to the existing errno
error codes. In the cases where an interface/library needs a larger and
meaningful set of error codes, it is perfectly fine to define your own set.
Note: Your error codes have names like ERR_xxx, I would suggest prefixing
them with the name of the library, eg. MBR_xxx, MBR_Exxxx or so, to prevent
name clashes.
libgpt now checks partition boundaries, as promised. It is already on
launchpad (lp:hdisk), feel free to test. Otherwise, it is ready for
merge.
I didn't have a chance to re-test your code so far. I suggest merging with
the mainline, btw, due to big recent changes like list_foreach().
I haven't had a chance to try running your code again. I've looked at
briefly and I still find some deviations from the official Cstyle, such as:
(I am only including one exaple of each type of Cstyle error):
* Copyright (c) 2012, 2013 Dominik Taborsky
we only put the last year of modification in, such as:
* Copyright (c) 2013 Dominik Taborsky
I have to admit, though, that I am not sure whether the current way is a
good idea, we might discuss about changing it
hdisk.c:
int interact(service_id_t);
void print_help(void);
void select_label_format(tinput_t *);
void construct_label(layouts_t);
void free_label(void);
int try_read(service_id_t);
int try_read_mbr(service_id_t);
int try_read_gpt(service_id_t);
void set_alignment(tinput_t *);
I suggest that module-private functions should be declared static.
input.h:
extern int get_input_line(tinput_t * in, char ** str);
extern uint8_t get_input_uint8(tinput_t * in);
extern uint32_t get_input_uint32(tinput_t * in);
extern uint64_t get_input_uint64(tinput_t * in);
extern size_t get_input_size_t(tinput_t * in);
func_gpt.h:
extern int construct_gpt_label(label_t *);
extern int add_gpt_part (label_t *, tinput_t *);
extern int delete_gpt_part (label_t *, tinput_t *);
extern int destroy_gpt_label(label_t *);
extern int new_gpt_label (label_t *);
extern int print_gpt_parts (label_t *);
extern int read_gpt_parts (label_t *, service_id_t);
extern int write_gpt_parts (label_t *, service_id_t);
extern int extra_gpt_funcs (label_t *, tinput_t *, service_id_t);
Here's a block of function declarations that use tab for aligning - in one
case you are aligning function names, in the other you are aligning the
opening brackets?!. You should not align either, use a single space between
type and name (same for lists of variable declarations) and no space between
name and opening bracket.
input.c:
int get_input_line(tinput_t * in, char ** str)
There should be no space after asterisk.
func_mbr.c:133:
printf("\t%10u %10u %10u %7u\n", it->start_addr, it->start_addr + it
->length, it->length, it->type);
This line ends at column 117 - lines should not exceed 80 characters.
func_mbr.c:
#include <stdio.h>
#include <errno.h>
#include <str_error.h>
#include <sys/types.h>
#include "func_mbr.h"
#include "input.h"
This is a clear violation of IWIU (include what you use). You are using
common.h to include libmbr.h and libgpt.h, but really func_mbr.c should
directly include libmbr.h.
Speaking of which I don't think the headers should be named libmbr.h and
libgpt.h - after all the library names are 'mbr' and 'gpt'. libmbr and
libgpt are just part of the scheme of file names where the libraries are
stored.
func_gpt.c:
printf("%3zu %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %3zu %s\
n",
i-1, gpt_get_start_lba(iter), gpt_get_end_lba(iter),
gpt_get_end_lba(iter) - gpt_get_start_lba(iter),
gpt_get_part_type(iter), gpt_get_part_name(iter));
libgpt.c:
label->gpt->header->pe_array_crc32 = host2uint32_t_le(compute_crc32(
(uint8_t *) label->parts->part_array,
fillries * e_size));
etc.
Continuation lines should be indented by 4 spaces.
(again I don't think you should call the main source module of gpt library
libgpt.c)
Blank line placement is also a bit erratic sometimes. For example:
int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
{
gpt_part_t *p;
/* Find the first empty entry */
do {
if (label->parts->fill == label->parts->arr_size) {
if (extend_part_array(label->parts) == -1)
return ENOMEM;
}
p = label->parts->part_array + label->parts->fill++;
} while (gpt_get_part_type(p) != GPT_PTE_UNUSED);
memcpy(p, partition, sizeof(gpt_entry_t));
return EOK;
}
should really look something like:
int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
{
gpt_part_t *p;
/* Find the first empty entry */
do {
if (label->parts->fill == label->parts->arr_size) {
if (extend_part_array(label->parts) == -1)
return ENOMEM;
}
p = label->parts->part_array + label->parts->fill++;
} while (gpt_get_part_type(p) != GPT_PTE_UNUSED);
memcpy(p, partition, sizeof(gpt_entry_t));
return EOK;
}
Note that blank lines are placed:
- after the closing line of a block {} statement
- between variable declarations and other statements
- no more than one blank line is used
libgpt.c:
/** Set partition type
* @param p partition to be set
* @param type partition type to set
* - see our fine selection at gpt_ptypes to choose from
*/
The spacing in the above block is:
3 tabs between 'p' and 'partition to be set'
2 tabs between 'type' and 'partition type to be set'
1 space and 5 tabs between '*' and '- see our fine selection'
that puts the text you were trying to align at columns 33, 25 and 41,
respectively, if tab width is 8 characters.
libmbr.c:248:
link_t *l = label->parts->list.head.next;
/* Encoding primary partitions */
for (i = 0; i < N_PRIMARY; i++) {
p = list_get_instance(l, mbr_part_t, link);
encode_part(p, &(label->mbr->raw_data.pte[i]), 0, false);
l = l->next;
}
Use either list_foreach() or list_first() and list_next(). Also, what
happens if there are less than N_PRIMARY entries in the list?
libmbr.c:256:
&(label->mbr->raw_data)
the parentheses are unnecessary, it should be just &label->mbr->raw_data
/* Encoding and writing first logical partition */
if (l != &(label->parts->list.head)) {
had you used list_first()/list_next() you could check for l != NULL.
/** Remove partition
* Removes partition by index, indexed from zero. When removing extended
* partition, all logical partitions get removed as well.
*
It should be indented/spaced like:
/** Remove partition
*
* Remove partition by index, indexed from zero. When removing extended
* partition, all logical partitions are removed aswell.
*
typedef enum {
/** Other flags unknown - saving previous state */
/** Bootability */
ST_BOOT = 7,
/** Logical partition, 0 = primary, 1 = logical*/
ST_LOGIC = 8
} MBR_FLAGS;
typedef enum {
/** No error */
ERR_OK = 0,
/** All primary partitions already present */
ERR_PRIMARY_FULL,
/** Extended partition already present */
ERR_EXTENDED_PRESENT,
/** No extended partition present */
ERR_NO_EXTENDED,
/** Partition overlapping */
ERR_OVERLAP,
/** Partition out of bounds */
ERR_OUT_BOUNDS,
/** No space left for EBR */
ERR_NO_EBR,
/** Out of memory */
ERR_NOMEM,
/** Libblock error */
ERR_LIBBLOCK,
} mbr_err_val;
Typedefs should have a lowercase_t name, e.g. mbr_flags_t, mbr_err_t.
/** Check whether two partitions overlap
*
* @return true/false
*/
does not really say any more useful information than
/** Check whether two partitions overlap. */
If you want to convey more information, how about:
/** Check whether two partitions overlap
*
* @param p1 First partition
* @param p2 Second partition
*
* @return @c true if @a p1 and @a p2 overlap, @c false otherwise.
*/
Functionality wise:
- it appears to me that mbr checks for overlap when adding a partition,
but gpt checks it only when writing the table?
- maybe you should check the consistency (e.g. overlaps) when you read the
label
- I really really think the interface should allow you to specify just the
size of the partition
- you should be able to specify the size/capacity not only in number of
blocks, but also in number of {T|G|M|k}Bytes or percent
Terminology wise:
You are using the term 'sector' to mean a unit of data on the block
device, but that is really called a 'block'. Sector is the coordinate in the
cylinder-head-sector coordinate system, i.e. a 'sector' s contains the
blocks Forall x,y: (C,H,S)=(x,y,s). In the LBA coordinate system there are
no sectors at all, just linear block addresses.
When I get some time to test your code, I may have further comments.
Best regards,
Jiri
_______________________________________________
HelenOS-devel mailing list
[email protected]
http://lists.modry.cz/listinfo/helenos-devel