]> err.no Git - util-linux/commitdiff
swapon: Reinitialize software suspend areas to avoid future corruption.
authorKees Cook <kees.cook@canonical.com>
Thu, 20 Mar 2008 08:24:03 +0000 (01:24 -0700)
committerLaMont Jones <lamont@debian.org>
Fri, 21 Mar 2008 16:06:04 +0000 (10:06 -0600)
This is based on the earlier swsuspend re-init patch carried by
RedHat, SuSE, and Ubuntu.  It has been updated to include passing
the known UUID to mkswap, and fixing the fstype name.

Co-Author: Karel Zak <kzak@redhat.com>
Signed-off-by: Kees Cook <kees.cook@canonical.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
mount/swapon.c

index ed91afc0c2ce0b2532d8e9d12b20d3c76affcdfd..e97f83542db913061684d8e372ecd80ff06b0614 100644 (file)
@@ -10,6 +10,9 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
 #include "xmalloc.h"
 #include "swap_constants.h"
 #include "nls.h"
@@ -17,6 +20,8 @@
 #include "realpath.h"
 #include "mount_paths.h"
 
+#define PATH_MKSWAP    "/sbin/mkswap"
+
 #ifdef HAVE_SYS_SWAP_H
 # include <sys/swap.h>
 #endif
@@ -157,6 +162,64 @@ display_summary(void)
        return 0 ;
 }
 
+static int
+swap_is_suspend(const char *device) {
+       const char *type = fsprobe_get_fstype_by_devname(device);
+
+       return (type && strcmp(type, "suspend") == 0) ? 1 : 0;
+}
+
+/* calls mkswap */
+static int
+swap_reinitialize(const char *device) {
+       const char *label = fsprobe_get_label_by_devname(device);
+       const char *uuid  = fsprobe_get_uuid_by_devname(device);
+       pid_t pid;
+       int status, ret;
+       char *cmd[7];
+       int idx=0;
+
+       switch((pid=fork())) {
+       case -1: /* fork error */
+               fprintf(stderr, _("%s: cannot fork: %s\n"),
+                       progname, strerror(errno));
+               return -1;
+
+       case 0: /* child */
+               cmd[idx++] = PATH_MKSWAP;
+               if (label && *label) {
+                       cmd[idx++] = "-L";
+                       cmd[idx++] = (char *) label;
+               }
+               if (uuid && *uuid) {
+                       cmd[idx++] = "-U";
+                       cmd[idx++] = (char *) uuid;
+               }
+               cmd[idx++] = (char *) device;
+               cmd[idx++] = NULL;
+               execv(cmd[0], cmd);
+               perror("execv");
+               exit(1); /* error  */
+
+       default: /* parent */
+               do {
+                       if ((ret = waitpid(pid, &status, 0)) < 0
+                                       && errno == EINTR)
+                               continue;
+                       else if (ret < 0) {
+                               fprintf(stderr, _("%s: waitpid: %s\n"),
+                                       progname, strerror(errno));
+                               return -1;
+                       }
+               } while (0);
+
+               /* mkswap returns: 0=suss, 1=error */
+               if (WIFEXITED(status) && WEXITSTATUS(status)==0)
+                       return 0; /* ok */
+       }
+       return -1; /* error */
+}
+
 static int
 do_swapon(const char *orig_special, int prio, int canonic) {
        int status;
@@ -179,6 +242,18 @@ do_swapon(const char *orig_special, int prio, int canonic) {
                return -1;
        }
 
+       /* We have to reinitialize swap with old (=useless) software suspend
+        * data. The problem is that if we don't do it, then we get data
+        * corruption the next time an attempt at unsuspending is made.
+        */
+       if (swap_is_suspend(special)) {
+               fprintf(stdout, _("%s: %s: software suspend data detected. "
+                                       "Reinitializing the swap.\n"),
+                       progname, special);
+               if (swap_reinitialize(special) < 0)
+                       return -1;
+       }
+
        /* people generally dislike this warning - now it is printed
           only when `verbose' is set */
        if (verbose) {