[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kde-workspace] kdm/backend: Add support for GRUB2 submenus.
From:       Konstantinos Smanis <konstantinos.smanis () gmail ! com>
Date:       2012-08-07 23:10:54
Message-ID: 20120807231054.AE3EEA6094 () git ! kde ! org
[Download RAW message or body]

Git commit c578e8804ee6505ea282fb046972bf88213157e4 by Konstantinos Smanis.
Committed on 08/08/2012 at 01:06.
Pushed by ksmanis into branch 'master'.

Add support for GRUB2 submenus.

Properly parse the 'submenu' directive in GRUB's configuration file
and provide the user with an appropriate menu interface when choosing
which entry to reboot into.

Limitations: Internally we make use of the " >> " separator (hardcoded
in both kdm and ksmserver). An occurence of the separator in a menu
title (be it menuentry or submenu) will baffle our parser. Moreover,
we only support multi-line statements: one-liners, although supported
by GRUB, will fail to be parsed. Lastly, only up to 5 nesting levels
are supported. The above limits are more than enough for all but a
handful of cases.

(forward ported from commit b8e506743429fa28694b3565a231e48e52cfa6ef)

BUG: 297209
FIXED-IN: 4.9.1
REVIEW: 105563

M  +93   -44   kdm/backend/bootman.c
M  +0    -16   kdm/backend/ctrl.c
M  +4    -0    kdm/backend/dm.h
M  +40   -1    kdm/backend/util.c

http://commits.kde.org/kde-workspace/c578e8804ee6505ea282fb046972bf88213157e4

diff --git a/kdm/backend/bootman.c b/kdm/backend/bootman.c
index 8b834d2..5aa35a3 100644
--- a/kdm/backend/bootman.c
+++ b/kdm/backend/bootman.c
@@ -43,6 +43,8 @@ from the copyright holder.
 #include <ctype.h>
 #include <sys/stat.h>
 
+#define SEP " >> "
+
 static int
 getNull(char ***opts ATTR_UNUSED, int *def ATTR_UNUSED, int *cur ATTR_UNUSED)
 {
@@ -123,7 +125,7 @@ setGrub(const char *opt, SdRec *sdr)
                 fclose(f);
                 sdr->osindex = i;
                 sdr->bmstamp = mTime(GRUB_MENU);
-                return BO_OK;
+                return strDup(&sdr->osname, opt) ? BO_OK : BO_IO;
             }
             i++;
         }
@@ -161,16 +163,79 @@ commitGrub(void)
     }
 }
 
+#define GRUB2_MAX_MENU_LEVEL 5
+
 static char *grubReboot;
 static const char *grubConfig;
 
 static int
