121c1c48aSSascha Wildner /* 221c1c48aSSascha Wildner * Copyright (c)2004 The DragonFly Project. All rights reserved. 321c1c48aSSascha Wildner * 421c1c48aSSascha Wildner * Redistribution and use in source and binary forms, with or without 521c1c48aSSascha Wildner * modification, are permitted provided that the following conditions 621c1c48aSSascha Wildner * are met: 721c1c48aSSascha Wildner * 821c1c48aSSascha Wildner * Redistributions of source code must retain the above copyright 921c1c48aSSascha Wildner * notice, this list of conditions and the following disclaimer. 1021c1c48aSSascha Wildner * 1121c1c48aSSascha Wildner * Redistributions in binary form must reproduce the above copyright 1221c1c48aSSascha Wildner * notice, this list of conditions and the following disclaimer in 1321c1c48aSSascha Wildner * the documentation and/or other materials provided with the 1421c1c48aSSascha Wildner * distribution. 1521c1c48aSSascha Wildner * 1621c1c48aSSascha Wildner * Neither the name of the DragonFly Project nor the names of its 1721c1c48aSSascha Wildner * contributors may be used to endorse or promote products derived 1821c1c48aSSascha Wildner * from this software without specific prior written permission. 1921c1c48aSSascha Wildner * 2021c1c48aSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2121c1c48aSSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2221c1c48aSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2321c1c48aSSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2421c1c48aSSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 2521c1c48aSSascha Wildner * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2621c1c48aSSascha Wildner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2721c1c48aSSascha Wildner * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2821c1c48aSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2921c1c48aSSascha Wildner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3021c1c48aSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 3121c1c48aSSascha Wildner * OF THE POSSIBILITY OF SUCH DAMAGE. 3221c1c48aSSascha Wildner */ 3321c1c48aSSascha Wildner 3421c1c48aSSascha Wildner /* 3521c1c48aSSascha Wildner * survey.c 3621c1c48aSSascha Wildner * Survey the storage capacity of the system. 3721c1c48aSSascha Wildner * $Id: survey.c,v 1.17 2005/02/06 21:05:18 cpressey Exp $ 3821c1c48aSSascha Wildner */ 3921c1c48aSSascha Wildner 4021c1c48aSSascha Wildner #include <sys/types.h> 4121c1c48aSSascha Wildner #include <sys/sysctl.h> 4221c1c48aSSascha Wildner 4321c1c48aSSascha Wildner #include <stdio.h> 4421c1c48aSSascha Wildner #include <string.h> 4521c1c48aSSascha Wildner 4621c1c48aSSascha Wildner #include "libaura/dict.h" 4721c1c48aSSascha Wildner 4821c1c48aSSascha Wildner #include "commands.h" 4921c1c48aSSascha Wildner #include "diskutil.h" 5021c1c48aSSascha Wildner #include "functions.h" 5121c1c48aSSascha Wildner 5221c1c48aSSascha Wildner static int fgets_chomp(char *, int, FILE *); 5321c1c48aSSascha Wildner static int parse_geometry_info(char *, int *, int *, int *); 5421c1c48aSSascha Wildner static int parse_slice_info(char *, int *, 5521c1c48aSSascha Wildner unsigned long *, unsigned long *, int *, int *); 5621c1c48aSSascha Wildner 5721c1c48aSSascha Wildner /* 5821c1c48aSSascha Wildner * Get a line from a file. Remove any trailing EOL's. 5921c1c48aSSascha Wildner * Return 1 if we did not hit EOF, 0 if we did. 6021c1c48aSSascha Wildner */ 6121c1c48aSSascha Wildner static int 6221c1c48aSSascha Wildner fgets_chomp(char *line, int size, FILE *f) 6321c1c48aSSascha Wildner { 6421c1c48aSSascha Wildner if (fgets(line, size, f) == NULL) 6521c1c48aSSascha Wildner return(0); 6621c1c48aSSascha Wildner while (strlen(line) > 0 && line[strlen(line) - 1] == '\n') 6721c1c48aSSascha Wildner line[strlen(line) - 1] = '\0'; 6821c1c48aSSascha Wildner return(1); 6921c1c48aSSascha Wildner } 7021c1c48aSSascha Wildner 7121c1c48aSSascha Wildner /* 7221c1c48aSSascha Wildner * Given a geometry line from fdisk's summary output, return the 7321c1c48aSSascha Wildner * number of cylinders, heads, and sectors. 7421c1c48aSSascha Wildner */ 7521c1c48aSSascha Wildner static int 7621c1c48aSSascha Wildner parse_geometry_info(char *line, int *cyl, int *head, int *sec) 7721c1c48aSSascha Wildner { 7821c1c48aSSascha Wildner char *word; 7921c1c48aSSascha Wildner 8021c1c48aSSascha Wildner /* 8121c1c48aSSascha Wildner * /dev/ad3: 2112 cyl 16 hd 63 sec 8221c1c48aSSascha Wildner */ 8321c1c48aSSascha Wildner if ((word = strtok(line, " \t")) == NULL) /* /dev/ad3: */ 8421c1c48aSSascha Wildner return(0); 8521c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 2112 */ 8621c1c48aSSascha Wildner return(0); 8721c1c48aSSascha Wildner *cyl = atoi(word); 8821c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* cyl */ 8921c1c48aSSascha Wildner return(0); 9021c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 16 */ 9121c1c48aSSascha Wildner return(0); 9221c1c48aSSascha Wildner *head = atoi(word); 9321c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* hd */ 9421c1c48aSSascha Wildner return(0); 9521c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 63 */ 9621c1c48aSSascha Wildner return(0); 9721c1c48aSSascha Wildner *sec = atoi(word); 9821c1c48aSSascha Wildner 9921c1c48aSSascha Wildner return(1); 10021c1c48aSSascha Wildner } 10121c1c48aSSascha Wildner 10221c1c48aSSascha Wildner /* 10321c1c48aSSascha Wildner * Given a slice description line from fdisk's summary output, return 10421c1c48aSSascha Wildner * the number of the slice, and its start, size, type, and flags. 10521c1c48aSSascha Wildner */ 10621c1c48aSSascha Wildner static int 10721c1c48aSSascha Wildner parse_slice_info(char *line, int *slice, 10821c1c48aSSascha Wildner unsigned long *start, unsigned long *size, 10921c1c48aSSascha Wildner int *type, int *flags) 11021c1c48aSSascha Wildner { 11121c1c48aSSascha Wildner char *word; 11221c1c48aSSascha Wildner 11321c1c48aSSascha Wildner /* 11421c1c48aSSascha Wildner * Part Start Size Type Flags 11521c1c48aSSascha Wildner * 1: 63 2128833 0xa5 0x80 11621c1c48aSSascha Wildner */ 11721c1c48aSSascha Wildner if ((word = strtok(line, " \t")) == NULL) /* 1: */ 11821c1c48aSSascha Wildner return(0); 11921c1c48aSSascha Wildner *slice = atoi(word); 12021c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 63 */ 12121c1c48aSSascha Wildner return(0); 12221c1c48aSSascha Wildner *start = strtoul(word, NULL, 10); 12321c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 2128833 */ 12421c1c48aSSascha Wildner return(0); 12521c1c48aSSascha Wildner *size = strtoul(word, NULL, 10); 12621c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 0xa5 */ 12721c1c48aSSascha Wildner return(0); 12821c1c48aSSascha Wildner if (!hex_to_int(word, type)) 12921c1c48aSSascha Wildner return(0); 13021c1c48aSSascha Wildner if ((word = strtok(NULL, " \t")) == NULL) /* 0x80 */ 13121c1c48aSSascha Wildner return(0); 13221c1c48aSSascha Wildner if (!hex_to_int(word, flags)) 13321c1c48aSSascha Wildner return(0); 13421c1c48aSSascha Wildner 13521c1c48aSSascha Wildner return(1); 13621c1c48aSSascha Wildner } 13721c1c48aSSascha Wildner 13821c1c48aSSascha Wildner /* 13921c1c48aSSascha Wildner * Survey storage capacity of this system. 14021c1c48aSSascha Wildner */ 14121c1c48aSSascha Wildner int 14221c1c48aSSascha Wildner survey_storage(struct i_fn_args *a) 14321c1c48aSSascha Wildner { 14421c1c48aSSascha Wildner unsigned long mem = 0; 14521c1c48aSSascha Wildner char disks[256], line[256]; 14621c1c48aSSascha Wildner char *disk, *disk_ptr; 14721c1c48aSSascha Wildner struct commands *cmds; 14821c1c48aSSascha Wildner struct command *cmd; 14921c1c48aSSascha Wildner FILE *f; 15021c1c48aSSascha Wildner char *filename; 15121c1c48aSSascha Wildner struct disk *d = NULL; 152*f59b7dfaSSascha Wildner int number = 0; 15321c1c48aSSascha Wildner int failure = 0; 15421c1c48aSSascha Wildner size_t len; 15521c1c48aSSascha Wildner struct aura_dict *di; 15621c1c48aSSascha Wildner void *rk; 15721c1c48aSSascha Wildner size_t rk_len; 15821c1c48aSSascha Wildner 15921c1c48aSSascha Wildner disks_free(a->s); 16021c1c48aSSascha Wildner 16121c1c48aSSascha Wildner len = sizeof(mem); 16221c1c48aSSascha Wildner if (sysctlbyname("hw.physmem", &mem, &len, NULL, 0) < 0) { 16321c1c48aSSascha Wildner failure |= 1; 16421c1c48aSSascha Wildner } else { 16521c1c48aSSascha Wildner storage_set_memsize(a->s, next_power_of_two(mem >> 20)); 16621c1c48aSSascha Wildner } 16721c1c48aSSascha Wildner len = 256; 16821c1c48aSSascha Wildner if (sysctlbyname("kern.disks", disks, &len, NULL, 0) < 0) { 16921c1c48aSSascha Wildner failure |= 1; 17021c1c48aSSascha Wildner } 17121c1c48aSSascha Wildner disk_ptr = disks; 17221c1c48aSSascha Wildner 17321c1c48aSSascha Wildner di = aura_dict_new(1, AURA_DICT_SORTED_LIST); 17421c1c48aSSascha Wildner while (!failure && (disk = strsep(&disk_ptr, " ")) != NULL) { 17521c1c48aSSascha Wildner if (disk[0] == '\0') 17621c1c48aSSascha Wildner continue; 17721c1c48aSSascha Wildner 17821c1c48aSSascha Wildner /* 17921c1c48aSSascha Wildner * If the disk is a memory disk, floppy or CD-ROM, skip it. 18021c1c48aSSascha Wildner */ 18121c1c48aSSascha Wildner if (strncmp(disk, "md", 2) == 0 || 18221c1c48aSSascha Wildner strncmp(disk, "cd", 2) == 0 || 18321c1c48aSSascha Wildner strncmp(disk, "acd", 3) == 0 || 18421c1c48aSSascha Wildner strncmp(disk, "fd", 2) == 0) 18521c1c48aSSascha Wildner continue; 18621c1c48aSSascha Wildner 18721c1c48aSSascha Wildner aura_dict_store(di, disk, strlen(disk) + 1, "", 1); 18821c1c48aSSascha Wildner } 18921c1c48aSSascha Wildner 19021c1c48aSSascha Wildner cmds = commands_new(); 19121c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s -n '' >%ssurvey.txt", 19221c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 19321c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 19421c1c48aSSascha Wildner 19521c1c48aSSascha Wildner aura_dict_rewind(di); 19621c1c48aSSascha Wildner while (!aura_dict_eof(di)) { 19721c1c48aSSascha Wildner aura_dict_get_current_key(di, &rk, &rk_len), 19821c1c48aSSascha Wildner 19921c1c48aSSascha Wildner disk = (char *)rk; 20021c1c48aSSascha Wildner 20121c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '@DISK' >>%ssurvey.txt", 20221c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 20321c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 20421c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '%s' >>%ssurvey.txt", 20521c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), disk, a->tmp); 20621c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 20721c1c48aSSascha Wildner 20821c1c48aSSascha Wildner /* 20921c1c48aSSascha Wildner * Look for descriptions of this disk. 21021c1c48aSSascha Wildner */ 21121c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '@DESC' >>%ssurvey.txt", 21221c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 21321c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 21421c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s -w '^%s: [0-9]*MB' %s%s >>%ssurvey.txt || %s%s '%s' >>%ssurvey.txt", 21521c1c48aSSascha Wildner a->os_root, cmd_name(a, "GREP"), 21621c1c48aSSascha Wildner disk, 21721c1c48aSSascha Wildner a->os_root, cmd_name(a, "DMESG_BOOT"), 21821c1c48aSSascha Wildner a->tmp, 21921c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), 22021c1c48aSSascha Wildner disk, 22121c1c48aSSascha Wildner a->tmp); 22221c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '@END' >>%ssurvey.txt", 22321c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 22421c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 22521c1c48aSSascha Wildner 22621c1c48aSSascha Wildner /* 227*f59b7dfaSSascha Wildner * Look for the disk's serial number. 228*f59b7dfaSSascha Wildner */ 229*f59b7dfaSSascha Wildner cmd = command_add(cmds, "%s%s '@SERNO' >>%ssurvey.txt", 230*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 231*f59b7dfaSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 232*f59b7dfaSSascha Wildner cmd = command_add(cmds, "if %s%s -d /dev/serno; then %s%s -l /dev/serno | %s%s \"`%s%s -l /dev/%s | %s%s '{print $5, $6;}'`\" | %s%s '{print $10;}' >>%ssurvey.txt; fi", 233*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "TEST"), 234*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "LS"), 235*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "GREP"), 236*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "LS"), 237*f59b7dfaSSascha Wildner disk, 238*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "AWK"), 239*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "AWK"), 240*f59b7dfaSSascha Wildner a->tmp); 241*f59b7dfaSSascha Wildner cmd = command_add(cmds, "%s%s '@END' >>%ssurvey.txt", 242*f59b7dfaSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 243*f59b7dfaSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 244*f59b7dfaSSascha Wildner 245*f59b7dfaSSascha Wildner /* 24621c1c48aSSascha Wildner * Probe the disk with fdisk. 24721c1c48aSSascha Wildner */ 24821c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '@SLICES' >>%ssurvey.txt", 24921c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 25021c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 25121c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s -s %s 2>/dev/null >>%ssurvey.txt || %s%s '' >>%ssurvey.txt", 25221c1c48aSSascha Wildner a->os_root, cmd_name(a, "FDISK"), 25321c1c48aSSascha Wildner disk, 25421c1c48aSSascha Wildner a->tmp, 25521c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), 25621c1c48aSSascha Wildner a->tmp); 25721c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '@END' >>%ssurvey.txt", 25821c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 25921c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 26021c1c48aSSascha Wildner 26121c1c48aSSascha Wildner aura_dict_next(di); 26221c1c48aSSascha Wildner } 26321c1c48aSSascha Wildner 26421c1c48aSSascha Wildner cmd = command_add(cmds, "%s%s '.' >>%ssurvey.txt", 26521c1c48aSSascha Wildner a->os_root, cmd_name(a, "ECHO"), a->tmp); 26621c1c48aSSascha Wildner command_set_log_mode(cmd, COMMAND_LOG_SILENT); 26721c1c48aSSascha Wildner 26821c1c48aSSascha Wildner if (!commands_execute(a, cmds)) 26921c1c48aSSascha Wildner failure |= 1; 27021c1c48aSSascha Wildner commands_free(cmds); 27121c1c48aSSascha Wildner temp_file_add(a, "survey.txt"); 27221c1c48aSSascha Wildner 27321c1c48aSSascha Wildner aura_dict_free(di); 27421c1c48aSSascha Wildner 27521c1c48aSSascha Wildner /* 27621c1c48aSSascha Wildner * Now read in and parse the file that those commands just created. 27721c1c48aSSascha Wildner */ 27821c1c48aSSascha Wildner asprintf(&filename, "%ssurvey.txt", a->tmp); 27921c1c48aSSascha Wildner if ((f = fopen(filename, "r")) == NULL) 28021c1c48aSSascha Wildner failure |= 1; 28121c1c48aSSascha Wildner free(filename); 28221c1c48aSSascha Wildner 28321c1c48aSSascha Wildner while (!failure && fgets_chomp(line, 255, f)) { 28421c1c48aSSascha Wildner if (strcmp(line, "@DISK") == 0) { 28521c1c48aSSascha Wildner if (fgets_chomp(line, 255, f)) { 28621c1c48aSSascha Wildner d = disk_new(a->s, line); 287*f59b7dfaSSascha Wildner disk_set_number(d, number++); 28821c1c48aSSascha Wildner } 28921c1c48aSSascha Wildner } else if (strcmp(line, "@DESC") == 0) { 29021c1c48aSSascha Wildner while (d != NULL && strcmp(line, "@END") != 0 && fgets_chomp(line, 255, f)) { 29121c1c48aSSascha Wildner disk_set_desc(d, line); 29221c1c48aSSascha Wildner } 293*f59b7dfaSSascha Wildner } else if (strcmp(line, "@SERNO") == 0) { 294*f59b7dfaSSascha Wildner fgets_chomp(line, 255, f); 295*f59b7dfaSSascha Wildner if (strcmp(line, "@END") != 0) 296*f59b7dfaSSascha Wildner disk_set_serno(d, line); 29721c1c48aSSascha Wildner } else if (strcmp(line, "@SLICES") == 0) { 29821c1c48aSSascha Wildner int cyl, hd, sec; 29921c1c48aSSascha Wildner int number, type, flags; 30021c1c48aSSascha Wildner unsigned long start, size; 30121c1c48aSSascha Wildner 30221c1c48aSSascha Wildner /* 30321c1c48aSSascha Wildner * /dev/ad3: 2112 cyl 16 hd 63 sec 30421c1c48aSSascha Wildner * Part Start Size Type Flags 30521c1c48aSSascha Wildner * 1: 63 2128833 0xa5 0x80 30621c1c48aSSascha Wildner */ 30721c1c48aSSascha Wildner while (d != NULL && strcmp(line, "@END") != 0 && fgets_chomp(line, 255, f)) { 30821c1c48aSSascha Wildner if (strncmp(line, "/dev/", 5) == 0) { 30921c1c48aSSascha Wildner parse_geometry_info(line, &cyl, &hd, &sec); 31021c1c48aSSascha Wildner disk_set_geometry(d, cyl, hd, sec); 31121c1c48aSSascha Wildner } else if (strncmp(line, "Part", 4) == 0) { 31221c1c48aSSascha Wildner /* ignore it */ 31321c1c48aSSascha Wildner } else { 31421c1c48aSSascha Wildner if (parse_slice_info(line, &number, &start, &size, 31521c1c48aSSascha Wildner &type, &flags)) { 31621c1c48aSSascha Wildner /* 31721c1c48aSSascha Wildner fprintfo(log, "| Found slice #%d, sysid %d, " 31821c1c48aSSascha Wildner "start %ld, size %ld\n", number, type, start, size); 31921c1c48aSSascha Wildner */ 32021c1c48aSSascha Wildner slice_new(d, number, type, flags, start, size); 32121c1c48aSSascha Wildner } 32221c1c48aSSascha Wildner } 32321c1c48aSSascha Wildner } 32421c1c48aSSascha Wildner } 32521c1c48aSSascha Wildner } 32621c1c48aSSascha Wildner 32721c1c48aSSascha Wildner if (f != NULL) 32821c1c48aSSascha Wildner fclose(f); 32921c1c48aSSascha Wildner 33021c1c48aSSascha Wildner /* 33121c1c48aSSascha Wildner * Fix up any disk descriptions that didn't make it. 33221c1c48aSSascha Wildner */ 33321c1c48aSSascha Wildner for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d)) { 33421c1c48aSSascha Wildner if (disk_get_desc(d) == NULL) 33521c1c48aSSascha Wildner disk_set_desc(d, disk_get_device_name(d)); 33621c1c48aSSascha Wildner } 33721c1c48aSSascha Wildner 33821c1c48aSSascha Wildner return(!failure); 33921c1c48aSSascha Wildner } 340