3 |
* PUPA -- Preliminary Universal Programming Architecture for GRUB |
* PUPA -- Preliminary Universal Programming Architecture for GRUB |
4 |
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. |
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. |
5 |
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org> |
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org> |
6 |
|
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl> |
7 |
* |
* |
8 |
* PUPA is free software; you can redistribute it and/or modify |
* PUPA is free software; you can redistribute it and/or modify |
9 |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
39 |
#include <sys/types.h> |
#include <sys/types.h> |
40 |
#include <sys/stat.h> |
#include <sys/stat.h> |
41 |
#include <dirent.h> |
#include <dirent.h> |
42 |
|
#include <pupa/util/getroot.h> |
43 |
|
|
44 |
#define _GNU_SOURCE 1 |
#define _GNU_SOURCE 1 |
45 |
#include <getopt.h> |
#include <getopt.h> |
64 |
pupa_uint16_t segment; |
pupa_uint16_t segment; |
65 |
} __attribute__ ((packed)); |
} __attribute__ ((packed)); |
66 |
|
|
67 |
|
void |
68 |
|
pupa_putchar (int c) |
69 |
|
{ |
70 |
|
putchar (c); |
71 |
|
} |
72 |
|
|
73 |
|
void |
74 |
|
pupa_refresh (void) |
75 |
|
{ |
76 |
|
} |
77 |
|
|
78 |
static void |
static void |
79 |
setup (const char *prefix, const char *dir, |
setup (const char *prefix, const char *dir, |
80 |
const char *boot_file, const char *core_file, |
const char *boot_file, const char *core_file, |
492 |
return dev + 1; |
return dev + 1; |
493 |
} |
} |
494 |
|
|
|
static char * |
|
|
xgetcwd (void) |
|
|
{ |
|
|
size_t size = 10; |
|
|
char *path; |
|
|
|
|
|
path = xmalloc (size); |
|
|
while (! getcwd (path, size)) |
|
|
{ |
|
|
size <<= 1; |
|
|
path = xrealloc (path, size); |
|
|
} |
|
|
|
|
|
return path; |
|
|
} |
|
|
|
|
|
static void |
|
|
strip_extra_slashes (char *dir) |
|
|
{ |
|
|
char *p = dir; |
|
|
|
|
|
while ((p = strchr (p, '/')) != 0) |
|
|
{ |
|
|
if (p[1] == '/') |
|
|
{ |
|
|
memmove (p, p + 1, strlen (p)); |
|
|
continue; |
|
|
} |
|
|
else if (p[1] == '\0') |
|
|
{ |
|
|
p[0] = '\0'; |
|
|
break; |
|
|
} |
|
|
|
|
|
p++; |
|
|
} |
|
|
} |
|
|
|
|
|
static char * |
|
|
get_prefix (const char *dir) |
|
|
{ |
|
|
char *saved_cwd; |
|
|
char *abs_dir, *prev_dir; |
|
|
char *prefix; |
|
|
struct stat st, prev_st; |
|
|
|
|
|
/* Save the current directory. */ |
|
|
saved_cwd = xgetcwd (); |
|
|
|
|
|
if (chdir (dir) < 0) |
|
|
pupa_util_error ("Cannot change directory to `%s'", dir); |
|
|
|
|
|
abs_dir = xgetcwd (); |
|
|
strip_extra_slashes (abs_dir); |
|
|
prev_dir = xstrdup (abs_dir); |
|
|
|
|
|
if (stat (".", &prev_st) < 0) |
|
|
pupa_util_error ("Cannot stat `%s'", dir); |
|
|
|
|
|
if (! S_ISDIR (prev_st.st_mode)) |
|
|
pupa_util_error ("`%s' is not a directory", dir); |
|
|
|
|
|
while (1) |
|
|
{ |
|
|
if (chdir ("..") < 0) |
|
|
pupa_util_error ("Cannot change directory to the parent"); |
|
|
|
|
|
if (stat (".", &st) < 0) |
|
|
pupa_util_error ("Cannot stat current directory"); |
|
|
|
|
|
if (! S_ISDIR (st.st_mode)) |
|
|
pupa_util_error ("Current directory is not a directory???"); |
|
|
|
|
|
if (prev_st.st_dev != st.st_dev || prev_st.st_ino == st.st_ino) |
|
|
break; |
|
|
|
|
|
free (prev_dir); |
|
|
prev_dir = xgetcwd (); |
|
|
prev_st = st; |
|
|
} |
|
|
|
|
|
strip_extra_slashes (prev_dir); |
|
|
prefix = xmalloc (strlen (abs_dir) - strlen (prev_dir) + 2); |
|
|
prefix[0] = '/'; |
|
|
strcpy (prefix + 1, abs_dir + strlen (prev_dir)); |
|
|
strip_extra_slashes (prefix); |
|
|
|
|
|
if (chdir (saved_cwd) < 0) |
|
|
pupa_util_error ("Cannot change directory to `%s'", dir); |
|
|
|
|
|
free (saved_cwd); |
|
|
free (abs_dir); |
|
|
free (prev_dir); |
|
|
|
|
|
pupa_util_info ("prefix = %s", prefix); |
|
|
return prefix; |
|
|
} |
|
|
|
|
|
static char * |
|
|
find_root_device (const char *dir, dev_t dev) |
|
|
{ |
|
|
DIR *dp; |
|
|
char *saved_cwd; |
|
|
struct dirent *ent; |
|
|
|
|
|
dp = opendir (dir); |
|
|
if (! dp) |
|
|
return 0; |
|
|
|
|
|
saved_cwd = xgetcwd (); |
|
|
|
|
|
pupa_util_info ("changing current directory to %s", dir); |
|
|
if (chdir (dir) < 0) |
|
|
{ |
|
|
free (saved_cwd); |
|
|
closedir (dp); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
while ((ent = readdir (dp)) != 0) |
|
|
{ |
|
|
struct stat st; |
|
|
|
|
|
if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) |
|
|
continue; |
|
|
|
|
|
if (lstat (ent->d_name, &st) < 0) |
|
|
/* Ignore any error. */ |
|
|
continue; |
|
|
|
|
|
if (S_ISLNK (st.st_mode)) |
|
|
/* Don't follow symbolic links. */ |
|
|
continue; |
|
|
|
|
|
if (S_ISDIR (st.st_mode)) |
|
|
{ |
|
|
/* Find it recursively. */ |
|
|
char *res; |
|
|
|
|
|
res = find_root_device (ent->d_name, dev); |
|
|
|
|
|
if (res) |
|
|
{ |
|
|
if (chdir (saved_cwd) < 0) |
|
|
pupa_util_error ("Cannot restore the original directory"); |
|
|
|
|
|
free (saved_cwd); |
|
|
closedir (dp); |
|
|
return res; |
|
|
} |
|
|
} |
|
|
|
|
|
if (S_ISBLK (st.st_mode) && st.st_rdev == dev) |
|
|
{ |
|
|
/* Found! */ |
|
|
char *res; |
|
|
char *cwd; |
|
|
|
|
|
cwd = xgetcwd (); |
|
|
res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 2); |
|
|
sprintf (res, "%s/%s", cwd, ent->d_name); |
|
|
strip_extra_slashes (res); |
|
|
free (cwd); |
|
|
|
|
|
if (chdir (saved_cwd) < 0) |
|
|
pupa_util_error ("Cannot restore the original directory"); |
|
|
|
|
|
free (saved_cwd); |
|
|
closedir (dp); |
|
|
return res; |
|
|
} |
|
|
} |
|
|
|
|
|
if (chdir (saved_cwd) < 0) |
|
|
pupa_util_error ("Cannot restore the original directory"); |
|
|
|
|
|
free (saved_cwd); |
|
|
closedir (dp); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static char * |
|
|
guess_root_device (const char *dir) |
|
|
{ |
|
|
struct stat st; |
|
|
char *os_dev; |
|
|
|
|
|
if (stat (dir, &st) < 0) |
|
|
pupa_util_error ("Cannot stat `%s'", dir); |
|
|
|
|
|
/* This might be truly slow, but is there any better way? */ |
|
|
os_dev = find_root_device ("/dev", st.st_dev); |
|
|
if (! os_dev) |
|
|
return 0; |
|
|
|
|
|
return pupa_util_biosdisk_get_pupa_dev (os_dev); |
|
|
} |
|
|
|
|
495 |
int |
int |
496 |
main (int argc, char *argv[]) |
main (int argc, char *argv[]) |
497 |
{ |
{ |
589 |
usage (1); |
usage (1); |
590 |
} |
} |
591 |
|
|
592 |
prefix = get_prefix (dir ? : DEFAULT_DIRECTORY); |
prefix = pupa_get_prefix (dir ? : DEFAULT_DIRECTORY); |
593 |
|
|
594 |
/* Initialize the emulated biosdisk driver. */ |
/* Initialize the emulated biosdisk driver. */ |
595 |
pupa_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); |
pupa_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); |
610 |
} |
} |
611 |
else |
else |
612 |
{ |
{ |
613 |
root_dev = guess_root_device (dir ? : DEFAULT_DIRECTORY); |
root_dev = pupa_guess_root_device (dir ? : DEFAULT_DIRECTORY); |
614 |
if (! root_dev) |
if (! root_dev) |
615 |
{ |
{ |
616 |
pupa_util_info ("guessing the root device failed, because of `%s'", |
pupa_util_info ("guessing the root device failed, because of `%s'", |