1  /*
       2   * swaplabel.c - Print or change the label / UUID of a swap partition
       3   *
       4   * Copyright (C) 2010 Jason Borden <jborden@bluehost.com>
       5   * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
       6   *
       7   * Usage: swaplabel [-L label] [-U UUID] device
       8   *
       9   * This file may be redistributed under the terms of the GNU Public License
      10   * version 2 or later.
      11   *
      12   */
      13  #include <stdio.h>
      14  #include <stddef.h>
      15  #include <string.h>
      16  #include <fcntl.h>
      17  #include <sys/types.h>
      18  #include <sys/stat.h>
      19  #include <unistd.h>
      20  #include <stdlib.h>
      21  #include <getopt.h>
      22  
      23  #ifdef HAVE_LIBUUID
      24  # include <uuid.h>
      25  #endif
      26  
      27  #include "c.h"
      28  #include "nls.h"
      29  #include "all-io.h"
      30  #include "strutils.h"
      31  #include "closestream.h"
      32  
      33  #include "swapheader.h"
      34  #include "swapprober.h"
      35  
      36  #define SWAP_UUID_OFFSET	(offsetof(struct swap_header_v1_2, uuid))
      37  #define SWAP_LABEL_OFFSET	(offsetof(struct swap_header_v1_2, volume_name))
      38  
      39  /* Print the swap partition information */
      40  static int print_info(blkid_probe pr)
      41  {
      42  	const char *data;
      43  
      44  	if (!blkid_probe_lookup_value(pr, "LABEL", &data, NULL))
      45  		printf("LABEL: %s\n", data);
      46  
      47  	if (!blkid_probe_lookup_value(pr, "UUID", &data, NULL))
      48  		printf("UUID:  %s\n", data);
      49  
      50  	return 0;
      51  }
      52  
      53  /* Change the swap partition info */
      54  #ifdef HAVE_LIBUUID
      55  static int change_info(const char *devname, const char *label, const char *uuid)
      56  #else
      57  static int change_info(const char *devname, const char *label,
      58  		       const char *uuid __attribute__((__unused__)))
      59  #endif
      60  {
      61  	int fd;
      62  
      63  	fd = open(devname, O_RDWR);
      64  	if (fd < 0) {
      65  		warn(_("cannot open %s"), devname);
      66  		goto err;
      67  	}
      68  #ifdef HAVE_LIBUUID
      69  	/* Write the uuid if it was provided */
      70  	if (uuid) {
      71  		uuid_t newuuid;
      72  
      73  		if (uuid_parse(uuid, newuuid) == -1)
      74  			warnx(_("failed to parse UUID: %s"), uuid);
      75  		else {
      76  			if (lseek(fd, SWAP_UUID_OFFSET, SEEK_SET) !=
      77  							SWAP_UUID_OFFSET) {
      78  				warn(_("%s: failed to seek to swap UUID"), devname);
      79  				goto err;
      80  
      81  			} else if (write_all(fd, newuuid, sizeof(newuuid))) {
      82  				warn(_("%s: failed to write UUID"), devname);
      83  				goto err;
      84  			}
      85  		}
      86  	}
      87  #endif
      88  	/* Write the label if it was provided */
      89  	if (label) {
      90  		char newlabel[SWAP_LABEL_LENGTH];
      91  
      92  		if (lseek(fd, SWAP_LABEL_OFFSET, SEEK_SET) != SWAP_LABEL_OFFSET) {
      93  			warn(_("%s: failed to seek to swap label "), devname);
      94  			goto err;
      95  		}
      96  		memset(newlabel, 0, sizeof(newlabel));
      97  		xstrncpy(newlabel, label, sizeof(newlabel));
      98  
      99  		if (strlen(label) > strlen(newlabel))
     100  			warnx(_("label is too long. Truncating it to '%s'"),
     101  					newlabel);
     102  		if (write_all(fd, newlabel, sizeof(newlabel))) {
     103  			warn(_("%s: failed to write label"), devname);
     104  			goto err;
     105  		}
     106  	}
     107  
     108  	if (close_fd(fd) != 0) {
     109  		warn(_("write failed: %s"), devname);
     110  		return -1;
     111  	}
     112  	return 0;
     113  err:
     114  	if (fd >= 0)
     115  		close(fd);
     116  	return -1;
     117  }
     118  
     119  static void __attribute__((__noreturn__)) usage(void)
     120  {
     121  	FILE *out = stdout;
     122  	fputs(USAGE_HEADER, out);
     123  	fprintf(out, _(" %s [options] <device>\n"),
     124  		program_invocation_short_name);
     125  
     126  	fputs(USAGE_SEPARATOR, out);
     127  	fputs(_("Display or change the label or UUID of a swap area.\n"), out);
     128  
     129  	fputs(USAGE_OPTIONS, out);
     130  	fputs(_(" -L, --label <label> specify a new label\n"
     131  		" -U, --uuid <uuid>   specify a new uuid\n"), out);
     132  	fputs(USAGE_SEPARATOR, out);
     133  	printf(USAGE_HELP_OPTIONS(21));
     134  	printf(USAGE_MAN_TAIL("swaplabel(8)"));
     135  	exit(EXIT_SUCCESS);
     136  }
     137  
     138  int main(int argc, char *argv[])
     139  {
     140  	blkid_probe pr = NULL;
     141  	char *uuid = NULL, *label = NULL, *devname;
     142  	int c, rc = -1;
     143  
     144  	static const struct option longopts[] = {
     145  	    { "help",      no_argument,       NULL, 'h' },
     146  	    { "version",   no_argument,       NULL, 'V' },
     147  	    { "label",     required_argument, NULL, 'L' },
     148  	    { "uuid",      required_argument, NULL, 'U' },
     149  	    { NULL,        0, NULL, 0 }
     150  	};
     151  
     152  	setlocale(LC_ALL, "");
     153  	bindtextdomain(PACKAGE, LOCALEDIR);
     154  	textdomain(PACKAGE);
     155  	close_stdout_atexit();
     156  
     157  	while ((c = getopt_long(argc, argv, "hVL:U:", longopts, NULL)) != -1) {
     158  		switch (c) {
     159  		case 'h':
     160  			usage();
     161  			break;
     162  		case 'V':
     163  			print_version(EXIT_SUCCESS);
     164  		case 'L':
     165  			label = optarg;
     166  			break;
     167  		case 'U':
     168  #ifdef HAVE_LIBUUID
     169  			uuid = optarg;
     170  #else
     171  			warnx(_("ignore -U (UUIDs are unsupported)"));
     172  #endif
     173  			break;
     174  		default:
     175  			errtryhelp(EXIT_FAILURE);
     176  		}
     177  	}
     178  
     179  	if (optind == argc) {
     180  		warnx(_("no device specified"));
     181  		errtryhelp(EXIT_FAILURE);
     182  	}
     183  	devname = argv[optind];
     184  	pr = get_swap_prober(devname);
     185  	if (pr) {
     186  		if (uuid || label)
     187  			rc = change_info(devname, label, uuid);
     188  		else
     189  			rc  = print_info(pr);
     190  		blkid_free_probe(pr);
     191  	}
     192  	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
     193  }
     194