grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* Proposition for Add-on
@ 2013-12-02  0:11 Michel Benoit
  2013-12-02  0:28 ` SevenBits
  2013-12-02  3:59 ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 2 replies; 3+ messages in thread
From: Michel Benoit @ 2013-12-02  0:11 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 2993 bytes --]

Hi!

I’ve d develop an internal command for grub to help the administrators of 
pool of dual boot machine.

The problem: We have class with near 100 computers in dual boot, under 
windows we have a maintenance period in the night to automatically install 
update. For that, in grub we put Windows has the default menu-entry.

The only time the computers are in linux, is when a student is using it. 
It's not a good time to install update. To install update, security patch, 
or other package, i was forced to pass computer by computer.


To get a period for the maintenance in linux, i wrote a simple module for 
grub that select the default menu-entry depending of the time of the day.

ex. :

    I set the period from 4am to 6am with the default boot to linux.
    So i can put a script in the crontab at 4h05 to install the update.
    (you have to put a shutdown -r command in Windows task scheduler at 4.00 
am. And use a wake on lan for computer that are down)

Is it possible to integrate in in the distribution of grub, if you think it 
could help other user.

-------------------------------------------------------------------------------------------------------------------------------------------------------------

The principal module grub-core/commands/select_by_time.c

The configuration file, two option

        the simple version /etc/grub.d/98_select_by_time

                    In 98_select_by_time, you select the period of time and 
the menuentry for that period, you can use many period of time. It use the 
24 hours time format notation without colon.

        ex:

            # from 4 am to 6 am select item 3 as default
            select_by_time 0400 0600 3
            # and from 11h25 pm to midnight select item 5 as default
            select_by_time 2325 2400 5

       or

        the more complete /etc/grub.d/99_select_by_time, that use the config 
file /boot/grub/select_by_time.cfg
        With this version you don't have to know the position of the 
operating system in grub.cfg (menuitem).

        exemple of select_by_time.cfg

            select_default Windows
            select_by_time 5:00 6:00 ubuntu           # maintenance period
            select_by_time 13:00 15:00 ubuntu       # linux course
            select_by_time 19:00 2308 "Linux 3.2.0-23-generic"    # specific

–--------------------------------------------------------------------------------------

Right now, we are using select_by_time with 98_select_by_time, and we save a 
lot of days of work.
If you think it could be helpful for other administrator, could you put it 
in a future grub distribution (the source code is very simple).
The 99_select_by_time is optional, it's just more easy to use.

Thank's

------------------------------------------------------
Michel Benoit (morph1853)
Technicien Systèmes Ordinés
Dep. Informatique
Université de Sherbooke
michel.benoit@usherbrooke.ca

[-- Attachment #2: 98_select_by_time --]
[-- Type: application/octet-stream, Size: 375 bytes --]

#!/bin/sh
exec awk '$1 ~ /select_by_time/ {print $1,$2,$3,$4;}' $0

# select_by_time start_time stop_time menu choice
#
# exemple between 4h00am to 6h00am select the third menu in grub (menuitem start at 0) 
# select_by_time 400 600 2
# Module to select default entry by time

select_by_time 0400 0600 2    # linux maintenance period 
select_by_time 2000 2200 4


[-- Attachment #3: 99_select_by_time --]
[-- Type: application/octet-stream, Size: 6557 bytes --]

#!/bin/sh
# Module to select default entry by time


# Validation and Transformation of the time format
decript () { 
	# remove : h  AM  PM
        value=` echo $1 | tr -d '[:a-zA-Z]'`
           pm=` echo $1 | tr '[:upper:]' '[:lower:]' | tr -d '[:h0-9]' `	
	
	# data format validation  
	to_validate=` echo $1 | tr  '[:upper:]' '[:lower:]' `
 	case "$to_validate" in				# valide format
			           [0-9][0-5][0-9]) ;; 	#   700
		 	      [0,1][0-9][0-5][0-9]) ;;	#  1700
		 	        [2][0-4][0-5][0-9]) ;;	#  1700
			       [0-9][h:][0-5][0-9]) ;;	#  7:00  7h00
			  [0,1][0-9][h:][0-5][0-9]) ;; 	# 19:00 19h00
			    [2][0-4][h:][0-5][0-9]) ;; 	# 21:00 22h00
		
			    [0-9][0-5][0-9][a,p]m) ;; 	#   700am
		       [0,1][0-9][0-5][0-9][a,p]m) ;;	#  1700pm
		         [2][0-4][0-5][0-9][a,p]m) ;;	#  2300pm
		        [0-9][h:][0-5][0-9][a,p]m) ;;	#  7:00pm  7h00am
	 	   [0,1][0-9][h:][0-5][0-9][a,p]m) ;; 	# 19:00pm 19h00pm
	 	     [2][0-4][h:][0-5][0-9][a,p]m) ;; 	# 21:00pm 22h00pm

		*)  # echo "Invalide format" >&2
			return 1 
			;;
	esac
	if [ "$pm" = "pm" ]
	then
		if [ "$value" -lt "1200" ] ; then  value=`expr $value + 1200 ` ; fi  
	fi 
	if [ "$value" -gt "2400" ] ; then  return 1 ; fi  #echo not in range, only 24h by day
	echo $value  	# echo OK
        return 0
}

# find choice of menuentry in grub.cfg
# by item number
# or by description (ex.: Ubuntu, Debian, Windows, ... )
find_menu_item ()  {
      if [ ! -z "$1" ] ; then
                validate=` echo $1 | sed  's/[^0-9]*//g' `
                if [ "$1" = "$validate" ]  ; then
                        # the choice is a number
                        if [ $1 -gt $last_menu ]  ; then return 1 ; fi
                        choice=$1
                else
                        # the choice in alphanumeric, patch choice beginning by -
                        search=`echo $1 |  sed "s/^-/\\\\\-/"  `
                        choice=`egrep  "^menuentry" $GRUB_PREFIX/$MENU_FILE_CONVERT | nl -v0 -w1 -s\: | egrep -m1 -i "$search" | cut -d\:  -f1 `
                        # text selected not in menuentrys
                        if [ "$choice" = "" ]  ; then return 1 ; fi
                fi
                echo $choice    # first entry corresponding
		return 0
      fi
}

select_by_time ()  { 

	if [ $# != 3 ] ; then 
	  echo "select_by_time  $* : syntaxe error " >&2  
	  echo "    Select_by_time  start_time end_time menu_choice " >&2  
	  return
	fi
	start_time=`decript "$1" `
	if [ $? = 1 ] ; then echo "Select_by_time $* \t: Invalid format $1 " >&2 ; return ; fi 
	stop_time=`decript "$2" `
	if [ $? = 1 ] ; then echo "Select_by_time $* \t: Invalid format $2 " >&2 ; return ; fi 
	menu_item=`find_menu_item "$3" `
	if [ $? = 1 ] ; then echo "Select_by_time $* \t: $3 not available " >&2 ; return ; fi 

	if [ $start_time -ge $stop_time ] ; then echo "Select_by_time $* \t: Stop time is before start time " >&2 ; return ; fi
 
	echo  select_by_time $start_time $stop_time $menu_item
}


select_default ()  { 

	if [ $# != 1 ] ; then 
	  echo "select_default  $* : syntaxe error " >&2  
	  echo "    select_default  menu_choice " >&2  
	  return
	fi
	menu_item=`find_menu_item "$1" `
	if [ $? = 1 ] ; then return ; fi 
	echo  default=$menu_item
}

# extract menuentry from grub.cfg.new, taking care of "previous version" item
convert_grub_cfg ()  {
	if [ -f  $GRUB_PREFIX/$MENU_FILE_CONVERT ] ; then rm -f  $GRUB_PREFIX/$MENU_FILE_CONVERT ; fi 
        menu_count=0
        bracket_count=0
        sed "s/[{}]/\n&\n/" "$GRUB_PREFIX/$MENU_FILE" | egrep "}|{|menuentry|submenu"  | while read line 
        do
                bcount_open=`echo $line |  grep -o '{' | wc -w`
                bcount_close=`echo $line |  grep -o '}' | wc -w`
                bracket_count=` expr $bracket_count + $bcount_open - $bcount_close `
                tmp=`echo $line | egrep -ic "^menuentry"`
                if [ $? = 0 ] ; then
                        if [ $bracket_count = 0 ] ; then
                                sub_count=0
                                echo "$line" >> $GRUB_PREFIX/$MENU_FILE_CONVERT
                        else
                          if [ $bracket_count = 1 ] ; then  # inside a submenu
                                if  [ $sub_count = 0 ] ; then
                                        sub_count=1
                                        echo "$line"  >> $GRUB_PREFIX/$MENU_FILE_CONVERT
                                fi
                          fi
                        fi
                fi
        done
}


# main()

MENU_FILE="grub.cfg.new"
MENU_FILE_CONVERT="select_by_time_menu_grub"
USER_CHOICE="select_by_time.cfg"
if [ ! -e "$GRUB_PREFIX/$MENU_FILE" ] ; then  DEBUG=1 ; fi
if [ $DEBUG ] ; then 
	# set -x	
	GRUB_PREFIX=/boot/grub
	MENU_FILE=grub.cfg
fi
convert_grub_cfg     # extract menuentry from grub.cfg.new, taking care of "previous version" item

last_menu=`egrep  "^menuentry" $GRUB_PREFIX/$MENU_FILE_CONVERT | nl -v0 -w1 -s\: |tail -1 |cut -d\: -f1`
if [ "$last_menu" = "" ] ; then return; fi # file not containing menuentry

if [ -f "$GRUB_PREFIX/$USER_CHOICE" ] ; then
   # traitement
   # read user file

        egrep -i  "select_by_time|select_default" "$GRUB_PREFIX/$USER_CHOICE" | awk -F"#" '{print $1}' | tr '[:upper:]' '[:lower:]'  | while read line
        do
		command=`echo $line | awk -F" " '{print $1}'`
		argument=`echo $line | awk -F" " '{$1=""; print }'`
		eval set -- "$argument"
		if [ "$command" = "select_by_time" ] ; then select_by_time "$@" ; fi
		if [ "$command" = "select_default" ] ; then select_default "$@" ; fi 
	done
fi 

###################################################
# Clean temporary file
###################################################
if [ -f  $GRUB_PREFIX/$MENU_FILE_CONVERT ] ; then rm -f  $GRUB_PREFIX/$MENU_FILE_CONVERT ; fi 


###########################################################################################################
# time selection in /boot/grub/select_by_time.cfg
###########################################################################################################
# select_default must be before select_by_time
# exemple
# select_default Windows
# select_by_time 5:00 6:00 ubuntu	     # maintenance period
# select_by_time 13:00 15:00 ubuntu	     # linux course
# select_by_time 19:00 2308 "Linux 3.2.0-23-generic"   # specific 
# select_by_time  19:00 2302 "recovery mode" 





[-- Attachment #4: select_by_time.c --]
[-- Type: application/octet-stream, Size: 1972 bytes --]

/* select_by_time.c - command to choice menu item depanding of the time of the day.  */
/*
 * idea of: Michel.benoit@USherbrooke.ca (morph1853)
 */

#include <grub/dl.h>
#include <grub/err.h>
#include <grub/datetime.h>
#include <grub/command.h>
#include <grub/env.h>

GRUB_MOD_LICENSE ("GPLv3+");

static grub_err_t
grub_cmd_select_by_time (grub_command_t cmd __attribute__ ((unused)),
               int argc, char **args)
{
  struct grub_datetime datetime;

  if (argc != 3)
    {
	grub_printf (" Select default boot by time of the day \n");
	grub_printf (" usage: select_by_time hhmm HHMM number_of_menuitem \n");
	grub_printf (" between the time hhmm and HHMM use number_of_menuitem as default choice \n");
	
      return 0;
    }

  char *s;
  int  start_time, stop_time,  current_time ;
  if (grub_get_datetime (&datetime))
        return grub_errno;
  current_time= (datetime.hour * 100) + datetime.minute;
 
  /* convert argument, and validate that they contain only number, arg0 -> start_time, arg1 -> stop_time, arg2 -> menu choice */  
  start_time = grub_strtoul (args[0], &s, 10);
  if ( grub_errno != 0 || *s)
	return grub_error (GRUB_ERR_BAD_ARGUMENT, "start time invalid format"); 

  stop_time = grub_strtoul (args[1], &s, 10);
  if ( grub_errno != 0 || *s)
	return grub_error (GRUB_ERR_BAD_ARGUMENT, "stop time invalid format"); 

  grub_strtoul (args[2], &s, 10);
  if ( grub_errno != 0 || *s)
	return grub_error (GRUB_ERR_BAD_ARGUMENT, "menu choice not valid"); 
	
  if ((current_time >= start_time) && (current_time <= stop_time))
	grub_env_set ("default",args[2]);
  return 0;
}

static grub_command_t cmd;

GRUB_MOD_INIT(select_by_time)
{
  cmd =
    grub_register_command ("select_by_time", grub_cmd_select_by_time,
			   N_("hourminute  hourminute menuitem"),
			   N_("Set the default menu item by time."));
}

GRUB_MOD_FINI(select_by_time)
{
  grub_unregister_command (cmd);
}


[-- Attachment #5: select_by_time.cfg --]
[-- Type: application/octet-stream, Size: 590 bytes --]

###########################################################################################################
# select_by_time.cfg: time selection 
###########################################################################################################
# select_default must be before select_by_time
#
# exemple
# select_default Windows
# select_by_time 5:00 6:00 ubuntu            # maintenance period
# select_by_time 13:00 15:00 ubuntu          # linux course
# select_by_time 19:00 2308 "Linux 3.2.0-23-generic"   # specific 
# select_by_time  19:00 2302 "recovery mode" 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-12-02  3:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-02  0:11 Proposition for Add-on Michel Benoit
2013-12-02  0:28 ` SevenBits
2013-12-02  3:59 ` Vladimir 'φ-coder/phcoder' Serbinenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).