Author: smh
Date: Thu Jan 21 15:27:44 2016
New Revision: 294506
URL: https://svnweb.freebsd.org/changeset/base/294506

Log:
  Prevent loader.conf load failure due to unknown console entries
  
  When processing loader.conf if console contained an entry for an unsupported
  console then cons_set would return an error refusing to set any console.
  
  This has two side effects:
  
  1. Forth would throw a syntax error and stop processing loader.conf at that
    point.
  2. The value of console is ignored.
  
  #1 Means other important loader.conf entries may not be processed, which is
     clearly undesirable.
  #2 Means the users preference for console aren't applied even if they did
     contain valid options. Now we have support for multi boot paths from a
     single image e.g. bios and efi mode the console preference needs to deal
     with the need to set preference for more than one source.
  
  Fix this by:
  * Returning CMD_OK where possible from cons_set.
  * Allowing set with at least one valid console to proceed.
  
  Reviewed by:  allanjude
  MFC after:    1 week
  Sponsored by: Multiplay
  Differential Revision:        https://reviews.freebsd.org/D5018

Modified:
  head/sys/boot/common/console.c

Modified: head/sys/boot/common/console.c
==============================================================================
--- head/sys/boot/common/console.c      Thu Jan 21 14:57:45 2016        
(r294505)
+++ head/sys/boot/common/console.c      Thu Jan 21 15:27:44 2016        
(r294506)
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$");
 static int     cons_set(struct env_var *ev, int flags, const void *value);
 static int     cons_find(const char *name);
 static int     cons_check(const char *string);
-static void    cons_change(const char *string);
+static int     cons_change(const char *string);
 static int     twiddle_set(struct env_var *ev, int flags, const void *value);
 
 /*
@@ -47,12 +47,12 @@ static int  twiddle_set(struct env_var *e
  * as active.  Also create the console variable.
  */
 void
-cons_probe(void) 
+cons_probe(void)
 {
     int                        cons;
     int                        active;
     char               *prefconsole;
-    
+
     /* We want a callback to install the new value when this var changes. */
     env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set, env_nounset);
 
@@ -162,54 +162,69 @@ cons_find(const char *name)
 static int
 cons_set(struct env_var *ev, int flags, const void *value)
 {
-    int                cons;
+    int                ret;
 
-    if ((value == NULL) || (cons_check(value) == -1)) {
-       if (value != NULL) 
-           printf("no such console!\n");
-       printf("Available consoles:\n");
-       for (cons = 0; consoles[cons] != NULL; cons++)
-           printf("    %s\n", consoles[cons]->c_name);
-       return(CMD_ERROR);
+    if ((value == NULL) || (cons_check(value) == 0)) {
+       /*
+        * Return CMD_OK instead of CMD_ERROR to prevent forth syntax error,
+        * which would prevent it processing any further loader.conf entries.
+        */
+       return (CMD_OK);
     }
 
-    cons_change(value);
+    ret = cons_change(value);
+    if (ret != CMD_OK)
+       return (ret);
 
     env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
-    return(CMD_OK);
+    return (CMD_OK);
 }
 
 /*
- * Check that all of the consoles listed in *string are valid consoles
+ * Check that at least one the consoles listed in *string is valid
  */
 static int
 cons_check(const char *string)
 {
-    int                cons;
+    int                cons, found, failed;
     char       *curpos, *dup, *next;
 
     dup = next = strdup(string);
-    cons = -1;
+    found = failed = 0;
     while (next != NULL) {
        curpos = strsep(&next, " ,");
        if (*curpos != '\0') {
            cons = cons_find(curpos);
-           if (cons == -1)
-               break;
+           if (cons == -1) {
+               printf("console %s is invalid!\n", curpos);
+               failed++;
+           } else {
+               found++;
+           }
        }
     }
 
     free(dup);
-    return (cons);
+
+    if (found == 0)
+       printf("no valid consoles!\n");
+
+    if (found == 0 || failed != 0) {
+       printf("Available consoles:\n");
+       for (cons = 0; consoles[cons] != NULL; cons++)
+           printf("    %s\n", consoles[cons]->c_name);
+    }
+
+    return (found);
 }
 
 /*
- * Activate all of the consoles listed in *string and disable all the others.
+ * Activate all the valid consoles listed in *string and disable all others.
  */
-static void
+static int
 cons_change(const char *string)
 {
-    int                cons;
+    int                cons, active;
     char       *curpos, *dup, *next;
 
     /* Disable all consoles */
@@ -219,6 +234,7 @@ cons_change(const char *string)
 
     /* Enable selected consoles */
     dup = next = strdup(string);
+    active = 0;
     while (next != NULL) {
        curpos = strsep(&next, " ,");
        if (*curpos == '\0')
@@ -227,14 +243,37 @@ cons_change(const char *string)
        if (cons >= 0) {
            consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
            consoles[cons]->c_init(0);
-           if ((consoles[cons]->c_flags & (C_PRESENTIN | C_PRESENTOUT)) !=
-               (C_PRESENTIN | C_PRESENTOUT))
-               printf("console %s failed to initialize\n",
-                   consoles[cons]->c_name);
+           if ((consoles[cons]->c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
+               (C_PRESENTIN | C_PRESENTOUT)) {
+               active++;
+               continue;
+           }
+
+           if (active != 0) {
+               /* If no consoles have initialised we wouldn't see this. */
+               printf("console %s failed to initialize\n", 
consoles[cons]->c_name);
+           }
        }
     }
 
     free(dup);
+
+    if (active == 0) {
+       /* All requested consoles failed to initialise, try to recover. */
+       for (cons = 0; consoles[cons] != NULL; cons++) {
+           consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
+           consoles[cons]->c_init(0);
+           if ((consoles[cons]->c_flags &
+               (C_PRESENTIN | C_PRESENTOUT)) ==
+               (C_PRESENTIN | C_PRESENTOUT))
+               active++;
+       }
+
+       if (active == 0)
+           return (CMD_ERROR); /* Recovery failed. */
+    }
+
+    return (CMD_OK);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to