]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/mkswap.c
Remove now unused <sys/ioctl.h> includes
[thirdparty/util-linux.git] / disk-utils / mkswap.c
1 /*
2 * mkswap.c - set up a linux swap device
3 *
4 * (C) 1991 Linus Torvalds. This file may be redistributed as per
5 * the Linux copyright.
6 */
7
8 /*
9 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
10 *
11 * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
12 *
13 * -c for readability checking. (Use it unless you are SURE!)
14 * -vN for swap areas version N. (Only N=0,1 known today.)
15 * -f for forcing swap creation even if it would smash partition table.
16 *
17 * The device may be a block device or an image of one, but this isn't
18 * enforced (but it's not much fun on a character device :-).
19 *
20 * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
21 * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995.
22 *
23 * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
24 *
25 * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
26 * V1_MAX_PAGES fixes, jj, 990325.
27 * sparc64 fixes, jj, 000219.
28 *
29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
30 * - added Native Language Support
31 *
32 */
33
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <limits.h>
40 #include <mntent.h>
41 #include <sys/utsname.h>
42 #include <sys/stat.h>
43 #include <errno.h>
44 #ifdef HAVE_LIBSELINUX
45 #include <selinux/selinux.h>
46 #include <selinux/context.h>
47 #endif
48
49 #include "linux_version.h"
50 #include "swapheader.h"
51 #include "xstrncpy.h"
52 #include "nls.h"
53 #include "blkdev.h"
54 #include "pathnames.h"
55 #include "wholedisk.h"
56
57 #ifdef HAVE_LIBUUID
58 # ifdef HAVE_UUID_UUID_H
59 # include <uuid/uuid.h>
60 # else
61 # include <uuid.h>
62 # endif
63 #endif
64
65 #ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS
66 # include <blkid.h>
67 #endif
68
69 static char * program_name = "mkswap";
70 static char * device_name = NULL;
71 static int DEV = -1;
72 static unsigned long long PAGES = 0;
73 static unsigned long badpages = 0;
74 static int check = 0;
75
76 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
77
78 #ifdef __sparc__
79 # ifdef __arch64__
80 # define is_sparc64() 1
81 # define is_be64() 1
82 # else /* sparc32 */
83 static int
84 is_sparc64(void) {
85 struct utsname un;
86 static int sparc64 = -1;
87
88 if (sparc64 != -1) return sparc64;
89 sparc64 = 0;
90
91 if (uname(&un) < 0) return 0;
92 if (! strcmp(un.machine, "sparc64")) {
93 sparc64 = 1;
94 return 1;
95 }
96 if (strcmp(un.machine, "sparc"))
97 return 0; /* Should not happen */
98
99 #ifdef HAVE_PERSONALITY
100 {
101 extern int personality(unsigned long);
102 int oldpers;
103 #define PERS_LINUX 0x00000000
104 #define PERS_LINUX_32BIT 0x00800000
105 #define PERS_LINUX32 0x00000008
106
107 oldpers = personality(PERS_LINUX_32BIT);
108 if (oldpers != -1) {
109 if (personality(PERS_LINUX) != -1) {
110 uname(&un);
111 if (! strcmp(un.machine, "sparc64")) {
112 sparc64 = 1;
113 oldpers = PERS_LINUX32;
114 }
115 }
116 personality(oldpers);
117 }
118 }
119 #endif
120
121 return sparc64;
122 }
123 # define is_be64() is_sparc64()
124 # endif /* sparc32 */
125 #else /* !sparc */
126 # define is_be64() 0
127 #endif
128
129 /*
130 * The definition of the union swap_header uses the kernel constant PAGE_SIZE.
131 * Unfortunately, on some architectures this depends on the hardware model, and
132 * can only be found at run time -- we use getpagesize(), so that we do not
133 * need separate binaries e.g. for sun4, sun4c/d/m and sun4u.
134 *
135 * Even more unfortunately, getpagesize() does not always return the right
136 * information. For example, libc4, libc5 and glibc 2.0 do not use the system
137 * call but invent a value themselves (EXEC_PAGESIZE or NBPG * CLSIZE or NBPC),
138 * and thus it may happen that e.g. on a sparc kernel PAGE_SIZE=4096 and
139 * getpagesize() returns 8192.
140 *
141 * What to do? Let us allow the user to specify the pagesize explicitly.
142 *
143 */
144 static int user_pagesize;
145 static int pagesize;
146 static unsigned long *signature_page = NULL;
147 struct swap_header_v1 *p;
148
149 static void
150 init_signature_page(void) {
151
152 int kernel_pagesize = pagesize = getpagesize();
153
154 if (user_pagesize) {
155 if ((user_pagesize & (user_pagesize-1)) ||
156 user_pagesize < 1024) {
157 fprintf(stderr, _("Bad user-specified page size %d\n"),
158 user_pagesize);
159 exit(1);
160 }
161 pagesize = user_pagesize;
162 }
163
164 if (user_pagesize && user_pagesize != kernel_pagesize)
165 fprintf(stderr, _("Using user-specified page size %d, "
166 "instead of the system value %d\n"),
167 pagesize, kernel_pagesize);
168
169 signature_page = (unsigned long *) malloc(pagesize);
170 memset(signature_page, 0, pagesize);
171 p = (struct swap_header_v1 *) signature_page;
172 }
173
174 static void
175 deinit_signature_page(void) {
176 free(signature_page);
177 }
178
179 static void
180 write_signature(char *sig) {
181 char *sp = (char *) signature_page;
182
183 strncpy(sp+pagesize-10, sig, 10);
184 }
185
186 static void
187 write_uuid_and_label(unsigned char *uuid, char *volume_name) {
188 struct swap_header_v1_2 *h;
189
190 /* Sanity check */
191 if (sizeof(struct swap_header_v1) !=
192 sizeof(struct swap_header_v1_2)) {
193 fprintf(stderr,
194 _("Bad swap header size, no label written.\n"));
195 return;
196 }
197
198 h = (struct swap_header_v1_2 *) signature_page;
199 if (uuid)
200 memcpy(h->uuid, uuid, sizeof(h->uuid));
201 if (volume_name) {
202 xstrncpy(h->volume_name, volume_name, sizeof(h->volume_name));
203 if (strlen(volume_name) > strlen(h->volume_name))
204 fprintf(stderr, _("Label was truncated.\n"));
205 }
206 if (uuid || volume_name) {
207 if (volume_name)
208 printf("LABEL=%s, ", h->volume_name);
209 else
210 printf(_("no label, "));
211 #ifdef HAVE_LIBUUID
212 if (uuid) {
213 char uuid_string[37];
214 uuid_unparse(uuid, uuid_string);
215 printf("UUID=%s\n", uuid_string);
216 } else
217 #endif
218 printf(_("no uuid\n"));
219 }
220 }
221
222 /*
223 * Find out what the maximum amount of swap space is that the kernel will
224 * handle. This wouldn't matter if the kernel just used as much of the
225 * swap space as it can handle, but until 2.3.4 it would return an error
226 * to swapon() if the swapspace was too large.
227 */
228 /* Before 2.2.0pre9 */
229 #define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
230 /* Since 2.2.0pre9, before 2.3.4:
231 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
232 with variations on
233 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
234 #define SWP_OFFSET(entry) ((entry) >> 8)
235 on the various architectures. Below the result - yuk.
236
237 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
238 i386 2^12 o<<8 e>>8 1<<24 1<<19
239 mips 2^12 o<<15 e>>15 1<<17 1<<19
240 alpha 2^13 o<<40 e>>40 1<<24 1<<18
241 m68k 2^12 o<<12 e>>12 1<<20 1<<19
242 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
243 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
244 ppc 2^12 o<<8 e>>8 1<<24 1<<19
245 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
246 armv 2^12 o<<9 e>>9 1<<23 1<<19
247
248 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
249
250 The bad part is that we need to know this since the kernel will
251 refuse a swap space if it is too large.
252 */
253 /* patch from jj - why does this differ from the above? */
254 /* 32bit kernels have a second limitation of 2GB, sparc64 is limited by
255 the size of virtual address space allocation for vmalloc */
256 #if defined(__alpha__)
257 #define V1_MAX_PAGES ((1 << 24) - 1)
258 #elif defined(__mips__)
259 #define V1_MAX_PAGES ((1 << 17) - 1)
260 #elif defined(__sparc__)
261 #define V1_MAX_PAGES (is_sparc64() ? ((3 << 29) - 1) : ((1 << 18) - 1))
262 #elif defined(__ia64__)
263 /*
264 * The actual size will depend on the amount of virtual address space
265 * available to vmalloc the swap map.
266 */
267 #define V1_MAX_PAGES ((1UL << 54) - 1)
268 #else
269 #define V1_MAX_PAGES V1_OLD_MAX_PAGES
270 #endif
271 /* man page now says:
272 The maximum useful size of a swap area now depends on the architecture.
273 It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
274 128GB on alpha and 3TB on sparc64.
275 */
276
277 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
278 #define MIN_GOODPAGES 10
279
280 static void
281 usage(void) {
282 fprintf(stderr,
283 _("Usage: %s [-c] [-pPAGESZ] [-L label] [-U UUID] /dev/name [blocks]\n"),
284 program_name);
285 exit(1);
286 }
287
288 static void
289 die(const char *str) {
290 fprintf(stderr, "%s: %s\n", program_name, str);
291 exit(1);
292 }
293
294 static void
295 page_bad(int page) {
296 if (badpages == MAX_BADPAGES)
297 die(_("too many bad pages"));
298 p->badpages[badpages] = page;
299 badpages++;
300 }
301
302 static void
303 check_blocks(void) {
304 unsigned int current_page;
305 int do_seek = 1;
306 char *buffer;
307
308 buffer = malloc(pagesize);
309 if (!buffer)
310 die(_("Out of memory"));
311 current_page = 0;
312 while (current_page < PAGES) {
313 if (do_seek && lseek(DEV,current_page*pagesize,SEEK_SET) !=
314 current_page*pagesize)
315 die(_("seek failed in check_blocks"));
316 if ((do_seek = (pagesize != read(DEV, buffer, pagesize))))
317 page_bad(current_page);
318 current_page++;
319 }
320 if (badpages == 1)
321 printf(_("one bad page\n"));
322 else if (badpages > 1)
323 printf(_("%lu bad pages\n"), badpages);
324 free(buffer);
325 }
326
327 /* return size in pages */
328 static unsigned long long
329 get_size(const char *file) {
330 int fd;
331 unsigned long long size;
332
333 fd = open(file, O_RDONLY);
334 if (fd < 0) {
335 perror(file);
336 exit(1);
337 }
338 if (blkdev_get_size(fd, &size) == 0)
339 size /= pagesize;
340 else
341 size = blkdev_find_size(fd) / pagesize;
342
343 close(fd);
344 return size;
345 }
346
347 static int
348 isnzdigit(char c) {
349 return (c >= '1' && c <= '9');
350 }
351
352
353 /*
354 * Check to make certain that our new filesystem won't be created on
355 * an already mounted partition. Code adapted from mke2fs, Copyright
356 * (C) 1994 Theodore Ts'o. Also licensed under GPL.
357 * (C) 2006 Karel Zak -- port to mkswap
358 */
359 static int
360 check_mount(void) {
361 FILE * f;
362 struct mntent * mnt;
363
364 if ((f = setmntent (_PATH_MOUNTED, "r")) == NULL)
365 return 0;
366 while ((mnt = getmntent (f)) != NULL)
367 if (strcmp (device_name, mnt->mnt_fsname) == 0)
368 break;
369 endmntent (f);
370 if (!mnt)
371 return 0;
372 return 1;
373 }
374
375
376 static int
377 write_all(int fd, const void *buf, size_t count) {
378 while(count) {
379 ssize_t tmp;
380
381 errno = 0;
382 tmp = write(fd, buf, count);
383 if (tmp > 0) {
384 count -= tmp;
385 if (count)
386 buf += tmp;
387 } else if (errno != EINTR && errno != EAGAIN)
388 return -1;
389 }
390 return 0;
391 }
392
393 static void
394 zap_bootbits(int fd, const char *devname, int force)
395 {
396 char *type = NULL;
397 int whole = 0;
398 int zap = 1;
399
400 if (!force) {
401 if (lseek(fd, 0, SEEK_SET) != 0)
402 die(_("unable to rewind swap-device"));
403
404 if (is_whole_disk_fd(fd, devname)) {
405 /* don't zap bootbits on whole disk -- we know nothing
406 * about bootloaders on the device */
407 whole = 1;
408 zap = 0;
409 } else {
410 #ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS
411 blkid_probe pr = blkid_new_probe();
412 if (!pr)
413 die(_("unable to alloc new libblkid probe"));
414 if (blkid_probe_set_device(pr, fd, 0, 0))
415 die(_("unable to assign device to liblkid probe"));
416
417 blkid_probe_enable_partitions(pr, 1);
418 blkid_probe_enable_superblocks(pr, 0);
419
420 if (blkid_do_fullprobe(pr) == 0)
421 blkid_probe_lookup_value(pr, "PTTYPE",
422 (const char **) &type, NULL);
423 if (type) {
424 type = strdup(type);
425 zap = 0;
426 }
427 blkid_free_probe(pr);
428 #else
429 /* don't zap if compiled without libblkid */
430 zap = 0;
431 #endif
432 }
433 }
434
435 if (zap) {
436 char buf[1024];
437
438 if (lseek(fd, 0, SEEK_SET) != 0)
439 die(_("unable to rewind swap-device"));
440
441 memset(buf, 0, sizeof(buf));
442 if (write_all(fd, buf, sizeof(buf)))
443 die(_("unable to erase bootbits sectors"));
444 return;
445 }
446
447 fprintf(stderr, _("%s: %s: warning: don't erase bootbits sectors\n"),
448 program_name, devname);
449 if (type)
450 fprintf(stderr, _(" (%s partition table detected). "), type);
451 else if (whole)
452 fprintf(stderr, _(" on whole disk. "));
453 else
454 fprintf(stderr, _(" (compiled without libblkid). "));
455 fprintf(stderr, "Use -f to force.\n");
456 }
457
458 int
459 main(int argc, char ** argv) {
460 struct stat statbuf;
461 int i;
462 unsigned long long maxpages;
463 unsigned long long goodpages;
464 unsigned long long sz;
465 off_t offset;
466 int force = 0;
467 int version = 1;
468 char *block_count = 0;
469 char *pp;
470 char *opt_label = NULL;
471 unsigned char *uuid = NULL;
472 #ifdef HAVE_LIBUUID
473 const char *opt_uuid = NULL;
474 uuid_t uuid_dat;
475 #endif
476
477 program_name = (argc && *argv) ? argv[0] : "mkswap";
478 if ((pp = strrchr(program_name, '/')) != NULL)
479 program_name = pp+1;
480
481 setlocale(LC_ALL, "");
482 bindtextdomain(PACKAGE, LOCALEDIR);
483 textdomain(PACKAGE);
484
485 if (argc == 2 &&
486 (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) {
487 printf(_("%s (%s)\n"), program_name, PACKAGE_STRING);
488 exit(0);
489 }
490
491 for (i=1; i<argc; i++) {
492 if (argv[i][0] == '-') {
493 switch (argv[i][1]) {
494 case 'c':
495 check=1;
496 break;
497 case 'f':
498 force=1;
499 break;
500 case 'p':
501 pp = argv[i]+2;
502 if (!*pp && i+1 < argc)
503 pp = argv[++i];
504 if (isnzdigit(*pp))
505 user_pagesize = atoi(pp);
506 else
507 usage();
508 break;
509 case 'L':
510 pp = argv[i]+2;
511 if (!*pp && i+1 < argc)
512 pp = argv[++i];
513 opt_label = pp;
514 break;
515 case 'v':
516 version = atoi(argv[i]+2);
517 break;
518 case 'U':
519 #ifdef HAVE_LIBUUID
520 opt_uuid = argv[i]+2;
521 if (!*opt_uuid && i+1 < argc)
522 opt_uuid = argv[++i];
523 #else
524 fprintf(stderr, _("%1$s: warning: ignore -U (UUIDs are unsupported by %1$s)\n"),
525 program_name);
526 #endif
527 break;
528 default:
529 usage();
530 }
531 } else if (!device_name) {
532 device_name = argv[i];
533 } else if (!block_count) {
534 block_count = argv[i];
535 } else
536 usage();
537 }
538
539 if (version != 1) {
540 fprintf(stderr, _("%s: does not support swapspace version %d.\n"),
541 program_name, version);
542 exit(EXIT_FAILURE);
543 }
544
545 #ifdef HAVE_LIBUUID
546 if(opt_uuid) {
547 if (uuid_parse(opt_uuid, uuid_dat) != 0)
548 die(_("error: UUID parsing failed"));
549 } else
550 uuid_generate(uuid_dat);
551 uuid = uuid_dat;
552 #endif
553
554 init_signature_page(); /* get pagesize */
555 atexit(deinit_signature_page);
556
557 if (!device_name) {
558 fprintf(stderr,
559 _("%s: error: Nowhere to set up swap on?\n"),
560 program_name);
561 usage();
562 }
563 if (block_count) {
564 /* this silly user specified the number of blocks
565 explicitly */
566 char *tmp;
567 int blocks_per_page = pagesize/1024;
568 PAGES = strtoull(block_count,&tmp,0)/blocks_per_page;
569 if (*tmp)
570 usage();
571 }
572 sz = get_size(device_name);
573 if (!PAGES) {
574 PAGES = sz;
575 } else if (PAGES > sz && !force) {
576 fprintf(stderr,
577 _("%s: error: "
578 "size %llu KiB is larger than device size %llu KiB\n"),
579 program_name,
580 PAGES*(pagesize/1024), sz*(pagesize/1024));
581 exit(1);
582 }
583
584 if (PAGES < MIN_GOODPAGES) {
585 fprintf(stderr,
586 _("%s: error: swap area needs to be at least %ld KiB\n"),
587 program_name, (long)(MIN_GOODPAGES * pagesize/1024));
588 usage();
589 }
590
591 #ifdef __linux__
592 if (get_linux_version() >= KERNEL_VERSION(2,3,4))
593 maxpages = UINT_MAX + 1ULL;
594 else if (get_linux_version() >= KERNEL_VERSION(2,2,1))
595 maxpages = V1_MAX_PAGES;
596 else
597 #endif
598 maxpages = V1_OLD_MAX_PAGES;
599
600 if (PAGES > maxpages) {
601 PAGES = maxpages;
602 fprintf(stderr,
603 _("%s: warning: truncating swap area to %llu KiB\n"),
604 program_name, PAGES * pagesize / 1024);
605 }
606
607 if (stat(device_name, &statbuf) < 0) {
608 perror(device_name);
609 exit(EXIT_FAILURE);
610 }
611 if (S_ISBLK(statbuf.st_mode))
612 DEV = open(device_name, O_RDWR | O_EXCL);
613 else
614 DEV = open(device_name, O_RDWR);
615
616 if (DEV < 0) {
617 perror(device_name);
618 exit(1);
619 }
620
621 /* Want a block device. Probably not /dev/hda or /dev/hdb. */
622 if (!S_ISBLK(statbuf.st_mode))
623 check=0;
624 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) {
625 fprintf(stderr,
626 _("%s: error: "
627 "will not try to make swapdevice on '%s'\n"),
628 program_name, device_name);
629 exit(1);
630 } else if (check_mount()) {
631 fprintf(stderr,
632 _("%s: error: "
633 "%s is mounted; will not make swapspace.\n"),
634 program_name, device_name);
635 exit(1);
636 }
637
638 if (check)
639 check_blocks();
640
641 zap_bootbits(DEV, device_name, force);
642
643 p->version = 1;
644 p->last_page = PAGES-1;
645 p->nr_badpages = badpages;
646
647 if (badpages > PAGES - MIN_GOODPAGES)
648 die(_("Unable to set up swap-space: unreadable"));
649
650 goodpages = PAGES - badpages - 1;
651 printf(_("Setting up swapspace version 1, size = %llu KiB\n"),
652 goodpages * pagesize / 1024);
653
654 write_signature("SWAPSPACE2");
655 write_uuid_and_label(uuid, opt_label);
656
657 offset = 1024;
658 if (lseek(DEV, offset, SEEK_SET) != offset)
659 die(_("unable to rewind swap-device"));
660 if (write_all(DEV, (char *) signature_page + offset,
661 pagesize - offset) == -1) {
662 fprintf(stderr, _("%s: %s: unable to write signature page: %s"),
663 program_name, device_name, strerror(errno));
664 exit(1);
665 }
666
667 /*
668 * A subsequent swapon() will fail if the signature
669 * is not actually on disk. (This is a kernel bug.)
670 */
671 #ifdef HAVE_FSYNC
672 if (fsync(DEV))
673 die(_("fsync failed"));
674 #endif
675
676 #ifdef HAVE_LIBSELINUX
677 if (S_ISREG(statbuf.st_mode) && is_selinux_enabled() > 0) {
678 security_context_t context_string;
679 security_context_t oldcontext;
680 context_t newcontext;
681
682 if (fgetfilecon(DEV, &oldcontext) < 0) {
683 if (errno != ENODATA) {
684 fprintf(stderr, _("%s: %s: unable to obtain selinux file label: %s\n"),
685 program_name, device_name,
686 strerror(errno));
687 exit(1);
688 }
689 if (matchpathcon(device_name, statbuf.st_mode, &oldcontext))
690 die(_("unable to matchpathcon()"));
691 }
692 if (!(newcontext = context_new(oldcontext)))
693 die(_("unable to create new selinux context"));
694 if (context_type_set(newcontext, SELINUX_SWAPFILE_TYPE))
695 die(_("couldn't compute selinux context"));
696
697 context_string = context_str(newcontext);
698
699 if (strcmp(context_string, oldcontext)!=0) {
700 if (fsetfilecon(DEV, context_string)) {
701 fprintf(stderr, _("%s: unable to relabel %s to %s: %s\n"),
702 program_name, device_name,
703 context_string,
704 strerror(errno));
705 exit(1);
706 }
707 }
708 context_free(newcontext);
709 freecon(oldcontext);
710 }
711 #endif
712 return 0;
713 }