#include #include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "fs.h" #include "install.h" #include "intl.h" #include "log.h" #include "mkswap.h" #include "run.h" #include "smb.h" #include "windows.h" #ifndef DISABLE_NETWORK int nfsmount(const char *spec, const char *node, int *flags, char **extra_opts, char **mount_opts); char *nfs_error(void); #endif static int fstabCmp(const void * a, const void * b); static int mkdirChain(char * chain); static int mkdirIfNone(char * directory); int badBlocks = 0; char * nstrdup(const char * foo) { return foo ? strdup(foo) : NULL; } static int fstabCmp(const void * a, const void * b) { const struct fstabEntry * first = a; const struct fstabEntry * second = b; if (first->type != second->type) { if (first->type == PART_NFS) return 1; else if (second->type == PART_NFS) return -1; } return strcmp(first->mntpoint, second->mntpoint); } void fstabSort(struct fstab * fstab) { qsort(fstab->entries, fstab->numEntries, sizeof(*fstab->entries), fstabCmp); } void initFstabEntry(struct fstabEntry * e) { e->device = NULL; e->netHost = NULL; e->netPath = NULL; e->mntpoint = NULL; e->tagName = NULL; e->size = 0; e->type = PART_OTHER; e->isMounted = 0; e->doFormat = 0; } void addPartitionListbox(struct partitionTable table, int maxHeight, int type, int (*filter)(struct partition * part), int * numItems, newtGrid * gridPtr, newtComponent * listboxPtr) { newtComponent listbox, label; int i, count; char buf[80]; count = 0; for (i = 0; i < table.count; i++) if (table.parts[i].type & type) if (!filter || filter(table.parts + i)) count++; *listboxPtr = listbox = newtListbox(-1, -1, count < maxHeight ? count : maxHeight, NEWT_FLAG_RETURNEXIT | (count > maxHeight ? NEWT_FLAG_SCROLL : 0)); label = newtLabel(-1, -1, "Device Size (k)"); if (numItems) *numItems = 0; for (i = 0; i < table.count; i++) { if (table.parts[i].type & type) { if (!filter || filter(table.parts + i)) { sprintf(buf, "/dev/%-11s %9d", table.parts[i].device, table.parts[i].size); newtListboxAddEntry(listbox, buf, &table.parts[i]); if (numItems) (*numItems)++; } } } /* using VStacked right here adds too much padding */ *gridPtr = newtCreateGrid(1, 2); newtGridSetField(*gridPtr, 0, 0, NEWT_GRID_COMPONENT, label, 0, 0, 0, 0, 0, 0); newtGridSetField(*gridPtr, 0, 1, NEWT_GRID_COMPONENT, listbox, 0, 0, 0, 0, 0, 0); } static int badMountPoint(unsigned int type, char * item) { char * chptr = item; if (*chptr != '/') { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("Mount points must begin with a leading /.")); return INST_ERROR; } if (*(chptr + 1) && *(chptr + strlen(chptr) - 1) == '/') { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("Mount points may not end with a /.")); return INST_ERROR; } while (*chptr && isprint(*chptr)) chptr++; if (*chptr) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("Mount points may only printable characters.")); return INST_ERROR; } if (type != PART_EXT2 && ( !strncmp(item, "/var", 4) || !strncmp(item, "/tmp", 4) || !strncmp(item, "/bin", 4) || !strncmp(item, "/sbin", 4) || !strncmp(item, "/etc", 4) || !strncmp(item, "/boot", 4) || !strncmp(item, "/dev", 4) || !strncmp(item, "/root", 4) || !strncmp(item, "/lib", 4))) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("System partitions must be on Linux Native " "partitions.")); return INST_ERROR; } if (type != PART_EXT2 && type != PART_NFS && !strncmp(item, "/usr", 4)) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("/usr must be on a Linux Native partition " "or an NFS volume.")); return INST_ERROR; } return 0; } static char * restrdup(char * old, char * new) { if (old) free(old); if (new) return strdup(new); else return NULL; } #ifndef DISABLE_NETWORK void nfsMountCallback(newtComponent co, void * arg) { struct nfsMountCallbackInfo * nfsinfo = arg; char * chptr; char * copy; if (!strlen(nfsinfo->netpathVal)) { if (strchr(nfsinfo->serverVal, ':')) { chptr = copy = alloca(strlen(nfsinfo->serverVal) + 1); strcpy(copy, nfsinfo->serverVal); chptr = strchr(copy, ':'); *chptr = '\0'; chptr++; newtEntrySet(nfsinfo->server, copy, 1); newtEntrySet(nfsinfo->netpath, chptr, 1); } } if (nfsinfo->mntpoint) { if (strlen(nfsinfo->netpathVal) && !strlen(nfsinfo->mntpointVal)) { newtEntrySet(nfsinfo->mntpoint, nfsinfo->netpathVal, 1); } } } int editNetMountPoint(struct fstabEntry * item) { newtComponent form, server, path, point, okay, cancel, answer; char * pointValue, * pathValue, * serverValue; int done = 0; struct nfsMountCallbackInfo nfsinfo; newtCenteredWindow(50, 10, _("Edit Network Mount Point")); form = newtForm(NULL, NULL, 0); newtFormAddComponent(form, newtLabel(1, 1, "NFS Server :")); newtFormAddComponent(form, newtLabel(1, 2, "NFS Path :")); newtFormAddComponent(form, newtLabel(1, 3, "Mount point :")); server = newtEntry(17, 1, item->netHost, 20, &serverValue, NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT); path = newtEntry(17, 2, item->netPath, 20, &pathValue, NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT); point = newtEntry(17, 3, item->mntpoint, 20, &pointValue, NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT); nfsinfo.server = server; nfsinfo.mntpoint = point; nfsinfo.netpath = path; nfsinfo.serverVal = serverValue; nfsinfo.netpathVal = pathValue; nfsinfo.mntpointVal = pointValue; newtComponentAddCallback(server, nfsMountCallback, &nfsinfo); newtComponentAddCallback(path, nfsMountCallback, &nfsinfo); okay = newtButton(10, 6, _("Ok")); cancel = newtButton(30, 6, _("Cancel")); newtFormAddComponents(form, server, path, point, okay, cancel, NULL); do { answer = newtRunForm(form); if (answer == cancel) { done = 1; } else if (*pointValue) { if (!badMountPoint(item->type, pointValue)) done = 1; } } while (!done); if (answer != cancel) { item->mntpoint = restrdup(item->mntpoint, pointValue); item->netPath = restrdup(item->netPath, pathValue); item->netHost = restrdup(item->netHost, serverValue); if (item->device) free(item->device); item->device = malloc(strlen(pathValue) + strlen(serverValue) + 5); sprintf(item->device, "%s:%s", serverValue, pathValue); } newtPopWindow(); if (answer == cancel) return INST_CANCEL; return 0; } #endif void freeFstabEntry( struct fstabEntry *e ) { if (e->mntpoint) free(e->mntpoint); if (e->device) free(e->device); if (e->netPath) free(e->netPath); if (e->netHost) free(e->netHost); } void freeFstab(struct fstab fstab) { int i; for (i = 0; i < fstab.numEntries; i++) { freeFstabEntry( &fstab.entries[i] ); } if (fstab.numEntries) free(fstab.entries); } struct fstab copyFstab(struct fstab * fstab) { struct fstab newfstab; int i, j; if (!fstab->numEntries) { newfstab.numEntries = 0; newfstab.entries = malloc(1); return newfstab; } /* duplicate the current fstab */ newfstab.numEntries = fstab->numEntries; newfstab.entries = malloc(fstab->numEntries * sizeof(struct fstabEntry)); for (i = j = 0; i < newfstab.numEntries; i++) { if (fstab->entries[i].mntpoint) { newfstab.entries[j] = fstab->entries[i]; newfstab.entries[j].mntpoint = nstrdup(fstab->entries[i].mntpoint); newfstab.entries[j].device = nstrdup(fstab->entries[i].device); newfstab.entries[j].netPath = nstrdup(fstab->entries[i].netPath); newfstab.entries[j].netHost = nstrdup(fstab->entries[i].netHost); j++; } } newfstab.numEntries = j; /* return the memory we don't actually need */ newfstab.entries = realloc(newfstab.entries, j * sizeof(struct fstabEntry)); return newfstab; } static int mkExt2Filesystem(char * dev) { char * mke2fsargs[] = { "mke2fs", NULL, NULL, NULL, NULL, NULL, NULL, NULL}; int rc; int i; char message[80]; i = 1; mke2fsargs[i] = alloca(strlen(dev) + 6); strcpy(mke2fsargs[i], "/tmp/"); strcat(mke2fsargs[i++], dev); if (strstr (dev, "rd/") || strstr (dev, "ida/")) { /* For RAID only. */ mke2fsargs[i++] = "-b"; mke2fsargs[i++] = "4096"; mke2fsargs[i++] = "-R"; mke2fsargs[i++] = "stride=16"; } if (badBlocks) mke2fsargs[i++] = "-c"; sprintf(message, _("Making ext2 filesystem on /dev/%s..."), dev); winStatus(60, 3, _("Running"), message); devMakeInode(dev, mke2fsargs[1]); rc = runProgram(RUN_LOG, "/usr/bin/mke2fs", mke2fsargs); devRemoveInode(mke2fsargs[1]); newtPopWindow(); if (rc) return INST_ERROR; else return 0; } int queryFormatFilesystems(struct fstab * fstab) { newtComponent form, checkList, okay, cancel, sb, text, answer; newtComponent checkbox, blank; newtGrid grid, subgrid, checkgrid, buttons; char * states; char doCheck = ' '; newtComponent * checks; char buf[80]; int i, top; form = newtForm(NULL, NULL, 0); if (fstab->numEntries > 4) { sb = newtVerticalScrollbar(47, 7, 4, 9, 10); } else sb = NULL; checkList = newtForm(sb, NULL, 0); if (sb) newtFormSetHeight(checkList, 4); text = newtTextboxReflowed(-1, -1, _("What partitions would you like to " "format? We strongly suggest formatting all of the " "system partitions, including /, /usr, and /var. There " "is no need to format /home or /usr/local if they " "have already been configured during a previous " "install."), 55, 0, 15, 0); checks = alloca(sizeof(newtComponent) * fstab->numEntries); states = alloca(sizeof(char) * fstab->numEntries); for (i = 0, top = 0; i < fstab->numEntries; i++) { if (fstab->entries[i].doFormat) states[i] = '*'; else states[i] = ' '; if (fstab->entries[i].type == PART_EXT2) { sprintf(buf, "/dev/%-5s %-33s", fstab->entries[i].device, fstab->entries[i].mntpoint); checks[i] = newtCheckbox(-1, top++, buf, states[i], NULL, &states[i]); newtFormAddComponent(checkList, checks[i]); } else { checks[i] = NULL; } } if (top > 4) { blank = newtForm(NULL, NULL, 0); newtFormSetWidth(blank, 2); newtFormSetHeight(blank, 4); newtFormSetBackground(blank, NEWT_COLORSET_CHECKBOX); checkgrid = newtGridHCloseStacked( NEWT_GRID_COMPONENT, checkList, NEWT_GRID_COMPONENT, blank, NEWT_GRID_COMPONENT, sb, NULL); } else { checkgrid = newtGridHCloseStacked(NEWT_GRID_COMPONENT, checkList, NULL); } checkbox = newtCheckbox(10, 12, _("Check for bad blocks during format"), badBlocks ? '*' : ' ', NULL, &doCheck); buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL); subgrid = newtCreateGrid(1, 3); subgrid = newtGridVStacked(NEWT_GRID_SUBGRID, checkgrid, NEWT_GRID_COMPONENT, checkbox, NULL); grid = newtGridBasicWindow(text, subgrid, buttons); newtGridAddComponentsToForm(grid, form, 1); newtGridWrappedWindow(grid, _("Partitions To Format")); newtGridFree(grid, 1); answer = newtRunForm(form); newtFormDestroy(form); newtPopWindow(); if (answer == cancel) return INST_CANCEL; for (i = 0; i < fstab->numEntries; i++) { fstab->entries[i].doFormat = (states[i] != ' '); } if (doCheck == ' ') badBlocks = 0; else badBlocks = 1; return 0; } int formatFilesystems(struct fstab * fstab) { int i; for (i = 0; i < fstab->numEntries; i++) { if (fstab->entries[i].doFormat) mkExt2Filesystem(fstab->entries[i].device); } return 0; } int doMount(char * dev, char * where, char * fs, int rdonly, int istty) { return doPwMount(dev, where, fs, rdonly, istty, NULL, NULL); } int doPwMount(char * dev, char * where, char * fs, int rdonly, int istty, char * acct, char * pw) { char * buf = NULL; int isnfs = 0; char * mount_opt = NULL; long int flag; char * chptr; if (!strcmp(fs, "nfs")) isnfs = 1; logMessage("mounting %s on %s as type %s", dev, where, fs); if (testing) { newtWinMessage("Test mount", "Ok", "I would mount /dev/%s on %s " "using a(n) %s filesystem.", dev, where, fs); } else if (!strcmp(fs, "smb")) { #if 0 /* disabled for now */ mkdirChain(where); if (!acct) acct = "guest"; if (!pw) pw = ""; buf = alloca(strlen(dev) + 1); strcpy(buf, dev); chptr = buf; while (*chptr && *chptr != ':') chptr++; if (!*chptr) { logMessage("bad smb mount point %s", where); return 0; } *chptr = '\0'; chptr++; #ifdef __i386__ logMessage("mounting smb filesystem from %s path %s on %s", buf, chptr, where); return smbmount(buf, chptr, acct, pw, "localhost", where); #else errorWindow("smbfs only works on Intel machines"); #endif #endif /* disabled */ } else { mkdirChain(where); if (!isnfs && *dev == '/') { buf = dev; } else if (!isnfs) { buf = alloca(200); strcpy(buf, "/tmp/"); strcat(buf, dev); if (devMakeInode(dev, buf)) return 1; } else { #ifndef DISABLE_NETWORK char * extra_opts = NULL; int flags = 0; buf = dev; logMessage("calling nfsmount(%s, %s, &flags, &extra_opts, &mount_opt)", buf, where); if (nfsmount(buf, where, &flags, &extra_opts, &mount_opt)) { logMessage("\tnfsmount returned non-zero"); if (istty) { fprintf(stderr, "nfs mount failed: %s\n", nfs_error()); } else { newtWinMessage(_("Error"), _("Ok"), _("nfs mount failed: %s"), nfs_error()); } return 1; } #endif } flag = MS_MGC_VAL; if (rdonly) flag |= MS_RDONLY; if (!strncmp(fs, "vfat", 4)) mount_opt="check=relaxed"; logMessage("calling mount(%s, %s, %s, %ld, %p)", buf, where, fs, flag, mount_opt); if (mount(buf, where, fs, flag, mount_opt)) { if (istty) { fprintf(stderr, "mount failed: %s\n", strerror(errno)); } else { newtWinMessage(_("Error"), _("Ok"), _("mount failed: %s"), strerror(errno)); } return 1; } if (!isnfs) devRemoveInode(buf); } return 0; } int mountFilesystems(struct fstab * fstab) { int i; char buf[1000]; /* don't bother mounting odd (non-ext2) filesystems - we don't need them for installs */ /* what about NFS? we should probably mount them to check mount integrity, but we don't know if networking is working well enough for us to do this */ chdir("/"); for (i = 0; i < fstab->numEntries; i++) { strcpy(buf, "/mnt"); strcat(buf, fstab->entries[i].mntpoint); if (fstab->entries[i].type == PART_EXT2 || fstab->entries[i].type == PART_NFS ) { if (fstab->entries[i].type == PART_EXT2 && !doMount(fstab->entries[i].device, buf, "ext2", 0, 0)) fstab->entries[i].isMounted = 1; else if (fstab->entries[i].type == PART_NFS && !doMount(fstab->entries[i].device, buf, "nfs", 0, 0)) fstab->entries[i].isMounted = 1; else { logMessage("unmounting all filesystems due to mount error"); umountFilesystems(fstab); return INST_ERROR; } } else if (fstab->entries[i].type != PART_SWAP) { logMessage("creating directory %s", buf); mkdirChain(buf); } } return 0; } int umountFilesystems(struct fstab * fstab) { char buf[1000]; int i; int olderrno; logMessage("unmounting all filesystems"); chdir("/"); if (testing) return 0; for (i = fstab->numEntries - 1; i >= 0; i--) { if (fstab->entries[i].isMounted) { strcpy(buf, "/mnt"); strcat(buf, fstab->entries[i].mntpoint); fstab->entries[i].isMounted = 0; if (umount(buf)) { olderrno = errno; logMessage("error unmounting %s: %s\n", buf, strerror(errno)); errno = olderrno; errorWindow("error unmounting filesystem: %s"); } } } return 0; } static int mkdirChain(char * origChain) { char * chain; char * chptr; chain = alloca(strlen(origChain) + 1); strcpy(chain, origChain); chptr = chain; if (testing) return 0; while ((chptr = strchr(chptr, '/'))) { *chptr = '\0'; if (mkdirIfNone(chain)) { *chptr = '/'; return INST_ERROR; } *chptr = '/'; chptr++; } if (mkdirIfNone(chain)) return INST_ERROR; return 0; } static int mkdirIfNone(char * directory) { int rc, mkerr; char * chptr; /* If the file exists it *better* be a directory -- I'm not going to actually check or anything */ if (!access(directory, X_OK)) return 0; /* if the path is '/' we get ENOFILE not found" from mkdir, rather then EEXIST which is weird */ for (chptr = directory; *chptr; chptr++) if (*chptr != '/') break; if (!*chptr) return 0; rc = mkdir(directory, 0755); mkerr = errno; logMessage("creating directory %s rc = %d", directory, rc); if (!rc || mkerr == EEXIST) return 0; logMessage(" error: %s", strerror(mkerr)); return INST_ERROR; } int writeFstab(struct fstab * fstab) { int i; FILE * f; int fd; char * fs = NULL; int freq = 0; int passno = 0; int bad; char buf[4096]; char * chptr, * cddev = NULL; char * devFormat = "/dev/%-18s %-23s %-7s %-15s %d %d\n"; char * nfsFormat = "%-23s %-23s %-7s %-15s %d %d\n"; char * procFormat = "%-23s %-23s %-7s %-15s %d %d\n"; char * options; char * format; logMessage("scanning /proc/mounts for iso9660 filesystems"); fd = open("/proc/mounts", O_RDONLY); if (fd < 0) { logMessage("\terror opening /proc/mounts -- skipping check: %s", strerror(errno)); } else { i = read(fd, buf, sizeof(buf) - 1); if (i < 0) { logMessage("\terror reading /proc/mounts -- skipping check: %s", strerror(errno)); } else { buf[i] = 0; if ((chptr = strstr(buf, "iso9660"))) { chptr--; /* skip the mount point */ while (*chptr == ' ') chptr--; while (*chptr != ' ') chptr--; while (*chptr == ' ') chptr--; chptr++; *chptr = '\0'; while (*chptr != '/') chptr--; cddev = strdup(chptr + 1); logMessage("found mounted cdrom drive %s", cddev); } } } #ifndef __sparc__ if (!cddev) { if (findAtapi(&cddev)) cddev = NULL; } #endif /* cd-rom rooted installs have the cdrom mounted on /dev/root which */ /* is not what we want to symlink to /dev/cdrom. */ if (!cddev || !strncmp(cddev, "root", 4)) { if (findSCSIcdrom(&cddev)) cddev = NULL; } if (testing) { if (cddev) free(cddev); return 0; } logMessage("touching /etc/mtab"); f = fopen("/mnt/etc/mtab", "w+"); if (!f) { errorWindow("error touching /mnt/etc/mtab"); } else { fclose(f); } logMessage("creating /etc/fstab"); f = fopen("/mnt/etc/fstab", "w"); if (!f) { if (cddev) free(cddev); errorWindow("error creating /mnt/etc/fstab"); return INST_ERROR; } for (i = 0; i < fstab->numEntries; i++) { if (!fstab->entries[i].mntpoint) continue; passno = 0; freq = 0; format = devFormat; options = "defaults"; bad = 0; switch (fstab->entries[i].type) { case PART_EXT2: freq = 1; fs = "ext2"; if (!strcmp(fstab->entries[i].mntpoint, "/")) passno = 1; else passno = 2; break; case PART_NFS: fs = "nfs"; options = "ro"; format = nfsFormat; break; case PART_SWAP: fs = "swap"; break; case PART_DOS: fs = "vfat"; break; case PART_HPFS: fs = "hpfs"; break; default: bad = 1; } if (!bad) fprintf(f, format, fstab->entries[i].device, fstab->entries[i].mntpoint, fs, options, freq, passno); } fprintf(f, devFormat, "fd0", "/mnt/floppy", "ext2", "noauto", 0, 0); if (cddev) { if (mkdir("/mnt/mnt/cdrom", 0755)) logMessage("failed to mkdir /mnt/mnt/cdrom: %s", strerror(errno)); if (symlink(cddev, "/mnt/dev/cdrom")) logMessage("failed to symlink /mnt/dev/cdrom: %s", strerror(errno)); fprintf(f, devFormat, "cdrom", "/mnt/cdrom", "iso9660", "noauto,ro", 0, 0); free(cddev); } fprintf(f, procFormat, "none", "/proc", "proc", "defaults", 0, 0); fprintf(f, procFormat, "none", "/dev/pts", "devpts", "mode=0622", 0, 0); fclose(f); return 0; } int addFstabEntry(struct fstab * fstab, struct fstabEntry entry) { int i; for (i = 0; i < fstab->numEntries; i++) if (!strcmp(entry.device, fstab->entries[i].device)) break; if (i == fstab->numEntries) { fstab->numEntries++; if (fstab->numEntries > 1) fstab->entries = realloc(fstab->entries, sizeof(entry) * fstab->numEntries); else fstab->entries = malloc(sizeof(entry)); } fstab->entries[i] = entry; return i; }