[PATCH 4/6] Use readvars_parse_*() in loader/loader.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 loader/loader.c |  391 ++++++++++++++++++++++++++++---------------------------
 1 files changed, 202 insertions(+), 189 deletions(-)

diff --git a/loader/loader.c b/loader/loader.c
index c13b24f..a7f4e69 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -89,6 +89,7 @@
 
 #include "net.h"
 #include "telnetd.h"
+#include "readvars.h"
 
 #include <selinux/selinux.h>
 #include "selinux.h"
@@ -821,7 +822,12 @@ static void parseCmdLineIp(struct loaderData_s * loaderData, char *argv)
         char *start, *end;
 
         /* IP */
-        start = argv + 3;
+        if (!strncmp(argv, "ip=", 3)) {
+            start = argv + 3;
+        } else {
+            start = argv;
+        }
+
         end = strstr(start, ":");
         loaderData->ipv4 = strndup(start, end-start);
         loaderData->ipinfo_set = 1;
@@ -887,12 +893,12 @@ static void parseCmdLineIpv6(struct loaderData_s * loaderData, char *argv)
 }
 #endif
 
-static long argToLong(char *arg, int offset) {
+static long argToLong(char *arg) {
     long retval;
 
     errno = 0;
 
-    retval = strtol(arg+offset, NULL, 10);
+    retval = strtol(arg, NULL, 10);
     if ((errno == ERANGE && (retval == LONG_MIN || retval == LONG_MAX)) ||
         (errno != 0 && retval == 0)) {
         logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
@@ -907,15 +913,10 @@ static long argToLong(char *arg, int offset) {
  */
 static void parseCmdLineFlags(struct loaderData_s * loaderData,
                               char * cmdLine) {
-    int fd;
-    char buf[1024];
-    int len;
-    gint argc = 0;
-    gchar **argv = NULL;
-    GError *optErr = NULL;
     int numExtraArgs = 0;
-    int i;
-    char *front;
+    GHashTable *args = NULL;
+    GHashTableIter iter;
+    gpointer key = NULL, value = NULL;
 
     /* we want to default to graphical and allow override with 'text' */
     flags |= LOADER_FLAGS_GRAPHICAL;
@@ -923,224 +924,236 @@ static void parseCmdLineFlags(struct loaderData_s * loaderData,
     /* if we have any explicit cmdline (probably test mode), we don't want
      * to parse /proc/cmdline */
     if (!cmdLine) {
-        if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) return;
-        len = read(fd, buf, sizeof(buf) - 1);
-        close(fd);
-        if (len <= 0) {
-            logMessage(INFO, "kernel command line was empty");
-            return;
-        }
-        
-        buf[len] = '\0';
-        cmdLine = buf;
+        args = readvars_parse_file("/proc/cmdline");
+    } else {
+        args = readvars_parse_string(cmdLine);
     }
 
-    logMessage(INFO, "kernel command line: %s", cmdLine);
-    
-    if (!g_shell_parse_argv(cmdLine, &argc, &argv, &optErr)) {
-        g_error_free(optErr);
+    if (args == NULL) {
+        logMessage(INFO, "kernel command line was empty");
         return;
     }
 
-    for (i=0; i < argc; i++) {
-        if (!strcasecmp(argv[i], "askmethod"))
+    logMessage(INFO, "kernel command line:");
+    g_hash_table_iter_init(&iter, args);
+
+    while (g_hash_table_iter_next(&iter, &key, &value)) {
+        gchar *k = (gchar *) key;
+        gchar *v = (gchar *) value;
+
+        if (v == NULL) {
+            logMessage(INFO, "    %s", k);
+        } else {
+            logMessage(INFO, "    %s=%s", k, v);
+        }
+
+        /* handle installer boot arguments */
+        if (!strcasecmp(k, "askmethod")) {
             flags |= LOADER_FLAGS_ASKMETHOD;
-        else if (!strcasecmp(argv[i], "asknetwork"))
+        } else if (!strcasecmp(k, "asknetwork")) {
             flags |= LOADER_FLAGS_ASKNETWORK;
-        else if (!strcasecmp(argv[i], "noshell"))
+        } else if (!strcasecmp(k, "noshell")) {
             flags |= LOADER_FLAGS_NOSHELL;
-        else if (!strcasecmp(argv[i], "nokill"))
+        } else if (!strcasecmp(k, "nokill")) {
             flags |= LOADER_FLAGS_NOKILL;
-        else if (!strcasecmp(argv[i], "mediacheck"))
+        } else if (!strcasecmp(k, "mediacheck")) {
             flags |= LOADER_FLAGS_MEDIACHECK;
-        else if (!strcasecmp(argv[i], "allowwireless"))
+        } else if (!strcasecmp(k, "allowwireless")) {
             flags |= LOADER_FLAGS_ALLOW_WIRELESS;
-        else if (!strcasecmp(argv[i], "telnet"))
+        } else if (!strcasecmp(k, "telnet")) {
             flags |= LOADER_FLAGS_TELNETD;
-        else if (!strcasecmp(argv[i], "noprobe"))
+        } else if (!strcasecmp(k, "noprobe")) {
             flags |= LOADER_FLAGS_NOPROBE;
-        else if (!strcasecmp(argv[i], "text")) {
+        } else if (!strcasecmp(k, "text")) {
             logMessage(INFO, "text mode forced from cmdline");
             flags |= LOADER_FLAGS_TEXT;
             flags &= ~LOADER_FLAGS_GRAPHICAL;
-        }
-        else if (!strcasecmp(argv[i], "graphical")) {
+        } else if (!strcasecmp(k, "graphical")) {
             logMessage(INFO, "graphical mode forced from cmdline");
             flags |= LOADER_FLAGS_GRAPHICAL;
-        } else if (!strcasecmp(argv[i], "cmdline")) {
+        } else if (!strcasecmp(k, "cmdline")) {
             logMessage(INFO, "cmdline mode forced from cmdline");
             flags |= LOADER_FLAGS_CMDLINE;
-        } else if (!strncasecmp(argv[i], "updates=", 8))
-            loaderData->updatessrc = strdup(argv[i] + 8);
-        else if (!strncasecmp(argv[i], "updates", 7))
-            flags |= LOADER_FLAGS_UPDATES;
-        else if (!strncasecmp(argv[i], "dogtail=", 8))
-            loaderData->dogtailurl = strdup(argv[i] + 8);
-        else if (!strncasecmp(argv[i], "dd=", 3) || 
-                 !strncasecmp(argv[i], "driverdisk=", 11)) {
-            loaderData->ddsrc = strdup(argv[i] + 
-                                       (argv[i][1] == 'r' ? 11 : 3));
-        }
-        else if (!strcasecmp(argv[i], "dd") || 
-                 !strcasecmp(argv[i], "driverdisk"))
-            flags |= LOADER_FLAGS_MODDISK;
-        else if (!strcasecmp(argv[i], "dlabel=on"))
-            flags |= LOADER_FLAGS_AUTOMODDISK;
-        else if (!strcasecmp(argv[i], "dlabel=off"))
-            flags &= ~LOADER_FLAGS_AUTOMODDISK;
-        else if (!strcasecmp(argv[i], "rescue"))
+        } else if (!strcasecmp(k, "updates")) {
+            if (v != NULL) {
+                loaderData->updatessrc = g_strdup(v);
+            } else {
+                flags |= LOADER_FLAGS_UPDATES;
+            }
+        } else if (!strcasecmp(k, "dd") || !strcasecmp(k, "driverdisk")) {
+            if (v != NULL) {
+                loaderData->ddsrc = g_strdup(v);
+            } else {
+                flags |= LOADER_FLAGS_MODDISK;
+            }
+        } else if (!strcasecmp(k, "rescue")) {
             flags |= LOADER_FLAGS_RESCUE;
-        else if (!strcasecmp(argv[i], "nopass"))
+        } else if (!strcasecmp(k, "nopass")) {
             flags |= LOADER_FLAGS_NOPASS;
-        else if (!strcasecmp(argv[i], "serial")) 
+        } else if (!strcasecmp(k, "serial")) {
             flags |= LOADER_FLAGS_SERIAL;
-        else if (!strcasecmp(argv[i], "noipv4"))
+        } else if (!strcasecmp(k, "noipv4")) {
             flags |= LOADER_FLAGS_NOIPV4;
 #ifdef ENABLE_IPV6
-        else if (!strcasecmp(argv[i], "noipv6"))
+        } else if (!strcasecmp(k, "noipv6")) {
             flags |= LOADER_FLAGS_NOIPV6;
 #endif
-        else if (!strcasecmp(argv[i], "kssendmac"))
+        } else if (!strcasecmp(k, "kssendmac")) {
             flags |= LOADER_FLAGS_KICKSTART_SEND_MAC;
-        else if (!strcasecmp(argv[i], "kssendsn"))
+        } else if (!strcasecmp(k, "kssendsn")) {
             flags |= LOADER_FLAGS_KICKSTART_SEND_SERIAL;
         /* deprecated hardware bits */
-        else if (!strcasecmp(argv[i], "nousbstorage"))
+        } else if (!strcasecmp(k, "nousbstorage")) {
             mlAddBlacklist("usb-storage");
-        else if (!strcasecmp(argv[i], "nousb")) {
+        } else if (!strcasecmp(k, "nousb")) {
             mlAddBlacklist("ehci-hcd");
             mlAddBlacklist("ohci-hcd");
             mlAddBlacklist("uhci-hcd");
-        } else if (!strcasecmp(argv[i], "nofirewire"))
+        } else if (!strcasecmp(k, "nofirewire")) {
             mlAddBlacklist("firewire-ohci");
-        else if (!strncasecmp(argv[i], "loglevel=", 9)) {
-            if (!strcasecmp(argv[i]+9, "debug")) {
-                loaderData->logLevel = strdup(argv[i]+9);
-                setLogLevel(DEBUGLVL);
-            }
-            else if (!strcasecmp(argv[i]+9, "info")) {
-                loaderData->logLevel = strdup(argv[i]+9);
-                setLogLevel(INFO);
-            }
-            else if (!strcasecmp(argv[i]+9, "warning")) {
-                loaderData->logLevel = strdup(argv[i]+9);
-                setLogLevel(WARNING);
-            }
-            else if (!strcasecmp(argv[i]+9, "error")) {
-                loaderData->logLevel = strdup(argv[i]+9);
-                setLogLevel(ERROR);
+        } else if (!strcasecmp(k, "ks")) {
+            GString *tmp = g_string_new("ks");
+
+            if (v != NULL) {
+                g_string_append_printf(tmp, "=%s", v);
             }
-            else if (!strcasecmp(argv[i]+9, "critical")) {
-                loaderData->logLevel = strdup(argv[i]+9);
-                setLogLevel(CRITICAL);
+
+            loaderData->ksFile = g_strdup(tmp->str);
+            g_string_free(tmp, TRUE);
+        } else if (!strcasecmp(k, "selinux")) {
+            if (v != NULL && !strcasecmp(v, "0")) {
+                flags &= ~LOADER_FLAGS_SELINUX;
+            } else {
+                flags |= LOADER_FLAGS_SELINUX;
             }
-        }
-        else if (!strncasecmp(argv[i], "ksdevice=", 9)) {
-            loaderData->netDev = strdup(argv[i] + 9);
-            loaderData->netDev_set = 1;
-        }
-        else if (!strncmp(argv[i], "BOOTIF=", 7)) {
-            /* +10 so that we skip over the leading 01- */
-            loaderData->bootIf = strdup(argv[i] + 10);
-
-            /* scan the BOOTIF value and replace '-' with ':' */
-            front = loaderData->bootIf;
-            if (front) {
-                while (*front != '\0') {
-                    if (*front == '-')
-                        *front = ':';
-                    front++;
+        } else if (v != NULL) {
+            /* boot arguments that are of the form name=value */
+            /* all arguments in this block require the value  */
+
+            if (!strcasecmp(k, "dogtail")) {
+                loaderData->dogtailurl = g_strdup(v);
+            } else if (!strcasecmp(k, "dlabel")) {
+                if (!strcasecmp(v, "on")) {
+                    flags |= LOADER_FLAGS_AUTOMODDISK;
+                } else if (!strcasecmp(v, "off")) {
+                    flags &= ~LOADER_FLAGS_AUTOMODDISK;
+                }
+            } else if (!strcasecmp(k, "loglevel")) {
+                if (!strcasecmp(v, "debug")) {
+                    loaderData->logLevel = g_strdup(v);
+                    setLogLevel(DEBUGLVL);
+                } else if (!strcasecmp(v, "info")) {
+                    loaderData->logLevel = g_strdup(v);
+                    setLogLevel(INFO);
+                } else if (!strcasecmp(v, "warning")) {
+                    loaderData->logLevel = g_strdup(v);
+                    setLogLevel(WARNING);
+                } else if (!strcasecmp(v, "error")) {
+                    loaderData->logLevel = g_strdup(v);
+                    setLogLevel(ERROR);
+                } else if (!strcasecmp(v, "critical")) {
+                    loaderData->logLevel = g_strdup(v);
+                    setLogLevel(CRITICAL);
+                }
+            } else if (!strcasecmp(k, "ksdevice")) {
+                loaderData->netDev = g_strdup(v);
+                loaderData->netDev_set = 1;
+            } else if (!strcmp(k, "BOOTIF")) {
+                /* trim leading '01-' if it exists */
+                if (!strncmp(v, "01-", 3)) {
+                    loaderData->bootIf = g_strdup(v + 3);
+                } else {
+                    loaderData->bootIf = g_strdup(v);
                 }
-            }
 
-            loaderData->bootIf_set = 1;
-        } else if (!strncasecmp(argv[i], "dhcpclass=", 10)) {
-            loaderData->netCls = strdup(argv[i] + 10);
-            loaderData->netCls_set = 1;
-        }
-        else if (!strcasecmp(argv[i], "ks") || !strncasecmp(argv[i], "ks=", 3))
-            loaderData->ksFile = strdup(argv[i]);
-        else if (!strncasecmp(argv[i], "display=", 8))
-            setenv("DISPLAY", argv[i] + 8, 1);
-        else if ((!strncasecmp(argv[i], "lang=", 5)) && 
-                 (strlen(argv[i]) > 5))  {
-            loaderData->lang = strdup(argv[i] + 5);
-            loaderData->lang_set = 1;
-        }
-        else if (!strncasecmp(argv[i], "keymap=", 7) &&
-                   (strlen(argv[i]) > 7)) {
-            loaderData->kbd = strdup(argv[i] + 7);
-            loaderData->kbd_set = 1;
-        }
-        else if (!strncasecmp(argv[i], "method=", 7)) {
-            logMessage(WARNING, "method= is deprecated.  Please use repo= instead.");
-            loaderData->instRepo = strdup(argv[i] + 7);
-        }
-        else if (!strncasecmp(argv[i], "repo=", 5))
-            loaderData->instRepo = strdup(argv[i] + 5);
-        else if (!strncasecmp(argv[i], "stage2=", 7))
-            setStage2LocFromCmdline(argv[i] + 7, loaderData);
-        else if (!strncasecmp(argv[i], "hostname=", 9))
-            loaderData->hostname = strdup(argv[i] + 9);
-        else if (!strncasecmp(argv[i], "ip=", 3))
-            parseCmdLineIp(loaderData, argv[i]);
+                loaderData->bootIf_set = 1;
+
+                /* scan the BOOTIF value and replace '-' with ':' */
+                char *front = loaderData->bootIf;
+                if (front) {
+                    while (*front != '\0') {
+                        if (*front == '-') {
+                            *front = ':';
+                        }
+
+                        front++;
+                    }
+                }
+            } else if (!strcasecmp(k, "dhcpclass")) {
+                loaderData->netCls = g_strdup(v);
+                loaderData->netCls_set = 1;
+            } else if (!strcasecmp(k, "display")) {
+                setenv("DISPLAY", v, 1);
+            } else if (!strcasecmp(k, "lang")) {
+                loaderData->lang = g_strdup(v);
+                loaderData->lang_set = 1;
+            } else if (!strcasecmp(k, "keymap")) {
+                loaderData->kbd = g_strdup(v);
+                loaderData->kbd_set = 1;
+             } else if (!strcasecmp(k, "method")) {
+                logMessage(WARNING, "method= is deprecated.  Please use repo= instead.");
+                loaderData->instRepo = g_strdup(v);
+            } else if (!strcasecmp(k, "repo")) {
+                loaderData->instRepo = g_strdup(v);
+            } else if (!strcasecmp(k, "stage2")) {
+                setStage2LocFromCmdline(v, loaderData);
+            } else if (!strcasecmp(k, "hostname")) {
+                loaderData->hostname = g_strdup(v);
+            } else if (!strcasecmp(k, "ip")) {
+                parseCmdLineIp(loaderData, v);
 #ifdef ENABLE_IPV6
-        else if (!strncasecmp(argv[i], "ipv6=", 5))
-            parseCmdLineIpv6(loaderData, argv[i]);
+            } else if (!strcasecmp(k, "ipv6")) {
+                parseCmdLineIpv6(loaderData, v);
 #endif
-        else if (!strncasecmp(argv[i], "netmask=", 8))
-            loaderData->netmask = strdup(argv[i] + 8);
-        else if (!strncasecmp(argv[i], "gateway=", 8))
-            loaderData->gateway = strdup(argv[i] + 8);
-        else if (!strncasecmp(argv[i], "dns=", 4))
-            loaderData->dns = strdup(argv[i] + 4);
-        else if (!strncasecmp(argv[i], "ethtool=", 8))
-            loaderData->ethtool = strdup(argv[i] + 8);
-        else if (!strncasecmp(argv[i], "essid=", 6))
-            loaderData->essid = strdup(argv[i] + 6);
-        else if (!strncasecmp(argv[i], "mtu=", 4))
-            loaderData->mtu = argToLong(argv[i], 4);
-        else if (!strncasecmp(argv[i], "wepkey=", 7))
-            loaderData->wepkey = strdup(argv[i] + 7);
-        else if (!strncasecmp(argv[i], "linksleep=", 10))
-            num_link_checks = argToLong(argv[i], 10);
-        else if (!strncasecmp(argv[i], "nicdelay=", 9))
-            post_link_sleep = argToLong(argv[i], 9);
-        else if (!strncasecmp(argv[i], "dhcptimeout=", 12))
-            loaderData->dhcpTimeout = argToLong(argv[i], 12);
-        else if (!strncasecmp(argv[i], "selinux=0", 9))
-            flags &= ~LOADER_FLAGS_SELINUX;
-        else if (!strncasecmp(argv[i], "selinux", 7))
-            flags |= LOADER_FLAGS_SELINUX;
-        else if (!strncasecmp(argv[i], "gdb=", 4))
-            loaderData->gdbServer = strdup(argv[i] + 4);
-        else if (!strncasecmp(argv[i], "proxy=", 6))
-            splitProxyParam(argv[i]+6, &loaderData->proxyUser,
-                            &loaderData->proxyPassword, &loaderData->proxy);
-        else if (numExtraArgs < (MAX_EXTRA_ARGS - 1)) {
-            /* go through and append args we just want to pass on to */
-            /* the anaconda script, but don't want to represent as a */
+            } else if (!strcasecmp(k, "netmask")) {
+                loaderData->netmask = g_strdup(v);
+            } else if (!strcasecmp(k, "gateway")) {
+                loaderData->gateway = g_strdup(v);
+            } else if (!strcasecmp(k, "dns")) {
+                loaderData->dns = g_strdup(v);
+            } else if (!strcasecmp(k, "ethtool")) {
+                loaderData->ethtool = g_strdup(v);
+            } else if (!strcasecmp(k, "essid")) {
+                loaderData->essid = g_strdup(v);
+            } else if (!strcasecmp(k, "mtu")) {
+                loaderData->mtu = argToLong(v);
+            } else if (!strcasecmp(k, "wepkey")) {
+                loaderData->wepkey = g_strdup(v);
+            } else if (!strcasecmp(k, "linksleep")) {
+                num_link_checks = argToLong(v);
+            } else if (!strcasecmp(k, "nicdelay")) {
+                post_link_sleep = argToLong(v);
+            } else if (!strcasecmp(k, "dhcptimeout")) {
+                loaderData->dhcpTimeout = argToLong(v);
+            } else if (!strcasecmp(k, "gdb")) {
+                loaderData->gdbServer = g_strdup(v);
+            } else if (!strcasecmp(k, "proxy")) {
+                splitProxyParam(v, &loaderData->proxyUser,
+                                &loaderData->proxyPassword, &loaderData->proxy);
+            }
+        } else if (numExtraArgs < (MAX_EXTRA_ARGS - 1)) {
+            /* go through and append args we just want to pass on to  */
+            /* the anaconda script, but don't want to represent as a  */
             /* LOADER_FLAGS_XXX since loader doesn't care about these */
-            /* particular options.                                   */
+            /* particular options.                                    */
             /* do vncpassword case first */
-            if (!strncasecmp(argv[i], "vncpassword=", 12)) {
-                writeVNCPasswordFile("/tmp/vncpassword.dat", argv[i]+12);
-            }
-            else if (!strncasecmp(argv[i], "resolution=", 11) ||
-                     !strncasecmp(argv[i], "nomount", 7) ||
-                     !strncasecmp(argv[i], "vnc", 3) ||
-                     !strncasecmp(argv[i], "vncconnect=", 11) ||
-                     !strncasecmp(argv[i], "headless", 8) ||
-                     !strncasecmp(argv[i], "usefbx", 6) ||
-                     !strncasecmp(argv[i], "mpath", 6) ||
-                     !strncasecmp(argv[i], "nompath", 8) ||
-                     !strncasecmp(argv[i], "dmraid", 6) ||
-                     !strncasecmp(argv[i], "nodmraid", 8) ||
-                     !strncasecmp(argv[i], "xdriver=", 8) ||
-                     !strncasecmp(argv[i], "syslog=", 7)) { 
+            if (!strcasecmp(k, "vncpassword") && v != NULL) {
+                writeVNCPasswordFile("/tmp/vncpassword.dat", v);
+            } else if (!strcasecmp(k, "resolution") ||
+                       !strcasecmp(k, "nomount") ||
+                       !strcasecmp(k, "vnc") ||
+                       !strcasecmp(k, "vncconnect") ||
+                       !strcasecmp(k, "headless") ||
+                       !strcasecmp(k, "usefbx") ||
+                       !strcasecmp(k, "mpath") ||
+                       !strcasecmp(k, "nompath") ||
+                       !strcasecmp(k, "dmraid") ||
+                       !strcasecmp(k, "nodmraid") ||
+                       !strcasecmp(k, "xdriver") ||
+                       !strcasecmp(k, "syslog")) {
 
                 /* vnc implies graphical */
-                if (!strncasecmp(argv[i], "vnc", 3)) {
+                if (!strcasecmp(k, "vnc")) {
                     logMessage(INFO, "vnc forced graphical mode from cmdline");
                     flags |= LOADER_FLAGS_GRAPHICAL;
                 }
@@ -1149,18 +1162,17 @@ static void parseCmdLineFlags(struct loaderData_s * loaderData,
                  * by loader, so an active connection is ready once we get
                  * to anaconda
                  */
-                if (!strncasecmp(argv[i], "syslog", 6) ||
-                    !strncasecmp(argv[i], "vnc", 3)) {
-                    logMessage(INFO, "early networking required for %s",
-                               argv[i]);
+                if (!strcasecmp(k, "syslog") || !strcasecmp(k, "vnc")) {
+                    logMessage(INFO, "early networking required for %s", k);
                     flags |= LOADER_FLAGS_EARLY_NETWORKING;
                 }
+
                 if (isKickstartFileRemote(loaderData->ksFile)) {
                     logMessage(INFO, "early networking required for remote kickstart configuration");
                     flags |= LOADER_FLAGS_EARLY_NETWORKING;
                 }
 
-                checked_asprintf(&extraArgs[numExtraArgs],"--%s", argv[i]);
+                checked_asprintf(&extraArgs[numExtraArgs],"--%s", k);
                 numExtraArgs += 1;
 
                 if (numExtraArgs > (MAX_EXTRA_ARGS - 2)) {
@@ -1172,6 +1184,7 @@ static void parseCmdLineFlags(struct loaderData_s * loaderData,
         }
     }
 
+    g_hash_table_destroy(args);
     readNetInfo(&loaderData);
 
     /* NULL terminates the array of extra args */
-- 
1.7.1.1

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list


[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux