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