/* Code to read ufs2 superblock */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>

#define SBLOCK_UFS2 65536       /* ufs2 superblock starts at 64KB (64*1024) */
#define SBLOCK_PIGGY 262144 /* for some piggy systems it is stored at 256KB (256*1024) */

#define MAXMNTLEN	468
#define MAXVOLLEN	32
#define	NOCSPTRS	((128 / sizeof(void *)) - 4)
#define FSMAXSNAP 20

typedef int64_t ufs_time_t;
typedef int64_t ufs2_daddr_t;

struct ufs2_super_block
{
  u_char     s_dummy[0x55c];    /* Perfect */
  int32_t    fs_magic;
  u_char     s_pad[160];        /* padding to be multiple of 512 */
};

struct csum {
  int32_t	cs_ndir;		/* number of directories */
  int32_t	cs_nbfree;		/* number of free blocks */
  int32_t	cs_nifree;		/* number of free inodes */
  int32_t	cs_nffree;		/* number of free frags */
};

struct csum_total {
  int64_t	cs_ndir;		/* number of directories */
  int64_t	cs_nbfree;		/* number of free blocks */
  int64_t	cs_nifree;		/* number of free inodes */
  int64_t	cs_nffree;		/* number of free frags */
  int64_t	cs_numclusters;		/* number of free clusters */
  int64_t	cs_spare[3];		/* future expansion */
};

/*
 * Super block for an FFS filesystem.
 */
struct fs {
  int32_t	 fs_firstfield;		
  int32_t	 fs_unused_1;		
  int32_t	 fs_sblkno;		
  int32_t	 fs_cblkno;		
  int32_t	 fs_iblkno;		
  int32_t	 fs_dblkno;		
  int32_t	 fs_old_cgoffset;	
  int32_t	 fs_old_cgmask;		
  int32_t  fs_old_time;		
  int32_t	 fs_old_size;		
  int32_t	 fs_old_dsize;		
  int32_t	 fs_ncg;		
  int32_t	 fs_bsize;		
  int32_t	 fs_fsize;		
  int32_t	 fs_frag;		

  int32_t	 fs_minfree;		
  int32_t	 fs_old_rotdelay;	
  int32_t	 fs_old_rps;		

  int32_t	 fs_bmask;		
  int32_t	 fs_fmask;		
  int32_t	 fs_bshift;		
  int32_t	 fs_fshift;		

  int32_t	 fs_maxcontig;		
  int32_t	 fs_maxbpg;		

  int32_t	 fs_fragshift;		
  int32_t	 fs_fsbtodb;		
  int32_t	 fs_sbsize;		
  int32_t	 fs_spare1[2];		
					
  int32_t	 fs_nindir;		
  int32_t	 fs_inopb;		
  int32_t	 fs_old_nspf;		

  int32_t	 fs_optim;		
  int32_t	 fs_old_npsect;		
  int32_t	 fs_old_interleave;	
  int32_t	 fs_old_trackskew;	
  int32_t	 fs_id[2];		

  int32_t	 fs_old_csaddr;		
  int32_t	 fs_cssize;		
  int32_t	 fs_cgsize;		
  int32_t	 fs_spare2;		
  int32_t	 fs_old_nsect;		
  int32_t  fs_old_spc;		
  int32_t	 fs_old_ncyl;		
  int32_t	 fs_old_cpg;		
  int32_t	 fs_ipg;		
  int32_t	 fs_fpg;		

  struct	csum fs_old_cstotal;	

  int8_t   fs_fmod;		
  int8_t   fs_clean;		
  int8_t 	 fs_ronly;		
  int8_t   fs_old_flags;		
  u_char	 fs_fsmnt[MAXMNTLEN];	
  u_char	 fs_volname[MAXVOLLEN];	
  u_int64_t fs_swuid;		
  int32_t  fs_pad;		

  int32_t	 fs_cgrotor;		
  void 	*fs_ocsp[NOCSPTRS];	
  u_int8_t *fs_contigdirs;	
  struct	csum *fs_csp;		
  int32_t	*fs_maxcluster;		
  u_int	*fs_active;		
  int32_t	 fs_old_cpc;		
  int32_t	 fs_maxbsize;		
  int64_t	 fs_sparecon64[17];	
  int64_t	 fs_sblockloc;		
  struct	csum_total fs_cstotal;	
  ufs_time_t fs_time;
  int64_t	 fs_size;		
  int64_t	 fs_dsize;		
  ufs2_daddr_t fs_csaddr;
  int64_t	 fs_pendingblocks;	
  int32_t	 fs_pendinginodes;	
  int32_t	 fs_snapinum[FSMAXSNAP];
  int32_t	 fs_avgfilesize;	
  int32_t	 fs_avgfpdir;		
  int32_t	 fs_save_cgsize;	
  int32_t	 fs_sparecon32[26];	
  int32_t  fs_flags;		
  int32_t	 fs_contigsumsize;	 
  int32_t	 fs_maxsymlinklen;	
  int32_t	 fs_old_inodefmt;	
  u_int64_t fs_maxfilesize;	
  int64_t	 fs_qbmask;		
  int64_t	 fs_qfmask;		
  int32_t	 fs_state;		
  int32_t	 fs_old_postblformat;	
  int32_t	 fs_old_nrpos;		
  int32_t	 fs_spare5[2];		
					
  int32_t	 fs_magic;
  char  s_pad[6816];
};

int
main(int argc, char **argv)
{
  off_t seekpos;
  ssize_t rbytes;
  char *device;
  int fd;
  char *progname = argv[0];
  struct ufs2_super_block ufs2_sblock;
  struct fs fs_sblk;
  char buf[8192];            /* read so much data */

  if (argc != 2) {
    fprintf(stderr, "Usage: %s partition\n", progname);
    exit(EXIT_FAILURE);
  }

  device = argv[1];
  fd = open(device, O_RDONLY);
  if (fd < 0) {
    perror(progname);
    exit(EXIT_FAILURE);
  }

  /* seek to reiserfs offset */
  seekpos = lseek(fd, SBLOCK_UFS2, SEEK_SET);

  /* Trying for a regular ufs partition */
  rbytes = read(fd, (char *)&fs_sblk, sizeof(fs_sblk));

  if (rbytes < 0)
    perror(argv[0]);
  printf("Data read\n\n%s\n", &fs_sblk);
  return 0;
}
