1/* main.c - experimental GRUB stage2 that runs under Unix */
2/*
3 *  GRUB  --  GRand Unified Bootloader
4 *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc.
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software
18 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/* Simulator entry point. */
22int grub_stage2 (void);
23
24#include <stdio.h>
25#include <getopt.h>
26#include <unistd.h>
27#include <string.h>
28#include <stdlib.h>
29#include <limits.h>
30#include <setjmp.h>
31
32#define WITHOUT_LIBC_STUBS 1
33#include <shared.h>
34#include <term.h>
35
36char *program_name = 0;
37int use_config_file = 1;
38int use_preset_menu = 0;
39#ifdef HAVE_LIBCURSES
40int use_curses = 1;
41#else
42int use_curses = 0;
43#endif
44int verbose = 0;
45int read_only = 0;
46int floppy_disks = 1;
47char *device_map_file = 0;
48static int default_boot_drive;
49static int default_install_partition;
50static char *default_config_file;
51
52#define OPT_HELP		-2
53#define OPT_VERSION		-3
54#define OPT_HOLD		-4
55#define OPT_CONFIG_FILE		-5
56#define OPT_INSTALL_PARTITION	-6
57#define OPT_BOOT_DRIVE		-7
58#define OPT_NO_CONFIG_FILE	-8
59#define OPT_NO_CURSES		-9
60#define OPT_BATCH		-10
61#define OPT_VERBOSE		-11
62#define OPT_READ_ONLY		-12
63#define OPT_PROBE_SECOND_FLOPPY	-13
64#define OPT_NO_FLOPPY		-14
65#define OPT_DEVICE_MAP		-15
66#define OPT_PRESET_MENU		-16
67#define OPT_NO_PAGER		-17
68#define OPTSTRING ""
69
70static struct option longopts[] =
71{
72  {"batch", no_argument, 0, OPT_BATCH},
73  {"boot-drive", required_argument, 0, OPT_BOOT_DRIVE},
74  {"config-file", required_argument, 0, OPT_CONFIG_FILE},
75  {"device-map", required_argument, 0, OPT_DEVICE_MAP},
76  {"help", no_argument, 0, OPT_HELP},
77  {"hold", optional_argument, 0, OPT_HOLD},
78  {"install-partition", required_argument, 0, OPT_INSTALL_PARTITION},
79  {"no-config-file", no_argument, 0, OPT_NO_CONFIG_FILE},
80  {"no-curses", no_argument, 0, OPT_NO_CURSES},
81  {"no-floppy", no_argument, 0, OPT_NO_FLOPPY},
82  {"no-pager", no_argument, 0, OPT_NO_PAGER},
83  {"preset-menu", no_argument, 0, OPT_PRESET_MENU},
84  {"probe-second-floppy", no_argument, 0, OPT_PROBE_SECOND_FLOPPY},
85  {"read-only", no_argument, 0, OPT_READ_ONLY},
86  {"verbose", no_argument, 0, OPT_VERBOSE},
87  {"version", no_argument, 0, OPT_VERSION},
88  {0},
89};
90
91
92static void
93usage (int status)
94{
95  if (status)
96    fprintf (stderr, "Try ``grub --help'' for more information.\n");
97  else
98    printf ("\
99Usage: grub [OPTION]...\n\
100\n\
101Enter the GRand Unified Bootloader command shell.\n\
102\n\
103    --batch                  turn on batch mode for non-interactive use\n\
104    --boot-drive=DRIVE       specify stage2 boot_drive [default=0x%x]\n\
105    --config-file=FILE       specify stage2 config_file [default=%s]\n\
106    --device-map=FILE        use the device map file FILE\n\
107    --help                   display this message and exit\n\
108    --hold                   wait until a debugger will attach\n\
109    --install-partition=PAR  specify stage2 install_partition [default=0x%x]\n\
110    --no-config-file         do not use the config file\n\
111    --no-curses              do not use curses\n\
112    --no-floppy              do not probe any floppy drive\n\
113    --no-pager               do not use internal pager\n\
114    --preset-menu            use the preset menu\n\
115    --probe-second-floppy    probe the second floppy drive\n\
116    --read-only              do not write anything to devices\n\
117    --verbose                print verbose messages\n\
118    --version                print version information and exit\n\
119\n\
120Report bugs to <bug-grub@gnu.org>.\n\
121",
122	    default_boot_drive, default_config_file,
123	    default_install_partition);
124
125  exit (status);
126}
127
128
129int
130main (int argc, char **argv)
131{
132  int c;
133  int hold = 0;
134
135  /* First of all, call sync so that all in-core data is scheduled to be
136     actually written to disks. This is very important because GRUB does
137     not use ordinary stdio interface but raw devices.  */
138  sync ();
139
140  program_name = argv[0];
141  default_boot_drive = boot_drive;
142  default_install_partition = install_partition;
143  if (config_file)
144    default_config_file = config_file;
145  else
146    default_config_file = "NONE";
147
148  /* Parse command-line options. */
149  do
150    {
151      c = getopt_long (argc, argv, OPTSTRING, longopts, 0);
152      switch (c)
153	{
154	case EOF:
155	  /* Fall through the bottom of the loop. */
156	  break;
157
158	case OPT_HELP:
159	  usage (0);
160	  break;
161
162	case OPT_VERSION:
163	  printf ("grub (GNU GRUB " VERSION ")\n");
164	  exit (0);
165	  break;
166
167	case OPT_HOLD:
168	  if (! optarg)
169	    hold = -1;
170	  else
171	    hold = atoi (optarg);
172	  break;
173
174	case OPT_CONFIG_FILE:
175	  strncpy (config_file, optarg, 127); /* FIXME: arbitrary */
176	  config_file[127] = '\0';
177	  break;
178
179	case OPT_INSTALL_PARTITION:
180	  install_partition = strtoul (optarg, 0, 0);
181	  if (install_partition == ULONG_MAX)
182	    {
183	      perror ("strtoul");
184	      exit (1);
185	    }
186	  break;
187
188	case OPT_BOOT_DRIVE:
189	  boot_drive = strtoul (optarg, 0, 0);
190	  if (boot_drive == ULONG_MAX)
191	    {
192	      perror ("strtoul");
193	      exit (1);
194	    }
195	  break;
196
197	case OPT_NO_CONFIG_FILE:
198	  use_config_file = 0;
199	  break;
200
201	case OPT_NO_CURSES:
202	  use_curses = 0;
203	  break;
204
205	case OPT_NO_PAGER:
206	  use_pager = 0;
207	  break;
208
209	case OPT_BATCH:
210	  /* This is the same as "--no-config-file --no-curses --no-pager".  */
211	  use_config_file = 0;
212	  use_curses = 0;
213	  use_pager = 0;
214	  break;
215
216	case OPT_READ_ONLY:
217	  read_only = 1;
218	  break;
219
220	case OPT_VERBOSE:
221	  verbose = 1;
222	  break;
223
224	case OPT_NO_FLOPPY:
225	  floppy_disks = 0;
226	  break;
227
228	case OPT_PROBE_SECOND_FLOPPY:
229	  floppy_disks = 2;
230	  break;
231
232	case OPT_DEVICE_MAP:
233	  device_map_file = strdup (optarg);
234	  break;
235
236	case OPT_PRESET_MENU:
237	  use_preset_menu = 1;
238	  break;
239
240	default:
241	  usage (1);
242	}
243    }
244  while (c != EOF);
245
246  /* Wait until the HOLD variable is cleared by an attached debugger. */
247  if (hold && verbose)
248    printf ("Run \"gdb %s %d\", and set HOLD to zero.\n",
249	    program_name, (int) getpid ());
250  while (hold)
251    {
252      if (hold > 0)
253	hold--;
254
255      sleep (1);
256    }
257
258  /* If we don't have curses (!HAVE_LIBCURSES or --no-curses or
259     --batch) put terminal to dumb for better handling of line i/o */
260  if (! use_curses)
261    current_term->flags = TERM_NO_EDIT | TERM_DUMB;
262
263  /* Transfer control to the stage2 simulator. */
264  exit (grub_stage2 ());
265}
266