+parseGrubTitle(char *title)
+{
+    int len;
+    char *ptr = title;
+
+    if (!title)
+        return -1;
+
+    if (*ptr == '\'') {
+        for (len = 0, ptr++; *ptr && *ptr != '\''; ptr++)
+            title[len++] = *ptr;
+    } else if (*ptr == '"') {
+        for (len = 0, ptr++; *ptr && *ptr != '"'; ptr++) {
+            if (*ptr == '\\') {
+                switch (*(++ptr)) {
+                case 0:
+                    return -1; /* Unexpected end */
+                case '$':
+                case '"':
+                case '\\':
+                    break;
+                default:
+                    title[len++] = '\\';
+                    break;
+                }
+            }
+            title[len++] = *ptr;
+        }
+    } else {
+        for (len = 0; *ptr && !isspace(*ptr); ptr++) {
+            if (*ptr == '\\' && !*(++ptr))
+                return -1; /* Unexpected end */
+            title[len++] = *ptr;
+        }
+    }
+
+    return *ptr ? len : -1;
+}
+
+static int
+buildBootList(char ***opts, char *title, int menuLvl, int *menus)
+{
+    int len;
+
+    if ((len = parseGrubTitle(title)) < 0)
+        return -1;
+
+    if (menuLvl > 0) {
+        char **strp;
+        title[len] = '\0';
+        *opts = extStrArr(*opts, &strp);
+        strApp(strp, (*opts)[menus[menuLvl - 1]], SEP, title, (char *)0);
+    } else {
+        *opts = addStrArr(*opts, title, len);
+    }
+
+    return 0;
+}
+
+static int
 getGrub2OrBurg(char ***opts, int *def, int *cur, const char *grubRebootExec)
 {
     FILE *f;
     char *ptr, *linp;
-    int len, ret = BO_NOMAN, i;
+    int len, ret = BO_NOMAN, menuLvl = 0, inEntry = 0;
     char line[1000];
+    int menus[GRUB2_MAX_MENU_LEVEL];
 
     if (!grubReboot && !(grubReboot = locate(grubRebootExec)))
         return BO_NOMAN;
@@ -183,38 +248,33 @@ getGrub2OrBurg(char ***opts, int *def, int *cur, const char \
*grubRebootExec)  return errno == ENOENT ? BO_NOMAN : BO_IO;
     while ((len = fGets(line, sizeof(line), f)) != -1) {
         for (linp = line; isspace(*linp); linp++, len--);
+        for (; isspace(*(linp + len - 1)); len--);
         if ((ptr = match(linp, &len, "set", 3)) && !memcmp(ptr, \
"default=\"${saved_entry}\"", 24)) {  ret = BO_OK;
         } else if ((ptr = match(linp, &len, "menuentry", 9))) {
-            linp = ptr;
-            if (*linp == '\'') {
-                for (i = 0, linp++; *linp && *linp != '\''; linp++)
-                    ptr[i++] = *linp;
-            } else if (*linp == '"') {
-                for (i = 0, linp++; *linp && *linp != '"'; linp++) {
-                    if (*linp == '\\') {
-                        switch (*(++linp)) {
-                        case 0:
-                            return BO_IO; /* Unexpected end */
-                        case '$':
-                        case '"':
-                        case '\\':
-                            break;
-                        default:
-                            ptr[i++] = '\\';
-                            break;
-                        }
-                    }
-                    ptr[i++] = *linp;
+            if (menuLvl <= GRUB2_MAX_MENU_LEVEL) {
+                if (buildBootList(opts, ptr, menuLvl, menus) < 0) {
+                    ret = BO_IO;
+                    break;
                 }
-            } else {
-                for (i = 0; *linp && !isspace(*linp); linp++) {
-                    if (*linp == '\\' && !*(++linp))
-                        return BO_IO; /* Unexpected end */
-                    ptr[i++] = *linp;
+            }
+            inEntry = 1;
+        } else if ((ptr = match(linp, &len, "submenu", 7))) {
+            if (menuLvl < GRUB2_MAX_MENU_LEVEL) {
+                menus[menuLvl] = arrLen(*opts);
+                if (buildBootList(opts, ptr, menuLvl, menus) < 0) {
+                    ret = BO_IO;
+                    break;
                 }
+            } else {
+                logWarn("Only " stringify(GRUB2_MAX_MENU_LEVEL) " nesting levels are \
supported in Grub2 menus.\n");  }
-            *opts = addStrArr(*opts, ptr, i);
+            menuLvl++;
+        } else if (linp[len - 1] == '}') {
+            if (inEntry)
+                inEntry = 0;
+            else if (menuLvl > 0)
+                menuLvl--;
         }
     }
     fclose(f);
@@ -245,10 +305,9 @@ setGrub2(const char *opt, SdRec *sdr)
         return ret;
     for (i = 0; opts[i]; i++) {
         if (!strcmp(opts[i], opt)) {
-            sdr->osindex = i;
             sdr->bmstamp = mTime(grubConfig);
             freeStrArr(opts);
-            return BO_OK;
+            return (sdr->osname = replaceInString(opt, SEP, ">")) ? BO_OK : BO_IO;
         }
     }
     freeStrArr(opts);
@@ -263,9 +322,7 @@ commitGrub2(void)
         return;
 
     if (grubReboot) {
-        char index[16];
-        const char *args[] = { grubReboot, index, 0 };
-        sprintf(index, "%d", sdRec.osindex);
+        const char *args[] = { grubReboot, sdRec.osname, 0 };
         runAndWait((char **)args, environ);
     }
 }
@@ -333,7 +390,7 @@ getLilo(char ***opts, int *def, int *cur)
 }
 
 static int
-setLilo(const char *opt, SdRec *sdr ATTR_UNUSED)
+setLilo(const char *opt, SdRec *sdr)
 {
     char **opts;
     int def, cur, ret, i;
@@ -351,7 +408,7 @@ setLilo(const char *opt, SdRec *sdr ATTR_UNUSED)
     }
   oke:
     freeStrArr(opts);
-    return BO_OK;
+    return strDup(&sdr->osname, opt) ? BO_OK : BO_IO;
 }
 
 static void
@@ -385,17 +442,9 @@ getBootOptions(char ***opts, int *def, int *cur)
 int
 setBootOption(const char *opt, SdRec *sdr)
 {
-    int ret;
-
     free(sdr->osname);
     sdr->osname = 0;
-    if (opt) {
-        if ((ret = bootOpts[bootManager].set(opt, sdr)) != BO_OK)
-            return ret;
-        if (!strDup(&sdr->osname, opt))
-            return BO_IO; /* BO_NOMEM */
-    }
-    return BO_OK;
+    return opt ? bootOpts[bootManager].set(opt, sdr) : BO_OK;
 }
 
 void
diff --git a/kdm/backend/ctrl.c b/kdm/backend/ctrl.c
index 5d219fe..f12ae2b 100644
--- a/kdm/backend/ctrl.c
+++ b/kdm/backend/ctrl.c
@@ -316,22 +316,6 @@ unQuote(const char *str)
 }
 
 static void
