home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / bootutil / bootmenu.lzh / bootmenu13.1 / pfdisk.c < prev    next >
C/C++ Source or Header  |  1991-03-12  |  16KB  |  566 lines

  1. /*
  2.  * pfdisk - Partition a Fixed DISK
  3.  *    by Gordon W. Ross, Jan. 1990
  4.  *
  5.  * See the file "pfdisk.doc" for user instructions.
  6.  *
  7.  * This program uses a simple, line-oriented interpreter,
  8.  * designed for both interactive and non-interactive use.
  9.  * To facilitate non-interactive use, the output from the
  10.  * 'L' (list partitions) command is carefully arranged so it
  11.  * can be used directly as command input.  Neat trick, eh?
  12.  */
  13.  
  14. char *versionString =
  15.   "# pfdisk version 1.3 by Gordon W. Ross  Oct. 1990\n";
  16.  
  17. /* These don't really matter.  The user is asked to set them. */
  18. #define DEFAULT_CYLS 306
  19. #define DEFAULT_HEADS 4
  20. #define DEFAULT_SECTORS 17
  21. #define PROMPT_STRING "pfdisk> "
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include "sysdep.h"
  27. #include "syscodes.h"
  28.  
  29. typedef unsigned char uchar;
  30. typedef unsigned int uint;
  31. typedef unsigned long ulong;
  32.  
  33. struct part {    /* An entry in the partition table */
  34.   uchar    active;        /* active flag (0x80 or 0) */
  35.   uchar    b_head;        /* begin head */
  36.   uchar    b_sec;        /*      sector */
  37.   uchar    b_cyl;        /*     cylinder */
  38.   uchar    sysid;        /* system id (see sysid.c) */
  39.   uchar    e_head;        /* end  head */
  40.   uchar    e_sec;        /* end    sector */
  41.   uchar    e_cyl;        /* end    cylinder */
  42.   /* These two are just longs, but this way is machine independent. */
  43.   uchar    lsBeg[4];    /* logical sectors, beginning */
  44.   uchar    lsLen[4];    /* logical sectors, length */
  45. };
  46.  
  47. #define LOC_PT        0x1BE
  48. #define LOC_NT        0x180
  49. #define LOC_GWR        0x1A0
  50. #define MAGIC_LOC    0x1FE
  51. #define MAGIC_0        0x55
  52. #define MAGIC_1        0xAA
  53. #define MAX_LINE    80
  54.  
  55. char    buffer[SECSIZE];    /* The boot block buffer */
  56. int    bufmod=0;        /* buffer modified... */
  57.         /* (zero means buffer is unmodified) */
  58. int    useNTable;        /* boot sector uses name table */
  59.  
  60. /* device parameters (force someone to set them!) */
  61. unsigned cyls = DEFAULT_CYLS;
  62. unsigned heads = DEFAULT_HEADS;
  63. unsigned sectors = DEFAULT_SECTORS;
  64.  
  65. char    *devname;        /* device name */
  66. char    cmdline[MAX_LINE];
  67. char    filename[80];        /* used by r/w commands */
  68. char    *prompt;        /* null if no tty input */
  69.  
  70. /* Some of these strings are used in more than one place.
  71.  * For consistency, I put a newline on all of them.
  72.  */
  73. char h_h[] = "? <enter>             : Help summary\n";
  74. char h_l[] = "L                     : List partition table\n";
  75. char h_1[] = "1 id first last name  : set partition 1\n";
  76. char h_2[] = "2,3,4 ... (like 1)    : set respective partition\n";
  77. char h_a[] = "A n                   : Activate partition n\n";
  78. char h_g[] = "G cyls heads sectors  : set disk Geometry\n";
  79. char h_i[] = "I                     : list known ID numbers\n";
  80. char h_r[] = "R [optional-file]     : Read  device (or specified file)\n";
  81. char h_w[] = "W [optional-file]     : Write device (or specified file)\n";
  82. char h_q[] = "Q[!]                  : Quit (! means force)\n";
  83.  
  84. char * helpTable[] = {
  85. h_h, h_l, h_1, h_2, h_a, h_g, h_i, h_r, h_w, h_q,
  86. "# (All command letters have lower-case equivalents.)\n",
  87. (char *) 0 }; /* This MUST have a zero as the last element */
  88.  
  89. char *BadArg="Error: bad argument: %s\n";
  90. char *WarnNotSaved =
  91.     "Warning, modified partition table not saved.\n";
  92.  
  93. /* forward declarations */
  94. void    main();
  95. void    help();
  96. void    listPTable();
  97. void    checkValidity();
  98. char *    setPartition();
  99. char *    makeActive();
  100. char *    setGeometry();
  101. void    long2chs();
  102. ulong    chs2long();
  103. char *    nameID();
  104. void    printIDs();
  105.  
  106. void help()
  107. {
  108.   char ** p;
  109.   for (p = helpTable; *p; p++)
  110.     printf(*p);
  111. }
  112.  
  113. void main(argc,argv)
  114. int    argc;
  115. char    *argv[];
  116. {
  117.   char    *cmdp;        /* points to command word */
  118.   char    *argp;        /* points to command args */
  119.  
  120.   /* check command line args (device name) */
  121.   if (argc != 2) {
  122.     usage(argv[0]);    /* See s-sysname.c */
  123.     exit(1);
  124.   }
  125.   devname = argv[1];
  126.  
  127.   /* Should we prompt? */
  128.   prompt = (isatty(fileno(stdin))) ? PROMPT_STRING : (char *) 0;
  129.  
  130.   /* Print version name. */
  131.   fputs(versionString, stderr);
  132.  
  133.   /* get disk parameters */
  134.   getGeometry(devname,&cyls,&heads,§ors);
  135.  
  136.   /* Get the boot block. */
  137.   if (getBBlk(devname, buffer) < 0)
  138.     fprintf(stderr,"%s: read failed\n", devname);
  139.   checkValidity();
  140.  
  141.   if (prompt) fprintf(stderr,"For help, enter: '?'\n");
  142.  
  143.  
  144.   /* Read and process commands a line at a time. */
  145.   while (1) {
  146.     if (prompt) fputs(prompt,stdout);
  147.     if (! fgets(cmdline, MAX_LINE, stdin)) break;
  148.  
  149.     /* Find beginning of command word */
  150.     cmdp = cmdline;
  151.     while (isspace(*cmdp)) cmdp++;
  152.  
  153.     /* find beginning of args */
  154.     argp = cmdp;
  155.     while (*argp && !isspace(*argp)) argp++;
  156.     while (isspace(*argp) || *argp=='=') argp++;
  157.  
  158.     switch (*cmdp) {
  159.  
  160.     case '\0':        /* blank line */
  161.     case '#':        /* line comment */
  162.       break;
  163.  
  164.     case '?': case 'h': case 'H':
  165.       help();
  166.       break;
  167.  
  168.     case '1':    /* set partition entry */
  169.     case '2': case '3': case '4':
  170.       argp = setPartition(cmdp, argp);
  171.       if (argp) {    /* arg list error */
  172.     fprintf(stderr,BadArg,argp);
  173.     fprintf(stderr,h_1);
  174.     fprintf(stderr,h_2);
  175.     break;
  176.       }
  177.       bufmod = 1;
  178.       break;
  179.  
  180.     case 'a': case 'A':    /* activate partition */
  181.       argp = makeActive(argp);
  182.       if (argp) {
  183.     fprintf(stderr,BadArg,argp);
  184.     fprintf(stderr,h_a);
  185.     break;
  186.       }
  187.       bufmod = 1;
  188.       break;
  189.  
  190.     case 'g': case 'G':    /* set disk parameters (Geometry) */
  191.       argp = setGeometry(argp);
  192.       if (argp) {    /* arg list error */
  193.     fprintf(stderr,BadArg,argp);
  194.     fprintf(stderr,h_g);
  195.       }
  196.       break;
  197.  
  198.     case 'i': case 'I':    /* List known ID numbers */
  199.       printIDs();
  200.       break;
  201.  
  202.     case 'l': case 'L':    /* List the partition table */
  203.       listPTable();
  204.       break;
  205.  
  206.     case 'q': case 'Q':    /* Quit */
  207.       if (bufmod && (cmdp[1]  != '!')) {
  208.     fprintf(stderr,"\007%s%s\n", WarnNotSaved,
  209.         "Use 'wq' or 'q!' (enter ? for help).");
  210.     break;
  211.       }
  212.       exit(0);
  213.       /*NOTREACHED*/
  214.  
  215.     case 'r': case 'R':    /* read from device or file */
  216.       if (sscanf(argp,"%80s",filename) == 1) {
  217.     /* Arg specified, read from filename */
  218.     if (getFile(filename, buffer, SECSIZE) < 0)
  219.       fprintf(stderr,"%s: read failed\n", filename);
  220.     bufmod = 1;
  221.       } else {
  222.     /* No arg, use device. */
  223.     if (getBBlk(devname, buffer) < 0)
  224.       fprintf(stderr,"%s: read failed\n", devname);
  225.     bufmod = 0;
  226.       }
  227.       checkValidity();
  228.       break;
  229.  
  230.     case 'w': case 'W':    /* Write to file or device */
  231.       if (sscanf(argp,"%80s",filename) == 1) {
  232.     /* Arg specified, write to filename */
  233.     if (putFile(filename, buffer, SECSIZE) < 0)
  234.       fprintf(stderr, "%s: write failed\n", filename);
  235.       } else {  /* No arg, use device. */
  236.     if (putBBlk(devname, buffer) < 0)
  237.       fprintf(stderr, "%s: write failed\n", devname);
  238.     bufmod = 0;
  239.       }
  240.       if (cmdp[1] == 'q' || cmdp[1] == 'Q') exit(0);
  241.       break;
  242.  
  243.     default:
  244.       fprintf(stderr,"'%c': unrecognized.  Enter '?' for help.\n", *cmdp);
  245.       break;
  246.  
  247.     } /* switch */
  248.   } /* while */
  249.   if (bufmod) fprintf(stderr, WarnNotSaved);
  250.   exit(0);
  251. } /* main */
  252.  
  253.  
  254. /* Check for valid boot block (magic number in last two bytes).
  255.  * Also, check for presence of partition name table.
  256.  */
  257. void checkValidity()
  258. {
  259.   /* Check the magic number. */
  260.   if ((buffer[MAGIC_LOC] & 0xFF) != MAGIC_0 ||
  261.       (buffer[MAGIC_LOC+1] & 0xFF) != MAGIC_1 ) {
  262.     /* The boot sector is not valid -- Fix it. */
  263.     buffer[MAGIC_LOC] = MAGIC_0;
  264.     buffer[MAGIC_LOC+1] = MAGIC_1;
  265.     bufmod = 1;
  266.     fprintf(stderr,
  267. "\n\tWarning:  The boot sector has an invalid magic number.\n\
  268. \tThe magic number has been fixed, but the other contents\n\
  269. \tare probably garbage.  Initialize using the command:\n\
  270. \t\tR boot-program-file    (i.e. bootmenu.bin)\n\
  271. \tthen set each partition entry if necessary.\n");
  272.   }
  273.  
  274.   /* Does it use a name table (for a boot menu)?
  275.    * My boot program does, and can be identified by
  276.    * finding my name in a particular (unused) area.
  277.    */
  278.   useNTable = !strcmp(buffer+LOC_GWR, "Gordon W. Ross");
  279.  
  280. }
  281.  
  282. char * setPartition(cmdp,argp)    /* return string on error */
  283. char    *cmdp,*argp;
  284. {
  285.   struct part *pp;    /* partition entry */
  286.   char *    np;        /* name table pointer */
  287.   char *    newname;    /* name field */
  288.   int    index;        /* partition index (0..3) */
  289.   uint    id;        /* ID code (see syscodes.c) */
  290.   uint    first,last;    /* user supplied cylinders */
  291.   uint    c,h,s;        /* working cyl,head,sect, */
  292.   uint    len;        /* chars seen by sscanf */
  293.   ulong    lsbeg, lslen;    /* logical begin, length */
  294.  
  295.   /* Value check the index */
  296.   index = *cmdp - '1';
  297.   if (index < 0 || index > 3)
  298.     return("index");
  299.   pp = (struct part *) (buffer + LOC_PT + index * 16);
  300.   np = buffer + LOC_NT + index * 8;
  301.  
  302.   /* Read System ID */
  303.   if (sscanf(argp,"%i%n", &id, &len) < 1)
  304.     return("id");
  305.   argp += len;
  306.  
  307.   /* If ID==0, just clear out the entry and return. */
  308.   if (id == 0) {
  309.     strncpy( (char *) pp, "", 16);
  310.     if (useNTable) strncpy( np, "", 8);
  311.     return((char *)0);
  312.   }
  313.  
  314.   /* Read first and last cylinder */
  315.   if (sscanf(argp,"%i%i%n",&first, &last, &len) < 2)
  316.     return("first last (missing)");
  317.   argp += len;
  318.  
  319.   /* Reasonable start,end cylinder numbers? */
  320.   if (first > last)    return("first > last");
  321.   if (first > 1023)    return("first > 1023");
  322.   if (last >= cyls)    return("last >= cyls");
  323.  
  324.   /* Get (optional) system name. */
  325.   if (*argp == '\n') {    /* no name given, use default */
  326.     newname = nameID(id);
  327.   } else {        /* use the given name */
  328.     /* skip leading space */
  329.     while (*argp == ' ') argp++;
  330.     newname = argp;
  331.     /* Remove newline from end */
  332.     while (isgraph(*argp)||*argp==' ') argp++;
  333.     *argp = '\0';
  334.     useNTable = 1;
  335.   }
  336.  
  337.   /* Set the ID and name. */
  338.   pp->sysid = id;
  339.   if (useNTable) {
  340.     strncpy(np, newname, 8);
  341.     strcpy(buffer + LOC_GWR, "Gordon W. Ross");
  342.   }
  343.  
  344.   /* set beginning c,h,s */
  345.   c = first;
  346.   /* if c == 0, head == 1 (reserve track 0) */
  347.   h = (first) ? 0 : 1;
  348.   s = 1;
  349.   pp->b_cyl = c & 0xFF;
  350.   pp->b_head = h;
  351.   pp->b_sec = s | ((c >> 2) & 0xC0);
  352.   /* Set the logical sector begin field */
  353.   lsbeg = lslen = chs2long(c,h,s); /* using lslen as temp. */
  354.   pp->lsBeg[0] = lslen & 0xff; lslen >>= 8;
  355.   pp->lsBeg[1] = lslen & 0xff; lslen >>= 8;
  356.   pp->lsBeg[2] = lslen & 0xff; lslen >>= 8;
  357.   pp->lsBeg[3] = lslen & 0xff; lslen >>= 8;
  358.  
  359.   /* set ending c,h,s (last may be larger than 1023) */
  360.   c = (last>1023) ? 1023 : last; /* limit c to 1023 */
  361.   h = heads - 1; s = sectors;
  362.   pp->e_cyl = c & 0xFF;
  363.   pp->e_head = h;
  364.   pp->e_sec = s | ((c >> 2) & 0xC0);
  365.   /* Set the logical sector length field (using REAL end cylinder) */
  366.   lslen = chs2long(last,h,s) + 1 - lsbeg;
  367.   pp->lsLen[0] = lslen & 0xff; lslen >>= 8;
  368.   pp->lsLen[1] = lslen & 0xff; lslen >>= 8;
  369.   pp->lsLen[2] = lslen & 0xff; lslen >>= 8;
  370.   pp->lsLen[3] = lslen & 0xff; lslen >>= 8;
  371.  
  372.   return((char *)0);    /* success */
  373. } /* setPartition() */
  374.  
  375. char * makeActive(argp)    /* return error string or zero */
  376. char    *argp;
  377. {
  378.   struct part *pp;    /* partition entry */
  379.   int    i,act;        /* which one becomes active */
  380.  
  381.   if (sscanf(argp,"%d", &act) < 1)
  382.     return("missing index");
  383.   act--;            /* make it zero-origin */
  384.  
  385.   i=0; pp = (struct part *) (buffer + LOC_PT);
  386.   while (i<4) {
  387.     pp->active = 0;
  388.     if (i == act) {
  389.       if (pp->sysid == 0) return("partition empty");
  390.       pp->active = 0x80;
  391.     }
  392.     i++; pp++;
  393.   }
  394.   return((char *)0);
  395. }
  396.  
  397. char * setGeometry(argp)    /* return string on error */
  398. char    *argp;
  399. {
  400.   int    c,h,s;
  401.  
  402.   if (sscanf(argp,"%i%i%i", &c, &h, &s) < 3)
  403.     return("(missing)");
  404.   if (c<1) return("cyls");
  405.   if (h<1) return("heads");
  406.   if (s<1) return("sectors");
  407.   cyls=c; heads=h; sectors=s;
  408.   return((char *)0);
  409. }
  410.  
  411. void listPTable()        /* print out partition table */
  412. {
  413.   struct part * pp;    /* partition table entry */
  414.   int    i;        /* partition number */
  415.   int    numActive=0;    /* active partition [1-4], 0==none */
  416.   uint    pbc,pbh,pbs;    /* physical beginning  c,h,s */
  417.   uint    pec,peh,pes;    /* physical ending     c,h,s */
  418.   uint    lbc,lbh,lbs;    /* logical beginning   c,h,s */
  419.   uint    lec,leh,les;    /* logical ending      c,h,s */
  420.   ulong    lsbeg,lslen;    /* logical sectors: begin, length */
  421.  
  422.   printf("# Partition table on device: %s\n", devname);
  423.   printf("geometry %d %d %d (cyls heads sectors)\n",
  424.      cyls, heads, sectors);
  425.   printf("#  ID  First(cyl)  Last(cyl)  Name     ");
  426.   printf("# start, length (sectors)\n");
  427.  
  428.   for (i=0; i<4; i++) {
  429.     pp = (struct part *) (buffer + LOC_PT + i * 16);
  430.  
  431.     if (pp->active) {
  432.       if(numActive)
  433.     fprintf(stderr,"Error: multiple active partitions.\n");
  434.       else numActive = i+1;
  435.     }
  436.  
  437.     /* physical beginning c,h,s */
  438.     pbc = pp->b_cyl & 0xff | (pp->b_sec << 2) & 0x300;
  439.     pbh = pp->b_head;
  440.     pbs = pp->b_sec & 0x3F;
  441.  
  442.     /* physical ending c,h,s */
  443.     pec = pp->e_cyl & 0xff | (pp->e_sec << 2) & 0x300;
  444.     peh = pp->e_head;
  445.     pes = pp->e_sec & 0x3F;
  446.  
  447.     /* compute logical beginning (c,h,s) */
  448.     lsbeg = ((((((pp->lsBeg[3] ) << 8 )
  449.         | pp->lsBeg[2] ) << 8 )
  450.         | pp->lsBeg[1] ) << 8 )
  451.         | pp->lsBeg[0] ;
  452.     long2chs(lsbeg, &lbc, &lbh, &lbs);
  453.     /* compute logical ending (c,h,s) */
  454.     lslen = ((((((pp->lsLen[3]) << 8 )
  455.         | pp->lsLen[2]) << 8 )
  456.         | pp->lsLen[1]) << 8 )
  457.         | pp->lsLen[0] ;
  458.     /* keep beginning <= end ... */
  459.     if (lslen > 0) long2chs(lsbeg+lslen-1, &lec, &leh, &les);
  460.     else       long2chs(lsbeg,       &lec, &leh, &les);
  461.  
  462.     /* show physical begin, logical end (works for cyl>1023) */
  463.     /*      #  ID  First(cyl)  Last(cyl)  Name... # ... */
  464.     printf("%d %3d   %4d       %4d       ", i+1, pp->sysid, pbc, lec);
  465.     if (useNTable) printf("%-8.8s ", buffer + LOC_NT + i * 8);
  466.     else       printf("# %-8.8s ", nameID((uint) pp->sysid));
  467.     printf("# %ld, %ld\n", lsbeg, lslen );
  468.  
  469.     /* That's all, for an empty partition. */
  470.     if (pp->sysid == 0) continue;
  471.  
  472.     /*
  473.      * Now do some consistency checks...
  474.      */
  475.  
  476.     /* Same physical / logical beginning? */
  477.     if (pbc != lbc || pbh != lbh || pbs != lbs ) {
  478.       printf("# note: first(%d): ", i+1);
  479.       printf("phys=(%d,%d,%d) ",    pbc, pbh, pbs);
  480.       printf("logical=(%d,%d,%d)\n",lbc, lbh, lbs);
  481.     }
  482.     /* Same physical / logical ending? */
  483.     if (pec != lec || peh != leh || pes != les ) {
  484.       printf("# note:  last(%d): ", i+1);
  485.       printf("phys=(%d,%d,%d) ",    pec, peh, pes);
  486.       printf("logical=(%d,%d,%d)\n",lec, leh, les);
  487.     }
  488.  
  489.     /* Beginning on cylinder boundary? */
  490.     if (pbc == 0) { /* exception: start on head 1 */
  491.       if (pbh != 1 || pbs != 1) {
  492.     printf("# note: first(%i): ", i+1);
  493.     printf("phys=(%d,%d,%d) ", pbc, pbh, pbs);
  494.     printf("should be (%d,1,1)\n", pbc);
  495.       }
  496.     } else { /* not on cyl 0 */
  497.       if (pbh != 0 || pbs != 1) {
  498.     printf("# note: first(%i): ", i+1);
  499.     printf("phys=(%d,%d,%d) ", pbc, pbh, pbs);
  500.     printf("should be (%d,0,1)\n", pbc);
  501.       }
  502.     }
  503.  
  504.     /* Ending on cylinder boundary? */
  505.     if (peh != (heads-1) || pes != sectors) {
  506.       printf("# note: last(%i): ", i+1);
  507.       printf("phys=(%d,%d,%d) ", pec, peh, pes);
  508.       printf("should be (%d,%d,%d)\n",
  509.          pec, heads-1, sectors);
  510.     }
  511.  
  512.   } /* for */
  513.   printf("active: %d  %s\n", numActive,
  514.      (numActive) ? "" : "(none)");
  515. } /* listPTable() */
  516.  
  517. ulong chs2long(c,h,s)
  518. uint c,h,s;
  519. {
  520.   ulong    l;
  521.   if (s<1) s=1;
  522.   l  = c; l *= heads;
  523.   l += h; l *= sectors;
  524.   l += (s - 1);
  525.   return(l);
  526. }
  527.  
  528. void long2chs(ls, c, h, s)    /* convert logical sec-num to c,h,s */
  529. ulong    ls;        /* Logical Sector number */
  530. uint    *c,*h,*s;    /* cyl, head, sector */
  531. {
  532.   int    spc = heads * sectors;
  533.   *c = ls / spc;
  534.   ls = ls % spc;
  535.   *h = ls / sectors;
  536.   *s = ls % sectors + 1;    /* sectors count from 1 */
  537. }
  538.  
  539. char * nameID(n)
  540. unsigned int n;
  541. {
  542.   struct intString *is;
  543.  
  544.   is = sysCodes;
  545.   while (is->i) {
  546.     if (is->i == n) return(is->s);
  547.     is++;
  548.   }
  549.   if (!n) return(is->s);
  550.   return("unknown");
  551. }
  552.  
  553. void printIDs()        /* print the known system IDs */
  554. {
  555.   struct intString * is = sysCodes;
  556.  
  557.   /* This might need to do more processing eventually, i.e.
  558.    * if (prompt) { ... do more processing ... }
  559.    */
  560.   printf("_ID_\t__Name__ ____Description____\n");
  561.   while (is->i) {
  562.     printf("%3d\t%s\n", is->i, is->s);
  563.     is++;
  564.   }
  565. }
  566.