static void grub_vprintf (const char *format, int *dataptr) { char c, str[16]; while ((c = *(format++)) != 0) { if (c != '%') grub_putchar (c); else switch (c = *(format++)) { #ifndef STAGE1_5 case 'd': case 'x': case 'X': #endif case 'u': *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0; grub_putstr (str); break; #ifndef STAGE1_5 case 'c': grub_putchar ((*(dataptr++)) & 0xff); break; case 's': grub_putstr ((char *) *(dataptr++)); break; #endif } } }
/* Move the cursor forward. */ void cl_forward (int count) { lpos += count; /* If the cursor goes outside, scroll the screen to the right. */ if (xpos + count >= CMDLINE_WIDTH) cl_refresh (1, 0); else { xpos += count; if (current_term->flags & TERM_DUMB) { int i; for (i = lpos - count; i < lpos; i++) { if (! echo_char) grub_putchar (buf[i]); else grub_putchar (echo_char); } } else gotoxy (xpos, getxy () & 0xFF); } }
/* Wait until the user pushes any key so that the user can see what happened. */ void grub_wait_after_message (void) { grub_putchar ('\n'); grub_printf_ (N_("Press any key to continue...")); (void) grub_getkey (); grub_putchar ('\n'); }
int grub_puts (const char *s) { while (*s) { grub_putchar (*s); s++; } grub_putchar ('\n'); return 1; /* Cannot fail. */ }
static char * grub_getline (void) { int i; char *line; char *tmp; char c; i = 0; line = grub_malloc (1 + i + sizeof('\0')); if (! line) return NULL; while (1) { c = grub_getkey (); if ((c == '\n') || (c == '\r')) break; line[i] = c; if (grub_isprint (c)) grub_putchar (c); i++; tmp = grub_realloc (line, 1 + i + sizeof('\0')); if (! tmp) { grub_free (line); return NULL; } line = tmp; } line[i] = '\0'; return line; }
/* Initialize the command-line. */ void cl_init (void) { /* Distinguish us from other lines and error messages! */ grub_putchar ('\n'); /* Print full line and set position here. */ cl_refresh (1, 0); }
/* Enter the command-line interface. HEAP is used for the command-line buffer. Return only if FOREVER is nonzero and get_cmdline returns nonzero (ESC is pushed). */ void enter_cmdline (char *heap, int forever) { /* Initialize the data and print a message. */ init_cmdline (); grub_setjmp (restart_cmdline_env); init_page (); #ifdef SUPPORT_DISKLESS print_network_configuration (); grub_putchar ('\n'); #endif print_cmdline_message (forever); while (1) { struct builtin *builtin; char *arg; *heap = 0; print_error (); errnum = ERR_NONE; /* Get the command-line with the minimal BASH-like interface. */ if (get_cmdline (PACKAGE "> ", heap, 2048, 0, 1)) return; /* If there was no command, grab a new one. */ if (! heap[0]) continue; /* Find a builtin. */ builtin = find_command (heap); if (! builtin) continue; /* If BUILTIN cannot be run in the command-line, skip it. */ if (! (builtin->flags & BUILTIN_CMDLINE)) { errnum = ERR_UNRECOGNIZED; continue; } /* Invalidate the cache, because the user may exchange removable disks. */ buf_drive = -1; /* Start to count lines, only if the internal pager is in use. */ if (use_pager) count_lines = 0; /* Run BUILTIN->FUNC. */ arg = skip_to (1, heap); (builtin->func) (arg, BUILTIN_CMDLINE); /* Finish the line count. */ count_lines = -1; } }
void twiddle (void) { static unsigned long lastticks = 0; static int count = 0; static const char tiddles[]="-\\|/"; unsigned long ticks; if (debug) { if ((ticks = currticks ()) == lastticks) return; lastticks = ticks; grub_putchar (tiddles[(count++) & 3]); grub_putchar ('\b'); } }
/* Send the RRQ whose length is LEN. */ static int send_rrq (void) { /* Initialize some variables. */ retry = 0; block = 0; prevblock = 0; packetsize = TFTP_DEFAULTSIZE_PACKET; bcounter = 0; buf = (char *) FSYS_BUF; buf_eof = 0; buf_read = 0; saved_filepos = 0; /* Clear out the Rx queue first. It contains nothing of interest, * except possibly ARP requests from the DHCP/TFTP server. We use * polling throughout Etherboot, so some time may have passed since we * last polled the receive queue, which may now be filled with * broadcast packets. This will cause the reply to the packets we are * about to send to be lost immediately. Not very clever. */ await_reply (AWAIT_QDRAIN, 0, NULL, 0); #ifdef TFTP_DEBUG grub_printf ("send_rrq ()\n"); { int i; char *p; for (i = 0, p = (char *) &tp; i < len; i++) if (p[i] >= ' ' && p[i] <= '~') grub_putchar (p[i]); else grub_printf ("\\%x", (unsigned) p[i]); grub_putchar ('\n'); } #endif /* Send the packet. */ return udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp); }
/* Enter the command-line interface. HEAP is used for the command-line buffer. Return only if FOREVER is nonzero and get_cmdline returns nonzero (ESC is pushed). */ void enter_cmdline (char *heap, int forever) { if (! debug) debug++; //grub_setjmp (restart_cmdline_env); /* Initialize the data and print a message. */ current_drive = GRUB_INVALID_DRIVE; count_lines = -1; kernel_type = KERNEL_TYPE_NONE; errnum = 0; errorcheck = 1; /* errorcheck on */ init_page (); grub_putchar ('\n'); #ifdef SUPPORT_DISKLESS print_network_configuration (); grub_putchar ('\n'); #endif print_cmdline_message (forever); while (1) { struct builtin *builtin; char *arg; grub_error_t errnum_old; errnum_old = errnum; *heap = 0; if (errnum && errorcheck) print_error (); errnum = ERR_NONE; /* Get the command-line with the minimal BASH-like interface. */ prompt = PACKAGE "> "; maxlen = 2048; echo_char = 0; readline = 1; if (get_cmdline (heap)) { kernel_type = KERNEL_TYPE_NONE; return; } /* If there was no command, grab a new one. */ if (! heap[0]) continue; /* Find a builtin. */ builtin = find_command (heap); if (! builtin) continue; /* If BUILTIN cannot be run in the command-line, skip it. */ if (! (builtin->flags & BUILTIN_CMDLINE)) { errnum = ERR_UNRECOGNIZED; continue; } /* Invalidate the cache, because the user may exchange removable disks. */ buf_drive = -1; /* Start to count lines, only if the internal pager is in use. */ if (use_pager) count_lines = 0; if ((builtin->func) == errnum_func || (builtin->func) == checkrange_func) errnum = errnum_old; /* find && and || */ for (arg = skip_to (0, heap); *arg != 0; arg = skip_to (0, arg)) { struct builtin *builtin1; int ret; char *arg1; arg1 = arg; if (*arg == '&' && arg[1] == '&' && (arg[2] == ' ' || arg[2] == '\t')) { /* handle the AND operator */ arg = skip_to (0, arg); builtin1 = find_command (arg); if (! builtin1 || ! (builtin1->flags & BUILTIN_CMDLINE)) { errnum = ERR_UNRECOGNIZED; goto next; } *arg1 = 0; ret = (builtin->func) (skip_to (1, heap), BUILTIN_CMDLINE); *arg1 = '&'; if (ret) { arg = skip_to (1, arg); if ((builtin1->func) != errnum_func && (builtin1->func) != checkrange_func) errnum = 0; (builtin1->func) (arg, BUILTIN_CMDLINE); } else errnum = 0; goto next; } else if (*arg == '|' && arg[1] == '|' && (arg[2] == ' ' || arg[2] == '\t')) { /* handle the OR operator */ arg = skip_to (0, arg); builtin1 = find_command (arg); if (! builtin1 || ! (builtin1->flags & BUILTIN_CMDLINE)) { errnum = ERR_UNRECOGNIZED; goto next; } *arg1 = 0; ret = (builtin->func) (skip_to (1, heap), BUILTIN_CMDLINE); *arg1 = '|'; if (! ret) { arg = skip_to (1, arg); if ((builtin1->func) != errnum_func && (builtin1->func) != checkrange_func) errnum = 0; (builtin1->func) (arg, BUILTIN_CMDLINE); } else errnum = 0; goto next; } } /* Run BUILTIN->FUNC. */ arg = (builtin->func) == commandline_func ? heap : skip_to (1, heap); (builtin->func) (arg, BUILTIN_CMDLINE); next: /* Finish the line count. */ count_lines = -1; } }
/* Read up to SIZE bytes, returned in ADDR. */ int tftp_read (char *addr, int size) { /* How many bytes is read? */ int ret = 0; #ifdef TFTP_DEBUG grub_printf ("tftp_read (0x%x, %d)\n", (int) addr, size); #endif if (filepos < saved_filepos) { /* Uggh.. FILEPOS has been moved backwards. So reopen the file. */ buf_read = 0; buf_fill (1); grub_memmove ((char *) &tp, (char *) &saved_tp, saved_len); len = saved_len; #ifdef TFTP_DEBUG { int i; grub_printf ("opcode = 0x%x, rrq = ", (unsigned long) tp.opcode); for (i = 0; i < TFTP_DEFAULTSIZE_PACKET; i++) { if (tp.u.rrq[i] >= ' ' && tp.u.rrq[i] <= '~') grub_putchar (tp.u.rrq[i]); else grub_putchar ('*'); } grub_putchar ('\n'); } #endif if (! send_rrq ()) { errnum = ERR_WRITE; return 0; } } while (size > 0) { int amt = buf_read + saved_filepos - filepos; /* If the length that can be copied from the buffer is over the requested size, cut it down. */ if (amt > size) amt = size; if (amt > 0) { /* Copy the buffer to the supplied memory space. */ grub_memmove (addr, buf + filepos - saved_filepos, amt); size -= amt; addr += amt; filepos += amt; ret += amt; /* If the size of the empty space becomes small, move the unused data forwards. */ if (filepos - saved_filepos > FSYS_BUFLEN / 2) { grub_memmove (buf, buf + FSYS_BUFLEN / 2, FSYS_BUFLEN / 2); buf_read -= FSYS_BUFLEN / 2; saved_filepos += FSYS_BUFLEN / 2; } } else { /* Skip the whole buffer. */ saved_filepos += buf_read; buf_read = 0; } /* Read the data. */ if (size > 0 && ! buf_fill (0)) { errnum = ERR_READ; return 0; } /* Sanity check. */ if (size > 0 && buf_read == 0) { errnum = ERR_READ; return 0; } } return ret; }
/* Refresh the screen. If FULL is true, redraw the full line, otherwise, only LEN characters from LPOS. */ void cl_refresh (int full, int len) { int i; int start; int pos = xpos; if (full) { /* Recompute the section number. */ if (lpos + plen < CMDLINE_WIDTH) section = 0; else section = ((lpos + plen - CMDLINE_WIDTH) / (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + 1); /* From the start to the end. */ len = CMDLINE_WIDTH; pos = 0; grub_putchar ('\r'); /* If SECTION is the first section, print the prompt, otherwise, print `<'. */ if (section == 0) { grub_printf ("%s", prompt); len -= plen; pos += plen; } else { grub_putchar ('<'); len--; pos++; } } /* Compute the index to start writing BUF and the resulting position on the screen. */ if (section == 0) { int offset = 0; if (! full) offset = xpos - plen; start = 0; xpos = lpos + plen; start += offset; } else { int offset = 0; if (! full) offset = xpos - 1; start = ((section - 1) * (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + CMDLINE_WIDTH - plen - CMDLINE_MARGIN); xpos = lpos + 1 - start; start += offset; } /* Print BUF. If ECHO_CHAR is not zero, put it instead. */ for (i = start; i < start + len && i < llen; i++) { if (! echo_char) grub_putchar (buf[i]); else grub_putchar (echo_char); pos++; } /* Fill up the rest of the line with spaces. */ for (; i < start + len; i++) { grub_putchar (' '); pos++; } /* If the cursor is at the last position, put `>' or a space, depending on if there are more characters in BUF. */ if (pos == CMDLINE_WIDTH) { if (start + len < llen) grub_putchar ('>'); else grub_putchar (' '); pos++; } /* Back to XPOS. */ if (current_term->flags & TERM_DUMB) { for (i = 0; i < pos - xpos; i++) grub_putchar ('\b'); } else gotoxy (xpos, getxy () & 0xFF); }
static int real_get_cmdline (char *prompt, char *cmdline, int maxlen, int echo_char, int readline) { /* This is a rather complicated function. So explain the concept. A command-line consists of ``section''s. A section is a part of the line which may be displayed on the screen, but a section is never displayed with another section simultaneously. Each section is basically 77 or less characters, but the exception is the first section, which is 78 or less characters, because the starting point is special. See below. The first section contains a prompt and a command-line (or the first part of a command-line when it is too long to be fit in the screen). So, in the first section, the number of command-line characters displayed is 78 minus the length of the prompt (or less). If the command-line has more characters, `>' is put at the position 78 (zero-origin), to inform the user of the hidden characters. Other sections always have `<' at the first position, since there is absolutely a section before each section. If there is a section after another section, this section consists of 77 characters and `>' at the last position. The last section has 77 or less characters and doesn't have `>'. Each section other than the last shares some characters with the previous section. This region is called ``margin''. If the cursor is put at the magin which is shared by the first section and the second, the first section is displayed. Otherwise, a displayed section is switched to another section, only if the cursor is put outside that section. */ /* XXX: These should be defined in shared.h, but I leave these here, until this code is freezed. */ #define CMDLINE_WIDTH 78 #define CMDLINE_MARGIN 10 int xpos, lpos, c, section; /* The length of PROMPT. */ int plen; /* The length of the command-line. */ int llen; /* The index for the history. */ int history = -1; /* The working buffer for the command-line. */ char *buf = (char *) CMDLINE_BUF; /* The kill buffer. */ char *kill_buf = (char *) KILL_BUF; /* Nested function definitions for code simplicity. */ /* The forward declarations of nested functions are prefixed with `auto'. */ auto void cl_refresh (int full, int len); auto void cl_backward (int count); auto void cl_forward (int count); auto void cl_insert (const char *str); auto void cl_delete (int count); auto void cl_init (void); /* Move the cursor backward. */ void cl_backward (int count) { lpos -= count; /* If the cursor is in the first section, display the first section instead of the second. */ if (section == 1 && plen + lpos < CMDLINE_WIDTH) cl_refresh (1, 0); else if (xpos - count < 1) cl_refresh (1, 0); else { xpos -= count; if (current_term->flags & TERM_DUMB) { int i; for (i = 0; i < count; i++) grub_putchar ('\b'); } else gotoxy (xpos, getxy () & 0xFF); } }
void grub_putstr (const char *str) { while (*str) grub_putchar (*str++); }
/* Print the information on the device NAME. */ grub_err_t grub_print_device_info (const char *name) { grub_device_t dev; char *p; p = grub_strchr (name, ','); if (p) { grub_putchar ('\t'); grub_printf_ (N_("Partition %s:"), name); grub_putchar (' '); } else { grub_printf_ (N_("Device %s:"), name); grub_putchar (' '); } dev = grub_device_open (name); if (! dev) grub_printf ("%s", _("Filesystem cannot be accessed")); else if (dev->disk) { grub_fs_t fs; fs = grub_fs_probe (dev); /* Ignore all errors. */ grub_errno = 0; if (fs) { grub_printf_ (N_("Filesystem type %s"), fs->name); if (fs->label) { char *label; (fs->label) (dev, &label); if (grub_errno == GRUB_ERR_NONE) { if (label && grub_strlen (label)) { grub_putchar (' '); grub_printf_ (N_("- Label \"%s\""), label); } grub_free (label); } grub_errno = GRUB_ERR_NONE; } if (fs->mtime) { grub_int32_t tm; struct grub_datetime datetime; (fs->mtime) (dev, &tm); if (grub_errno == GRUB_ERR_NONE) { grub_unixtime2datetime (tm, &datetime); grub_putchar (' '); grub_printf_ (N_("- Last modification time %d-%02d-%02d " "%02d:%02d:%02d %s"), datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, grub_get_weekday_name (&datetime)); } grub_errno = GRUB_ERR_NONE; } if (fs->uuid) { char *uuid; (fs->uuid) (dev, &uuid); if (grub_errno == GRUB_ERR_NONE) { if (uuid && grub_strlen (uuid)) grub_printf (", UUID %s", uuid); grub_free (uuid); } grub_errno = GRUB_ERR_NONE; } } else if (! dev->disk->has_partitions || dev->disk->partition) grub_printf ("%s", _("Unknown filesystem")); else grub_printf ("%s", _("Partition table")); grub_device_close (dev); } grub_putchar ('\n'); return grub_errno; }
/************************************************************************** PRINTF and friends Formats: %[#]x - 4 bytes long (8 hex digits, lower case) %[#]X - 4 bytes long (8 hex digits, upper case) %[#]hx - 2 bytes int (4 hex digits, lower case) %[#]hX - 2 bytes int (4 hex digits, upper case) %[#]hhx - 1 byte int (2 hex digits, lower case) %[#]hhX - 1 byte int (2 hex digits, upper case) - optional # prefixes 0x or 0X %d - decimal int %c - char %s - string %@ - Internet address in ddd.ddd.ddd.ddd notation %! - Ethernet address in xx:xx:xx:xx:xx:xx notation Note: width specification not supported **************************************************************************/ static int etherboot_vsprintf (char *buf, const char *fmt, va_list dp) { char *p, *s; s = buf; for ( ; *fmt != '\0'; ++fmt) { if (*fmt != '%') { buf ? *s++ = *fmt : grub_putchar (*fmt); continue; } if (*++fmt == 's') { for (p = va_arg (dp, char *); *p != '\0'; p++) buf ? *s++ = *p : grub_putchar (*p); } else { /* Length of item is bounded */ char tmp[20], *q = tmp; int alt = 0; int shift = 28; if (*fmt == '#') { alt = 1; fmt++; } if (*fmt == 'h') { shift = 12; fmt++; } if (*fmt == 'h') { shift = 4; fmt++; } /* * Before each format q points to tmp buffer * After each format q points past end of item */ if ((*fmt | 0x20) == 'x') { /* With x86 gcc, sizeof(long) == sizeof(int) */ long h = va_arg (dp, long); int ncase = (*fmt & 0x20); if (alt) { *q++ = '0'; *q++ = 'X' | ncase; } for (; shift >= 0; shift -= 4) *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase; } else if (*fmt == 'd')