sdisklabel.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. #include <ctype.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <disklabel.h>
  8. #include <sys/ioctl.h>
  9. #include <linux/hdreg.h>
  10. #include "library.h"
  11. /* from linux/fs.h */
  12. #define BLKSSZGET _IO(0x12,104) /* get block device sector size */
  13. #define BLKGETSIZE _IO(0x12,96) /* return device size */
  14. int label_modified=0;
  15. int force=0;
  16. int
  17. write_disklabel (int fd,struct disklabel *d)
  18. {
  19. dosumlabel(fd,d);
  20. if(lseek(fd,LABELOFFSET,SEEK_SET)<0) {
  21. return -1;
  22. }
  23. if(write(fd,d,sizeof(*d))!=sizeof(*d)) {
  24. return -1;
  25. }
  26. return 0;
  27. }
  28. void
  29. fixmagic (int fd,struct disklabel *d)
  30. {
  31. d->d_magic=DISKLABELMAGIC;
  32. d->d_magic2=DISKLABELMAGIC;
  33. d->d_type=DTYPE_SCSI;
  34. d->d_secsize=512;
  35. strcpy(d->d_typename,"SCSI");
  36. }
  37. void
  38. zero_disklabel (int fd,struct disklabel *d)
  39. {
  40. memset(d,0,sizeof(*d));
  41. fixmagic(fd,d);
  42. label_modified=1;
  43. }
  44. void
  45. print_disklabel(int fd,struct disklabel *d)
  46. {
  47. int x;
  48. for(x=0;x<d->d_npartitions;x++) {
  49. printf("partition %d: type %d, starts sector %d, size %d\n",
  50. x, d->d_partitions[x].p_fstype,
  51. d->d_partitions[x].p_offset, d->d_partitions[x].p_size);
  52. }
  53. }
  54. int total_disk_size, heads, sectors, cylinders;
  55. /* FIXME: use BLKSSZGET to get sector size. (depends on linux >=2.4) */
  56. int sector_size=512;
  57. #ifdef __linux__
  58. void
  59. set_disk_size (int fd)
  60. {
  61. struct hd_geometry hd;
  62. unsigned long blocks;
  63. unsigned int sectors_per_block;
  64. int r1, r2;
  65. sectors_per_block = sector_size / 512;
  66. heads = sectors = cylinders = blocks = 0;
  67. r1 = ioctl(fd,HDIO_GETGEO,&hd);
  68. if (r1) {
  69. perror("ioctl HDIO_GETGEO");
  70. } else {
  71. heads = hd.heads;
  72. sectors = hd.sectors;
  73. cylinders = hd.cylinders;
  74. if (heads * sectors * cylinders == 0) { r1 = -1; }
  75. /* fdisk says: "never use hd.cylinders - it is truncated"
  76. if BLKGETSIZE works we'll calculate our own value for
  77. cylinders in a little bit, but for now, use it anyway */
  78. total_disk_size=(heads*sectors*cylinders); /* in sectors */
  79. }
  80. r2 = ioctl(fd,BLKGETSIZE, &blocks);
  81. if (r2) {
  82. perror("ioctl BLKGETSIZE");
  83. }
  84. if (r1 && r2) {
  85. if (!total_disk_size) {
  86. fprintf(stderr, "Unable to get disk size. Please specify it with the size [size_in_sectors] option.\n\n");
  87. }
  88. return;
  89. }
  90. if (r1 == 0 && r2 == 0) {
  91. total_disk_size = blocks; /* sizes in sectors */
  92. cylinders = blocks / (heads * sectors);
  93. cylinders /= sectors_per_block;
  94. } else if (r1 == 0) {
  95. fprintf(stderr, "Unable to get disk geometry. Guessing number of sectors from disk size.\n");
  96. cylinders = heads = 1;
  97. sectors = blocks / sectors_per_block;
  98. }
  99. fprintf(stderr,"%d heads, %d sectors, %d cylinders %dK total size\n",
  100. heads, sectors, cylinders, total_disk_size/2);
  101. }
  102. #endif
  103. int
  104. set_partition (int fd,struct disklabel *d,int num,int offset,int size,int fstype)
  105. {
  106. int endplace=offset+size;
  107. int x;
  108. if(endplace>total_disk_size) {
  109. fprintf(stderr,"endplace is %d total_disk_size is %d\n",endplace,total_disk_size);
  110. if (!force) return -1;
  111. /* correct the discrepancy */
  112. size = total_disk_size-offset;
  113. endplace=total_disk_size;
  114. fprintf(stderr,"Warning: changing endplace to %d and size to %d\n",endplace,size);
  115. }
  116. if(num>d->d_npartitions) {
  117. fprintf(stderr,"Partition not consecutive! This would leave empty partitions.\nNext unset partition is %d.\n",d->d_npartitions);
  118. if (!force) return -1;
  119. }
  120. x=overlaplabel(d,offset,endplace,1U<<num);
  121. if(x!=-1)
  122. fprintf(stderr,"Warning: added partition %d overlaps with partition %d\n",num,x);
  123. d->d_partitions[num].p_offset=offset;
  124. d->d_partitions[num].p_size=size;
  125. d->d_partitions[num].p_fstype=fstype;
  126. if(num==d->d_npartitions) {
  127. d->d_npartitions++;
  128. }
  129. label_modified=1;
  130. return 0;
  131. }
  132. void
  133. usage (char *cmd_name)
  134. {
  135. fprintf(stderr,"Usage: %s drive print\n",cmd_name);
  136. fprintf(stderr," %s drive zero\n",cmd_name);
  137. fprintf(stderr," %s drive partition_number offset_in_sectors size_in_sectors partition_type\n",cmd_name);
  138. fprintf(stderr," %s drive sum\n",cmd_name);
  139. fprintf(stderr," %s drive size size_in_sectors [other command]\n\n",cmd_name);
  140. fprintf(stderr,"The print command may be placed before or after any other command.\n");
  141. fprintf(stderr,"The size command is used to override the size of the disk, if the\nprogram isn't able to obtain this information for some reason.\n");
  142. fprintf(stderr,"The partition type should be 8, unless you are creating\nlabels for OSF/1 partitions.\n");
  143. }
  144. int
  145. main (int argc,char **argv)
  146. {
  147. struct disklabel d;
  148. int fd,x;
  149. if(argc < 3) {
  150. usage(argv[0]);
  151. exit(1);
  152. }
  153. fd=open(argv[1],O_RDWR);
  154. if(fd<0) {
  155. perror("couldn't open scsi disk");
  156. exit(1);
  157. }
  158. #ifdef __linux__
  159. set_disk_size(fd);
  160. #endif
  161. if(strcmp(argv[2],"zero")==0) {
  162. zero_disklabel(fd,&d);
  163. } else {
  164. if(read_disklabel(fd,&d)) {
  165. fprintf(stderr,"Error reading disklabel\n");
  166. exit(1);
  167. }
  168. }
  169. for(x=2;x<argc;) {
  170. if(strcmp(argv[x],"size")==0 && ((x+1)<argc)) {
  171. total_disk_size=atoi(argv[x+1]);
  172. x+=2;
  173. }
  174. if(strcmp(argv[x],"sum")==0) {
  175. dosumlabel(fd,&d);
  176. x++;
  177. }
  178. else if(strcmp(argv[x],"zero")==0) {
  179. zero_disklabel(fd,&d);
  180. x++;
  181. }
  182. else if(strcmp(argv[x],"print")==0) {
  183. print_disklabel(fd,&d);
  184. x++;
  185. }
  186. else if(strcmp(argv[x],"force")==0) {
  187. force=1;
  188. x++;
  189. }
  190. else {
  191. if((argc-x)>3 && isdigit(argv[x][0]) && isdigit(argv[x+1][0]) && isdigit(argv[x+2][0]) && isdigit(argv[x+3][0])) {
  192. int partnum=atoi(argv[x]);
  193. int offset=atoi(argv[x+1]);
  194. int size=atoi(argv[x+2]);
  195. int fstype=atoi(argv[x+3]);
  196. if(partnum<0 || partnum>7) {
  197. fprintf(stderr,"Partition number %d out of range--partitions should be between 0 and 7\n",partnum);
  198. exit(1);
  199. }
  200. if(set_partition(fd,&d,partnum,offset,size,fstype)) {
  201. fprintf(stderr,"Set of partition failed\n");
  202. exit(1);
  203. }
  204. x+=4;
  205. } else {
  206. fprintf(stderr,"Unrecognized option %s\n",argv[x]);
  207. usage(argv[0]);
  208. exit(1);
  209. }
  210. }
  211. }
  212. if(label_modified && write_disklabel(fd,&d)) {
  213. fprintf(stderr,"Error writing disklabel\n");
  214. exit(1);
  215. }
  216. return 0;
  217. }