-strCatL(char **bp, const char *str, int max)
-{
-    int dnl = strnlen(str, max);
-    memcpy(*bp, str, dnl);
-    *bp += dnl;
-}
-
-static void
-strCat(char **bp, const char *str)
-{
-    int dnl = strlen(str);
-    memcpy(*bp, str, dnl);
-    *bp += dnl;
-}
-
-static void
 sdCat(char **bp, SdRec *sdr)
 {
     int delta = nowMonotonic ? time(0) - now : 0;
diff --git a/kdm/backend/dm.h b/kdm/backend/dm.h
index 13e7b45..64e106b 100644
--- a/kdm/backend/dm.h
+++ b/kdm/backend/dm.h
@@ -566,12 +566,15 @@ void *Calloc(size_t nmemb, size_t size);
 void *Malloc(size_t size);
 void *Realloc(void *ptr, size_t size);
 void wipeStr(char *str);
+void strCat(char **bp, const char *str);
+void strCatL(char **bp, const char *str, int max);
 int strCmp(const char *s1, const char *s2);
 #ifndef HAVE_STRNLEN
 int strnlen(const char *s, int max);
 #endif
 int strNDup(char **dst, const char *src, int len);
 int strDup(char **dst, const char *src);
+char *replaceInString(const char *str, const char *before, const char *after);
 int arrLen(char **arr);
 void freeStrArr(char **arr);
 char **initStrArr(char **arr);
@@ -580,6 +583,7 @@ char **xCopyStrArr(int rn, char **arr);
 int reStrN(char **dst, const char *src, int len);
 int reStr(char **dst, const char *src);
 int strApp(char **dst, ...);
+char **extStrArr(char **arr, char ***strp);
 char **addStrArr(char **arr, const char *str, int len);
 char **parseArgs(char **argv, const char *string);
 /* End note */
diff --git a/kdm/backend/util.c b/kdm/backend/util.c
index 6cd93ef..234d6dd 100644
--- a/kdm/backend/util.c
+++ b/kdm/backend/util.c
@@ -83,6 +83,22 @@ Realloc(void *ptr, size_t size)
     return ret;
 }
 
+void
+strCatL(char **bp, const char *str, int max)
+{
+    int dnl = strnlen(str, max);
+    memcpy(*bp, str, dnl);
+    *bp += dnl;
+}
+
+void
+strCat(char **bp, const char *str)
+{
+    int dnl = strlen(str);
+    memcpy(*bp, str, dnl);
+    *bp += dnl;
+}
+
 int
 strCmp(const char *s1, const char *s2)
 {
@@ -168,6 +184,29 @@ strDup(char **dst, const char *src)
     return strNDup(dst, src, -1);
 }
 
+char *
+replaceInString(const char *str, const char *before, const char *after)
+{
+    int len;
+    size_t beforeLen = strlen(before), afterLen = strlen(after);
+    char *buf, *ret;
+    const char *ptr;
+
+    for (ptr = str, len = 0; (ptr = strstr(ptr, before)); len++)
+        ptr += beforeLen;
+    len = strlen(str) + (afterLen - beforeLen) * len;
+
+    if (!(buf = ret = Malloc(len + 1)))
+        return 0;
+
+    for (ptr = str; (str = strstr(str, before)); str += beforeLen, ptr = str) {
+        strCatL(&buf, ptr, str - ptr);
+        strCatL(&buf, after, afterLen);
+    }
+    strcpy(buf, ptr);
+    return ret;
+}
+
 /* append any number of strings to dst */
 int
 strApp(char **dst, ...)
@@ -296,7 +335,7 @@ arrLen(char **arr)
     return nu;
 }
 
-static char **
+char **
 extStrArr(char **arr, char ***strp)
 {
     char **rarr;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic