[parted-devel] porting to FreeBSD
Jim Meyering
jim at meyering.net
Tue Mar 6 22:14:05 CET 2007
"Siavosh Benabbas" <sbenabas at gmail.com> wrote:
> 1) There is still one printf in the libparted/arch/freebsd.c file that
> is informational, e.g., it is not an exception or anything. What
> should I change this to?
Why not just remove it?
> 2) I have "#ifndef __FreeBSD__"-ed out all the si_code values that are
> not present on FreeBSD. As was already said on the list changing this
> to one #ifdef per value might be desirable.
>
> I am waiting for more comments specially on my use of
> ped_exception_throw, which I guessed.
I haven't looked closely at those.
I suggest you try to exercise a few of them.
First, a global syntactic nit:
You wrote this:
> + if(np == NULL)
There should be a space between the "if" and the open parenthesis:
> + if (np == NULL)
> diff --exclude=.git -NruBb parted/libparted/arch/freebsd.c parted-freebsd/libparted/arch/freebsd.c
...
> +
> +static int
> +_device_stat (PedDevice* dev, struct stat * dev_stat)
Please use "const" wherever possible. It makes your code more
robust and more readable. For example, add one in the line above:
_device_stat (const PedDevice* dev, struct stat * dev_stat)
> +static int
> +_device_probe_type (PedDevice* dev)
> +{
> + struct stat dev_stat;
> + char *np;
> + PedExceptionOption ex_status;
> +
> +#if (__FreeBSD_version >= 500000) && (__FreeBSD_version < 600000)
> + FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
Move this declaration "down" into the #if block where it's used.
That gets rid of these two cpp directives and makes the code
easier to follow as well.
> +#endif
> +
> + if (!_device_stat (dev, &dev_stat))
> + return 0;
> +
> + if (!S_ISCHR(dev_stat.st_mode)) {
> + dev->type = PED_DEVICE_FILE;
> + return 1;
> + }
> +
> + /* On FreeBSD ad0 ist the ATA device */
> + np = strrchr(dev->path, '/');
> + if(np == NULL)
> + {
> + dev->type = PED_DEVICE_UNKNOWN;
> + return 0;
> + }
> + np += 1; /* advance past '/' */
> +
> + if(strncmp(np, "ad", 2) == 0)
> + {
> + dev->type = PED_DEVICE_IDE;
> +
> + /* ad0 -> channel 0, master
> + * ad1 -> channel 0, slave
> + * ad2 -> channel 1, master
> + * ad3 -> channel 1, slave
> + */
If the above comments are relevant only to versions [5.0... 6.0),
then put them inside this #if block:
> +#if (__FreeBSD_version >= 500000) && (__FreeBSD_version < 600000)
> + switch(*(np+3))
> + {
> + case 0:
Shouldn't this be case '0':?
Otherwise, you're looking for the NUL byte.
> + arch_specific->channel = 0;
> + arch_specific->device = 0;
> + break;
> + case 1:
> + arch_specific->channel = 0;
> + arch_specific->device = 1;
> + break;
> + case 2:
> + arch_specific->channel = 1;
> + arch_specific->device = 0;
> + break;
> + case 4:
Shouldn't the above be "case '3':" ?
As in the byte, 3, in "/ad3" from the comment above?
> + arch_specific->channel = 1;
> + arch_specific->device = 1;
> + break;
Don't you want a "default:" label here, to handle e.g., "/ad9" and "/ad"?
> + }
Don't you want an #else here?
> +#endif
> + }
> + else
> + {
> + dev->type = PED_DEVICE_UNKNOWN;
> + }
> +
> + return 1;
> +}
...
> +static PedSector
> +_device_get_length (PedDevice* dev)
This parameter, too, should be "const".
Please fix all of them.
> +{
> + FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
> + off_t bytes = 0;
> +
> + PED_ASSERT (dev->open_count > 0, return 0);
> +
> + if(ioctl(arch_specific->fd, DIOCGMEDIASIZE, &bytes) == 0) {
> + return bytes / dev->sector_size;
> + }
> +
> + return 0;
> +}
> +
> +
> +#if (__FreeBSD_version >= 500000) && (__FreeBSD_version < 600000)
> +# define freebsd_get_ata_params freebsd_get_ata_params_compat5
> +#elif (__FreeBSD_version >= 600000)
> +# define freebsd_get_ata_params freebsd_get_ata_params_compat6
> +#else
> +# error "parted currently compiles on FreeBSD 5.X and 6.X only"
> +#endif
> +
> +#if (__FreeBSD_version >= 500000) && (__FreeBSD_version < 600000)
> +
> +static int freebsd_get_ata_params_compat5(PedDevice *dev,
> + struct ata_params *ap)
Very long line, above?
> +{
> + struct ata_cmd iocmd;
> + int fd, ret;
> + FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
> +
> + if ((fd = open("/dev/ata", O_RDWR)) == -1)
This file is being opened read/write, but below, ...
> + {
> + ped_exception_throw (
> + PED_EXCEPTION_ERROR,
> + PED_EXCEPTION_CANCEL,
> + _("Could not open /dev/ata."));
Rather than duplicating a file name like this, declare it
const char *dev_ata = "/dev/ata";
and use the variable in each place.
> +
> + ret = -1;
> + goto out;
> + }
> +
> + bzero(&iocmd, sizeof(struct ata_cmd));
Don't use the deprecated bzero function.
Use memset instead.
> + iocmd.channel = arch_specific->channel;
> + iocmd.device = arch_specific->device;
> + iocmd.cmd = ATAGPARM;
> +
> + if (ioctl(fd, IOCATA, &iocmd) == -1)
> + {
> + ped_exception_throw (
> + PED_EXCEPTION_ERROR,
> + PED_EXCEPTION_CANCEL,
> + _("Could not get ATA parameters. Please"
> + "contact the maintainer."));
> +
> + ret = -1;
> + goto out;
> + }
> +
> + if (iocmd.u.param.type[arch_specific->device]) {
> + *ap = iocmd.u.param.params[arch_specific->device];
> + } else
> + {
> + ped_exception_throw (
> + PED_EXCEPTION_ERROR,
> + PED_EXCEPTION_CANCEL,
> + _("Could not get ATA parameters. Please"
> + "contact the maintainer."));
> + ret = -1;
> + goto out;
> + }
> +
> + ret = 0;
> +
> +out:
> + close(fd);
You must check for close failure.
There are two more, below.
> +
> + return ret;
> +}
> +
> +#elif __FreeBSD_version >= 600000
> +
> +static int freebsd_get_ata_params_compat6(PedDevice *dev,
> + struct ata_params *ap)
Very long line again.
> +{
> + FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
Why so much space before the variable name?
> +
> + return ioctl (arch_specific->fd, IOCATAGPARM, ap);
> +}
> +
> +#endif
> +
> +static int
> +_device_probe_geometry (PedDevice* dev)
> +{
> + FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
here too.
...
> + if (freebsd_get_ata_params (dev, &ap) == -1) {
> + ex_status = ped_exception_throw (
> + PED_EXCEPTION_WARNING,
> + PED_EXCEPTION_IGNORE_CANCEL,
> + _("Could not get identity of device %s - %s"),
> + dev->path, strerror (errno));
> + switch (ex_status) {
> + case PED_EXCEPTION_CANCEL:
> + goto error_close_dev;
> +
> + case PED_EXCEPTION_UNHANDLED:
> + ped_exception_catch ();
> + case PED_EXCEPTION_IGNORE:
> + dev->model = strdup(_("IDE"));
> + }
> + } else {
> + snprintf (vendor_buf, 64, "%s/%s", ap.model, ap.revision);
don't use literal 64 here.
Rather, use sizeof vendor_buf.
> +static int
> +freebsd_close (PedDevice* dev)
> +{
> + FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
> +
> + if (dev->dirty)
> + _flush_cache (dev);
> + close (arch_specific->fd);
> + return 1;
> +}
...
> + ret = sysctlbyname("kern.geom.conftxt", conftxt, &confsize, NULL, 0);
> + if (ret) {
> + ped_exception_throw (
> + PED_EXCEPTION_ERROR,
> + PED_EXCEPTION_CANCEL,
> + _("error reading kern.geom.conftxt from the system"));//Was printf
> + free (conftxt);
> + return 0;
> + }
> +
> + cptr = conftxt;
> +
> + while (sscanf (cptr, "%*d %16s %16s",
> + devtype, devname) != EOF) {
What if the actual devname value is longer than 16 bytes?
Doesn't this code then silently accept it?
if you *must* use sscanf, you have to verify its return value
matches the number of format specifiers. i.e., don't compare w/EOF.
Instead, use "... == 3". But even that makes it hard to distinguish
EOF from a corrupted input file.
With your != EOF test, you could match just one or two, and the
2nd and/or 3rd pointers would be used uninitialized.
> + if (strcmp(devtype, "DISK") == 0)
> + {
> + strncpy (fullpath, _PATH_DEV, sizeof(fullpath) - 1);
> + fullpath[sizeof(fullpath) - 1] = '\0';
> + strncat (fullpath, devname,
> + sizeof(fullpath) - strlen(fullpath) - 1);
> + printf("Probing %s ...\n", fullpath);
> + _ped_device_probe (fullpath);
> +
> + if(_partition_is_mounted_by_path (fullpath)){
> + ped_exception_throw (
> + PED_EXCEPTION_WARNING,
> + PED_EXCEPTION_OK,
> + _("WARNING: %s or parts of it are mounted!.\n"),
> + fullpath);//Was printf
> + }
> + }
> +
> + if((cptr = strchr(cptr, '\n')) == NULL)
> + break;
> + else
> + cptr++;
> + }
> +
> + ped_free(conftxt);
> +
> + return 1;
> +}
> +
> +static void
> +freebsd_probe_all ()
> +{
> + _probe_standard_devices ();
> +}
> +
> +/* slice_num is slice number */
> +/* part_num is the partition number in this slice */
> +/* both slice_num and part_num can be -1. */
> +/* when slice_num is -1, then we're making paths for a raw disk */
> +/* e.g. ad0a, ad0c, ad0e, etc */
> +/* when part_num is -1, then we're making a path that takes */
> +/* the whole slice e.g. ad0s0, ad0s1, ad0s5. */
> +/* ad6s2e */
> +/* || */
> +/* | \__ part_num */
> +/* \___ slice_num */
> +static char*
> +_device_get_part_path (PedDevice* dev, int slice_num, int part_num)
> +{
> + int path_len = strlen (dev->path);
> + int result_len = path_len + 16;
> + char* result;
> + char part[2] = { '\0', '\0' };
> + char* fmt;
> +
> + result = (char*) ped_malloc (result_len);
> + if (!result)
> + return NULL;
> +
> + /* slice_num = -1 when covering raw disk (ad0a, ad0c, etc) */
> + if(slice_num == -1)
> + fmt = "%s%s";
> + else
> + fmt = "%ss%d%s";
There is no need for a "fmt" variable.
Remove the four lines above, and substitute the literal
format strings into the snprintf calls below.
> + /* if part_num is -1, then the part[] array is already a null string */
> + /* if it's not -1, then transform slice_num into a character and put it */
> + /* in part[] */
> + if(part_num != -1)
> + {
> + part[0] = (char) part_num + 'a';
> + part[1] = '\0';
> + }
> +
> + if(slice_num == -1)
> + /* append slice number (ad0, slice 2 => ad0s2) */
> + snprintf (result, result_len, fmt, dev->path, part);
> + else
> + /* append slice and partition number (ad0, slice 1, part 2 => ad0s1c) */
> + snprintf (result, result_len, fmt, dev->path, slice_num, part);
> +
> + return result;
> +}
...
More information about the parted-devel
mailing list