/* * Guillaume Cottenceau (gc@mandrakesoft.com) * * Copyright 2000 Mandrakesoft * * This software may be freely redistributed under the terms of the GNU * public license. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * Portions from Erik Troan (ewt@redhat.com) * * Copyright 1996 Red Hat Software * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stage1.h" #include "log.h" #include "mount.h" #include "frontend.h" #include "automatic.h" #include "tools.h" #include "probing.h" #include "modules.h" #include "lomount.h" static struct param_elem params[50]; static int param_number = 0; void process_cmdline(void) { char buf[512]; int size, i; int fd = -1; if (IS_TESTING) { log_message("TESTING: opening cmdline... "); if ((fd = open("cmdline", O_RDONLY)) == -1) log_message("TESTING: could not open cmdline"); } if (fd == -1) { log_message("opening /proc/cmdline... "); if ((fd = open("/proc/cmdline", O_RDONLY)) == -1) fatal_error("could not open /proc/cmdline"); } size = read(fd, buf, sizeof(buf)); buf[size-1] = '\0'; // -1 to eat the \n close(fd); log_message("\t%s", buf); i = 0; while (buf[i] != '\0') { char *name, *value = NULL; int j = i; while (buf[i] != ' ' && buf[i] != '=' && buf[i] != '\0') i++; if (i == j) { i++; continue; } name = memdup(&buf[j], i-j + 1); name[i-j] = '\0'; if (buf[i] == '=') { int k = i+1; i++; while (buf[i] != ' ' && buf[i] != '\0') i++; value = memdup(&buf[k], i-k + 1); value[i-k] = '\0'; } params[param_number].name = name; params[param_number].value = value; param_number++; if (!strcmp(name, "changedisk")) set_param(MODE_CHANGEDISK); if (!strcmp(name, "updatemodules") || !strcmp(name, "thirdparty")) set_param(MODE_THIRDPARTY); if (!strcmp(name, "rescue")) set_param(MODE_RESCUE); if (!strcmp(name, "keepmounted")) set_param(MODE_KEEP_MOUNTED); if (!strcmp(name, "noauto")) set_param(MODE_NOAUTO); if (!strcmp(name, "netauto")) set_param(MODE_NETAUTO); if (!strcmp(name, "debugstage1")) set_param(MODE_DEBUGSTAGE1); if (!strcmp(name, "automatic")) { set_param(MODE_AUTOMATIC); grab_automatic_params(value); } if (buf[i] == '\0') break; i++; } log_message("\tgot %d args", param_number); } int stage1_mode = 0; int get_param(int i) { #ifdef SPAWN_INTERACTIVE static int fd = 0; char buf[5000]; char * ptr; int nb; if (fd <= 0) { fd = open(interactive_fifo, O_RDONLY); if (fd == -1) return (stage1_mode & i); fcntl(fd, F_SETFL, O_NONBLOCK); } if (fd > 0) { if ((nb = read(fd, buf, sizeof(buf))) > 0) { buf[nb] = '\0'; ptr = buf; while ((ptr = strstr(ptr, "+ "))) { if (!strncmp(ptr+2, "rescue", 6)) set_param(MODE_RESCUE); ptr++; } ptr = buf; while ((ptr = strstr(ptr, "- "))) { if (!strncmp(ptr+2, "rescue", 6)) unset_param(MODE_RESCUE); ptr++; } } } #endif return (stage1_mode & i); } char * get_param_valued(char *param_name) { int i; for (i = 0; i < param_number ; i++) if (!strcmp(params[i].name, param_name)) return params[i].value; return NULL; } void set_param_valued(char *param_name, char *param_value) { params[param_number].name = param_name; params[param_number].value = param_value; param_number++; } void set_param(int i) { stage1_mode |= i; } void unset_param(int i) { stage1_mode &= ~i; } void unset_automatic(void) { log_message("unsetting automatic"); unset_param(MODE_AUTOMATIC); exit_bootsplash(); } // warning, many things rely on the fact that: // - when failing it returns 0 // - it stops on first non-digit char int charstar_to_int(const char * s) { int number = 0; while (*s && isdigit(*s)) { number = (number * 10) + (*s - '0'); s++; } return number; } off_t file_size(const char * path) { struct stat statr; if (stat(path, &statr)) return -1; else return statr.st_size; } int total_memory(void) { int value; /* drakx powered: use /proc/kcore and rounds every 4 Mbytes */ value = 4 * ((int)((float)file_size("/proc/kcore") / 1024 / 1024 / 4 + 0.5)); log_message("Total Memory: %d Mbytes", value); return value; } int image_has_stage2() { #ifdef MANDRAKE_MOVE return access(IMAGE_LOCATION "/live_tree.clp", R_OK) == 0; #else return access(CLP_FILE_REL(IMAGE_LOCATION "/"), R_OK) == 0 || access(IMAGE_LOCATION "/" LIVE_LOCATION_REL, R_OK) == 0; #endif } int ramdisk_possible(void) { if (total_memory() > (IS_RESCUE ? MEM_LIMIT_RESCUE : MEM_LIMIT_DRAKX)) return 1; else { log_message("warning, ramdisk is not possible due to low mem!"); return 0; } } int clp_preload(void) { if (total_memory() > (IS_RESCUE ? MEM_LIMIT_RESCUE_PRELOAD : MEM_LIMIT_DRAKX_PRELOAD)) return 1; else { log_message("warning, not preloading clp due to low mem"); return 0; } } enum return_type save_fd(int from_fd, char * to, void (*callback_func)(int overall)) { FILE * f_to; size_t quantity __attribute__((aligned(16))), overall = 0; char buf[4096] __attribute__((aligned(4096))); int ret = RETURN_ERROR; if (!(f_to = fopen(to, "w"))) { log_perror(to); goto close_from; } do { quantity = read(from_fd, buf, sizeof(buf)); if (quantity > 0) { if (fwrite(buf, 1, quantity, f_to) != quantity) { log_message("short write (%s)", strerror(errno)); goto cleanup; } } else if (quantity == -1) { log_message("an error occured: %s", strerror(errno)); goto cleanup; } if (callback_func) { overall += quantity; callback_func(overall); } } while (quantity); ret = RETURN_OK; cleanup: fclose(f_to); close_from: close(from_fd); return ret; } enum return_type copy_file(char * from, char * to, void (*callback_func)(int overall)) { int from_fd; log_message("copy_file: %s -> %s", from, to); from_fd = open(from, O_RDONLY); if (from_fd != -1) { return save_fd(from_fd, to, callback_func); } else { log_perror(from); return RETURN_ERROR; } } enum return_type mount_clp(char *clp, char *location_mount) { if (lomount(clp, location_mount, NULL, 1)) { stg1_error_message("Could not mount compressed loopback :(."); return RETURN_ERROR; } return RETURN_OK; } enum return_type preload_mount_clp(int clp_fd, int clp_size, char *clp_name, char *location_mount) { int ret; char *clp_tmpfs = asprintf_("%s/tmp/%s", SLASH_LOCATION, clp_name); #ifdef MANDRAKE_MOVE static int count = 0; char buf[5000]; sprintf(buf, "Loading program into memory (part %d)...", ++count); #else char *buf = "Loading program into memory..."; #endif init_progression(buf, clp_size); ret = save_fd(clp_fd, clp_tmpfs, update_progression); end_progression(); if (ret != RETURN_OK) return ret; return mount_clp(clp_tmpfs, location_mount); } enum return_type mount_clp_may_preload(char *clp_name, char *location_mount, int preload) { char *clp = asprintf_("%s/%s", CLP_LOCATION, clp_name); log_message("mount_clp_may_preload: %s into %s (preload = %d)", clp, location_mount, preload); if (access(clp, R_OK) != 0) return RETURN_ERROR; if (preload) { int clp_fd = open(clp, O_RDONLY); if (clp_fd != -1) { return preload_mount_clp(clp_fd, file_size(clp), clp_name, location_mount); } else { log_perror(clp); return RETURN_ERROR; } } else { return mount_clp(clp, location_mount); } } #ifndef MANDRAKE_MOVE enum return_type may_load_clp(void) { if (!IS_RESCUE && access(IMAGE_LOCATION "/" LIVE_LOCATION_REL, R_OK) == 0) { /* LIVE install */ return RETURN_OK; } else { /* CLP install */ return mount_clp_may_preload(CLP_NAME(""), STAGE2_LOCATION, clp_preload()); } } enum return_type load_clp_fd(int fd, int size) { return preload_mount_clp(fd, size, CLP_NAME(""), STAGE2_LOCATION); } #endif /* pixel's */ void * memdup(void *src, size_t size) { void * r; r = malloc(size); memcpy(r, src, size); return r; } void add_to_env(char * name, char * value) { FILE* fakeenv = fopen(SLASH_LOCATION "/tmp/env", "a"); if (fakeenv) { char* e = asprintf_("%s=%s\n", name, value); fwrite(e, 1, strlen(e), fakeenv); free(e); fclose(fakeenv); } else log_message("couldn't fopen to fake env"); } char ** list_directory(char * direct) { char * tmp[50000]; /* in /dev there can be many many files.. */ int i = 0; struct dirent *ep; DIR *dp = opendir(direct); while (dp && (ep = readdir(dp))) { if (strcmp(ep->d_name, ".") && strcmp(ep->d_name, "..")) { tmp[i] = strdup(ep->d_name); i++; } } if (dp) closedir(dp); tmp[i] = NULL; return memdup(tmp, sizeof(char*) * (i+1)); } int string_array_length(char ** a) { int i = 0; if (!a) return -1; while (a && *a) { a++; i++; } return i; } int kernel_version(void) { struct utsname val; if (uname(&val)) { log_perror("uname failed"); return -1; } return charstar_to_int(val.release + 2); } int try_mount(char * dev, char * location) { char device_fullname[50]; strcpy(device_fullname, "/dev/"); strcat(device_fullname, dev); if (my_mount(device_fullname, location, "ext2", 0) == -1 && my_mount(device_fullname, location, "vfat", 0) == -1 && my_mount(device_fullname, location, "ntfs", 0) == -1 && my_mount(device_fullname, location, "reiserfs", 0) == -1 && my_mount(device_fullname, location, "iso9660", 0) == -1) { return 1; } return 0; } #ifndef DISABLE_DISK int get_disks(char *** names, char *** models) { char ** ptr; int count = 0; my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL, 0); get_medias(DISK, names, models, BUS_ANY); ptr = *names; while (ptr && *ptr) { count++; ptr++; } return count; } #endif #ifndef DISABLE_CDROM int get_cdroms(char *** names, char *** models) { char ** ptr; int count = 0; my_insmod("ide-cd", ANY_DRIVER_TYPE, NULL, 0); my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL, 0); get_medias(CDROM, names, models, BUS_ANY); ptr = *names; while (ptr && *ptr) { count++; ptr++; } return count; } #endif char * floppy_device(void) { char ** names, ** models; int fd; my_insmod("floppy", ANY_DRIVER_TYPE, NULL, 0); fd = open("/dev/fd0", O_RDONLY|O_NONBLOCK); if (fd != -1) { char drivtyp[17]; if (!ioctl(fd, FDGETDRVTYP, (void *)drivtyp)) { struct floppy_drive_struct ds; log_message("/dev/fd0 type: %s", drivtyp); if (!ioctl(fd, FDPOLLDRVSTAT, &ds)) { log_message("\ttrack: %d", ds.track); if (ds.track >= 0) { close(fd); return "/dev/fd0"; } } } else { log_perror("can't FDGETDRVTYP /dev/fd0"); } close(fd); } log_message("seems that you don't have a regular floppy drive"); my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL, 0); get_medias(FLOPPY, &names, &models, BUS_ANY); if (names && *names) return asprintf_("/dev/%s", *names); else return "/dev/fd0"; } char * asprintf_(const char *msg, ...) { int n; char * s; va_list arg_ptr; va_start(arg_ptr, msg); n = vsnprintf(0, 1000000, msg, arg_ptr); va_start(arg_ptr, msg); if ((s = malloc(n + 1))) { vsnprintf(s, n + 1, msg, arg_ptr); va_end(arg_ptr); return s; } va_end(arg_ptr); return strdup(""); } int scall_(int retval, char * msg, char * file, int line) { char tmp[5000]; sprintf(tmp, "%s(%s:%d) failed", msg, file, line); if (retval) log_perror(tmp); return retval; }