1 /*
   2     libparted - a library for manipulating disk partitions
   3     Copyright (C) 2001, 2007 Free Software Foundation, Inc.
   4 
   5     This program is free software; you can redistribute it and/or modify
   6     it under the terms of the GNU General Public License as published by
   7     the Free Software Foundation; either version 3 of the License, or
   8     (at your option) any later version.
   9 
  10     This program is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13     GNU General Public License for more details.
  14 
  15     You should have received a copy of the GNU General Public License
  16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 
  18     Contributor: Ben Collins <bcollins@debian.org>
  19 */
  20 
  21 #include <config.h>
  22 
  23 #include <parted/parted.h>
  24 #include <parted/endian.h>
  25 #include <parted/debug.h>
  26 
  27 #if ENABLE_NLS
  28 #  include <libintl.h>
  29 #  define _(String) dgettext (PACKAGE, String)
  30 #else
  31 #  define _(String) (String)
  32 #endif /* ENABLE_NLS */
  33 
  34 #include <unistd.h>
  35 #include <string.h>
  36 
  37 #define SUN_UFS_BLOCK_SIZES       ((int[2]){512, 0})
  38 #define HP_UFS_BLOCK_SIZES        ((int[2]){512, 0})
  39 
  40 
  41 /* taken from ufs_fs.h in Linux */
  42 #define UFS_MAXNAMLEN 255
  43 #define UFS_MAXMNTLEN 512
  44 #define UFS_MAXCSBUFS 31
  45 #define UFS_LINK_MAX 32000
  46 
  47 #define UFS_MAGIC       0x00011954
  48 #define UFS_MAGIC_LFN   0x00095014
  49 #define UFS_MAGIC_FEA   0x00195612
  50 #define UFS_MAGIC_4GB   0x05231994
  51 
  52 struct ufs_csum {
  53         uint32_t        cs_ndir;        /* number of directories */
  54         uint32_t        cs_nbfree;      /* number of free blocks */
  55         uint32_t        cs_nifree;      /* number of free inodes */
  56         uint32_t        cs_nffree;      /* number of free frags */
  57 };
  58 
  59 struct ufs_super_block {
  60         uint32_t        fs_link;        /* UNUSED */
  61         uint32_t        fs_rlink;       /* UNUSED */
  62         uint32_t        fs_sblkno;      /* addr of super-block in filesys */
  63         uint32_t        fs_cblkno;      /* offset of cyl-block in filesys */
  64         uint32_t        fs_iblkno;      /* offset of inode-blocks in filesys */
  65         uint32_t        fs_dblkno;      /* offset of first data after cg */
  66         uint32_t        fs_cgoffset;    /* cylinder group offset in cylinder */
  67         uint32_t        fs_cgmask;      /* used to calc mod fs_ntrak */
  68         uint32_t        fs_time;        /* last time written -- time_t */
  69         uint32_t        fs_size;        /* number of blocks in fs */
  70         uint32_t        fs_dsize;       /* number of data blocks in fs */
  71         uint32_t        fs_ncg;         /* number of cylinder groups */
  72         uint32_t        fs_bsize;       /* size of basic blocks in fs */
  73         uint32_t        fs_fsize;       /* size of frag blocks in fs */
  74         uint32_t        fs_frag;        /* number of frags in a block in fs */
  75 /* these are configuration parameters */
  76         uint32_t        fs_minfree;     /* minimum percentage of free blocks */
  77         uint32_t        fs_rotdelay;    /* num of ms for optimal next block */
  78         uint32_t        fs_rps;         /* disk revolutions per second */
  79 /* these fields can be computed from the others */
  80         uint32_t        fs_bmask;       /* ``blkoff'' calc of blk offsets */
  81         uint32_t        fs_fmask;       /* ``fragoff'' calc of frag offsets */
  82         uint32_t        fs_bshift;      /* ``lblkno'' calc of logical blkno */
  83         uint32_t        fs_fshift;      /* ``numfrags'' calc number of frags */
  84 /* these are configuration parameters */
  85         uint32_t        fs_maxcontig;   /* max number of contiguous blks */
  86         uint32_t        fs_maxbpg;      /* max number of blks per cyl group */
  87 /* these fields can be computed from the others */
  88         uint32_t        fs_fragshift;   /* block to frag shift */
  89         uint32_t        fs_fsbtodb;     /* fsbtodb and dbtofsb shift constant */
  90         uint32_t        fs_sbsize;      /* actual size of super block */
  91         uint32_t        fs_csmask;      /* csum block offset */
  92         uint32_t        fs_csshift;     /* csum block number */
  93         uint32_t        fs_nindir;      /* value of NINDIR */
  94         uint32_t        fs_inopb;       /* value of INOPB */
  95         uint32_t        fs_nspf;        /* value of NSPF */
  96 /* yet another configuration parameter */
  97         uint32_t        fs_optim;       /* optimization preference, see below */
  98 /* these fields are derived from the hardware */
  99         union {
 100                 struct {
 101                         uint32_t        fs_npsect;      /* # sectors/track including spares */
 102                 } fs_sun;
 103                 struct {
 104                         int32_t         fs_state;       /* file system state time stamp */
 105                 } fs_sunx86;
 106         } fs_u1;
 107         uint32_t        fs_interleave;  /* hardware sector interleave */
 108         uint32_t        fs_trackskew;   /* sector 0 skew, per track */
 109 /* a unique id for this file system (currently unused and unmaintained) */
 110 /* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */
 111 /* Neither of those fields is used in the Tahoe code right now but */
 112 /* there could be problems if they are.                            */
 113         uint32_t        fs_id[2];       /* file system id */
 114 /* sizes determined by number of cylinder groups and their sizes */
 115         uint32_t        fs_csaddr;      /* blk addr of cyl grp summary area */
 116         uint32_t        fs_cssize;      /* size of cyl grp summary area */
 117         uint32_t        fs_cgsize;      /* cylinder group size */
 118 /* these fields are derived from the hardware */
 119         uint32_t        fs_ntrak;       /* tracks per cylinder */
 120         uint32_t        fs_nsect;       /* sectors per track */
 121         uint32_t        fs_spc;         /* sectors per cylinder */
 122 /* this comes from the disk driver partitioning */
 123         uint32_t        fs_ncyl;        /* cylinders in file system */
 124 /* these fields can be computed from the others */
 125         uint32_t        fs_cpg;         /* cylinders per group */
 126         uint32_t        fs_ipg;         /* inodes per group */
 127         uint32_t        fs_fpg;         /* blocks per group * fs_frag */
 128 /* this data must be re-computed after crashes */
 129         struct ufs_csum fs_cstotal;     /* cylinder summary information */
 130 /* these fields are cleared at mount time */
 131         int8_t          fs_fmod;        /* super block modified flag */
 132         int8_t          fs_clean;       /* file system is clean flag */
 133         int8_t          fs_ronly;       /* mounted read-only flag */
 134         int8_t          fs_flags;       /* currently unused flag */
 135         int8_t          fs_fsmnt[UFS_MAXMNTLEN];        /* name mounted on */
 136 /* these fields retain the current block allocation info */
 137         uint32_t        fs_cgrotor;     /* last cg searched */
 138         uint32_t        fs_csp[UFS_MAXCSBUFS];  /* list of fs_cs info buffers */
 139         uint32_t        fs_maxcluster;
 140         uint32_t        fs_cpc;         /* cyl per cycle in postbl */
 141         uint16_t        fs_opostbl[16][8];      /* old rotation block list head */      
 142         union {
 143                 struct {
 144                         int32_t         fs_sparecon[53];/* reserved for future constants */
 145                         int32_t         fs_reclaim;
 146                         int32_t         fs_sparecon2[1];
 147                         int32_t         fs_state;       /* file system state time stamp */
 148                         uint32_t        fs_qbmask[2];   /* ~usb_bmask */
 149                         uint32_t        fs_qfmask[2];   /* ~usb_fmask */
 150                 } fs_sun;
 151                 struct {
 152                         int32_t         fs_sparecon[53];/* reserved for future constants */
 153                         int32_t         fs_reclaim;
 154                         int32_t         fs_sparecon2[1];
 155                         uint32_t        fs_npsect;      /* # sectors/track including spares */
 156                         uint32_t        fs_qbmask[2];   /* ~usb_bmask */
 157                         uint32_t        fs_qfmask[2];   /* ~usb_fmask */
 158                 } fs_sunx86;
 159                 struct {
 160                         int32_t         fs_sparecon[50];/* reserved for future constants */
 161                         int32_t         fs_contigsumsize;/* size of cluster summary array */
 162                         int32_t         fs_maxsymlinklen;/* max length of an internal symlink */
 163                         int32_t         fs_inodefmt;    /* format of on-disk inodes */
 164                         uint32_t        fs_maxfilesize[2];      /* max representable file size */
 165                         uint32_t        fs_qbmask[2];   /* ~usb_bmask */
 166                         uint32_t        fs_qfmask[2];   /* ~usb_fmask */
 167                         int32_t         fs_state;       /* file system state time stamp */
 168                 } fs_44;
 169         } fs_u2;
 170         int32_t fs_postblformat;        /* format of positional layout tables */
 171         int32_t fs_nrpos;               /* number of rotational positions */
 172         int32_t fs_postbloff;           /* (__s16) rotation block list head */
 173         int32_t fs_rotbloff;            /* (uint8_t) blocks for each rotation */
 174         int32_t fs_magic;               /* magic number */
 175         uint8_t fs_space[4];            /* list of blocks for each rotation */
 176 };
 177 
 178 static PedGeometry*
 179 ufs_probe_sun (PedGeometry* geom)
 180 {
 181         int8_t buf[512 * 3];
 182         struct ufs_super_block *sb;
 183 
 184         if (geom->length < 5)
 185                 return 0;
 186         if (!ped_geometry_read (geom, buf, 16, 3))
 187                 return 0;
 188 
 189         sb = (struct ufs_super_block *)buf;
 190 
 191         if (PED_BE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) {
 192                 PedSector block_size = PED_BE32_TO_CPU(sb->fs_bsize) / 512;
 193                 PedSector block_count = PED_BE32_TO_CPU(sb->fs_size);
 194                 return ped_geometry_new (geom->dev, geom->start,
 195                                          block_size * block_count);
 196         }
 197         if (PED_LE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) {
 198                 PedSector block_size = PED_LE32_TO_CPU(sb->fs_bsize) / 512;
 199                 PedSector block_count = PED_LE32_TO_CPU(sb->fs_size);
 200                 return ped_geometry_new (geom->dev, geom->start,
 201                                          block_size * block_count);
 202         }
 203         return NULL;
 204 }
 205 
 206 static PedGeometry*
 207 ufs_probe_hp (PedGeometry* geom)
 208 {
 209         int8_t buf[1536];
 210         struct ufs_super_block *sb;
 211         PedSector block_size;
 212         PedSector block_count;
 213 
 214         if (geom->length < 5)
 215                 return 0;
 216         if (!ped_geometry_read (geom, buf, 16, 3))
 217                 return 0;
 218 
 219         sb = (struct ufs_super_block *)buf;
 220 
 221         /* Try sane bytesex */
 222         switch (PED_BE32_TO_CPU(sb->fs_magic)) {
 223                 case UFS_MAGIC_LFN:
 224                 case UFS_MAGIC_FEA:
 225                 case UFS_MAGIC_4GB:
 226                         block_size = PED_BE32_TO_CPU(sb->fs_bsize) / 512;
 227                         block_count = PED_BE32_TO_CPU(sb->fs_size);
 228                         return ped_geometry_new (geom->dev, geom->start,
 229                                                  block_size * block_count);
 230         }
 231 
 232         /* Try perverted bytesex */
 233         switch (PED_LE32_TO_CPU(sb->fs_magic)) {
 234                 case UFS_MAGIC_LFN:
 235                 case UFS_MAGIC_FEA:
 236                 case UFS_MAGIC_4GB:
 237                         block_size = PED_LE32_TO_CPU(sb->fs_bsize) / 512;
 238                         block_count = PED_LE32_TO_CPU(sb->fs_size);
 239                         return ped_geometry_new (geom->dev, geom->start,
 240                                                  block_size * block_count);
 241         }
 242         return NULL;
 243 }
 244 
 245 #ifndef DISCOVER_ONLY
 246 static int
 247 ufs_clobber (PedGeometry* geom)
 248 {
 249         char    buf[1536];
 250 
 251         if (!ped_geometry_read (geom, buf, 16, 3))
 252                 return 0;
 253 
 254         memset (buf, 0, sizeof(struct ufs_super_block));
 255 
 256         return ped_geometry_write (geom, buf, 16, 3);
 257 }
 258 #endif /* !DISCOVER_ONLY */
 259 
 260 static PedFileSystemOps ufs_ops_sun = {
 261         .probe =                ufs_probe_sun,
 262 #ifndef DISCOVER_ONLY
 263         .clobber =      ufs_clobber,
 264 #else
 265         .clobber =      NULL,
 266 #endif
 267         .open =         NULL,
 268         .create =               NULL,
 269         .close =                NULL,
 270         .check =                NULL,
 271         .copy =         NULL,
 272         .resize =               NULL,
 273         .get_create_constraint =        NULL,
 274         .get_resize_constraint =        NULL,
 275         .get_copy_constraint =  NULL
 276 };
 277 
 278 static PedFileSystemOps ufs_ops_hp = {
 279         .probe =                ufs_probe_hp,
 280 #ifndef DISCOVER_ONLY
 281         .clobber =      ufs_clobber,
 282 #else
 283         .clobber =      NULL,
 284 #endif
 285         .open =         NULL,
 286         .create =               NULL,
 287         .close =                NULL,
 288         .check =                NULL,
 289         .copy =         NULL,
 290         .resize =               NULL,
 291         .get_create_constraint =        NULL,
 292         .get_resize_constraint =        NULL,
 293         .get_copy_constraint =  NULL
 294 };
 295 
 296 static PedFileSystemType ufs_type_sun = {
 297         .next = NULL,
 298         .ops =  &ufs_ops_sun,
 299         .name = "sun-ufs",
 300         .block_sizes = SUN_UFS_BLOCK_SIZES
 301 };
 302 
 303 static PedFileSystemType ufs_type_hp = {
 304         .next =   NULL,
 305         .ops =    &ufs_ops_hp,
 306         .name =   "hp-ufs",
 307         .block_sizes = HP_UFS_BLOCK_SIZES
 308 };
 309 
 310 void
 311 ped_file_system_ufs_init ()
 312 {
 313         PED_ASSERT (sizeof (struct ufs_super_block) == 1380, return);
 314 
 315         ped_file_system_type_register (&ufs_type_sun);
 316         ped_file_system_type_register (&ufs_type_hp);
 317 }
 318 
 319 void
 320 ped_file_system_ufs_done ()
 321 {
 322         ped_file_system_type_unregister (&ufs_type_hp);
 323         ped_file_system_type_unregister (&ufs_type_sun);
 324 }