18097Sjkh/* 28097Sjkh * Miscellaneous support routines.. 38097Sjkh * 450479Speter * $FreeBSD$ 58097Sjkh * 68097Sjkh * Copyright (c) 1995 78097Sjkh * Jordan Hubbard. All rights reserved. 88097Sjkh * 98097Sjkh * Redistribution and use in source and binary forms, with or without 108097Sjkh * modification, are permitted provided that the following conditions 118097Sjkh * are met: 128097Sjkh * 1. Redistributions of source code must retain the above copyright 138881Srgrimes * notice, this list of conditions and the following disclaimer, 148881Srgrimes * verbatim and that no modifications are made prior to this 158097Sjkh * point in the file. 168097Sjkh * 2. Redistributions in binary form must reproduce the above copyright 178097Sjkh * notice, this list of conditions and the following disclaimer in the 188097Sjkh * documentation and/or other materials provided with the distribution. 198097Sjkh * 208097Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 218097Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228097Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238097Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 248097Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 258097Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 268097Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 278097Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 288097Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 298097Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 308097Sjkh * SUCH DAMAGE. 318097Sjkh * 328097Sjkh */ 338097Sjkh 348097Sjkh#include "sysinstall.h" 358097Sjkh#include <ctype.h> 368709Sjkh#include <unistd.h> 378556Sjkh#include <sys/stat.h> 388556Sjkh#include <sys/errno.h> 398556Sjkh#include <sys/file.h> 408556Sjkh#include <sys/types.h> 4112661Speter#include <dirent.h> 428556Sjkh#include <sys/wait.h> 438556Sjkh#include <sys/param.h> 448556Sjkh#include <sys/mount.h> 4524597Sjkh#include <ufs/ufs/ufsmount.h> 468556Sjkh#include <sys/reboot.h> 478556Sjkh#include <sys/disklabel.h> 48107525Smarcel#include <fs/msdosfs/msdosfsmount.h> 49160380Ssimon#include <sys/sysctl.h> 508097Sjkh 518097Sjkh/* Quick check to see if a file is readable */ 528097SjkhBoolean 538097Sjkhfile_readable(char *fname) 548097Sjkh{ 558097Sjkh if (!access(fname, F_OK)) 568097Sjkh return TRUE; 578097Sjkh return FALSE; 588097Sjkh} 598097Sjkh 608097Sjkh/* Quick check to see if a file is executable */ 618097SjkhBoolean 628097Sjkhfile_executable(char *fname) 638097Sjkh{ 648097Sjkh if (!access(fname, X_OK)) 658097Sjkh return TRUE; 668097Sjkh return FALSE; 678097Sjkh} 688097Sjkh 698097Sjkh/* Concatenate two strings into static storage */ 708097Sjkhchar * 718097Sjkhstring_concat(char *one, char *two) 728097Sjkh{ 738097Sjkh static char tmp[FILENAME_MAX]; 748097Sjkh 7512661Speter /* Yes, we're deliberately cavalier about not checking for overflow */ 768097Sjkh strcpy(tmp, one); 778097Sjkh strcat(tmp, two); 788097Sjkh return tmp; 798097Sjkh} 808097Sjkh 8120247Sjkh/* sane strncpy() function */ 8220247Sjkhchar * 8320247Sjkhsstrncpy(char *dst, const char *src, int size) 8420247Sjkh{ 8520569Sjkh dst[size] = '\0'; 8620377Sjkh return strncpy(dst, src, size); 8720247Sjkh} 8820247Sjkh 8912661Speter/* Concatenate three strings into static storage */ 9012661Speterchar * 9112661Speterstring_concat3(char *one, char *two, char *three) 9212661Speter{ 9312661Speter static char tmp[FILENAME_MAX]; 9412661Speter 9512661Speter /* Yes, we're deliberately cavalier about not checking for overflow */ 9612661Speter strcpy(tmp, one); 9712661Speter strcat(tmp, two); 9812661Speter strcat(tmp, three); 9912661Speter return tmp; 10012661Speter} 10112661Speter 1028097Sjkh/* Clip the whitespace off the end of a string */ 1038097Sjkhchar * 1048097Sjkhstring_prune(char *str) 1058097Sjkh{ 1068097Sjkh int len = str ? strlen(str) : 0; 1078097Sjkh 1088097Sjkh while (len && isspace(str[len - 1])) 1098097Sjkh str[--len] = '\0'; 1108097Sjkh return str; 1118097Sjkh} 1128097Sjkh 1138097Sjkh/* run the whitespace off the front of a string */ 1148097Sjkhchar * 1158097Sjkhstring_skipwhite(char *str) 1168097Sjkh{ 1178097Sjkh while (*str && isspace(*str)) 1188097Sjkh ++str; 1198097Sjkh return str; 1208097Sjkh} 1218097Sjkh 12212661Speter/* copy optionally and allow second arg to be null */ 12312661Speterchar * 12412661Speterstring_copy(char *s1, char *s2) 12512661Speter{ 12612661Speter if (!s1) 12712661Speter return NULL; 12812661Speter if (!s2) 12912661Speter s1[0] = '\0'; 13012661Speter else 13112661Speter strcpy(s1, s2); 13212661Speter return s1; 13312661Speter} 13412661Speter 13516462Sjkh/* convert an integer to a string, using a static buffer */ 13616462Sjkhchar * 13716462Sjkhitoa(int value) 13816462Sjkh{ 13916462Sjkh static char buf[13]; 14016462Sjkh 14116462Sjkh snprintf(buf, 12, "%d", value); 14216462Sjkh return buf; 14316462Sjkh} 14416462Sjkh 14512661SpeterBoolean 14614670Sjkhdirectory_exists(const char *dirname) 14712661Speter{ 14812661Speter DIR *tptr; 14912661Speter 15012661Speter if (!dirname) 15112661Speter return FALSE; 15212661Speter if (!strlen(dirname)) 15312661Speter return FALSE; 15412661Speter 15512661Speter tptr = opendir(dirname); 15612661Speter if (!tptr) 15712661Speter return (FALSE); 15812661Speter 15912661Speter closedir(tptr); 16012661Speter return (TRUE); 16112661Speter} 16212661Speter 16312661Speterchar * 16412661SpeterpathBaseName(const char *path) 16512661Speter{ 16612661Speter char *pt; 16712661Speter char *ret = (char *)path; 16812661Speter 16912661Speter pt = strrchr(path,(int)'/'); 17012661Speter 17112661Speter if (pt != 0) /* if there is a slash */ 17212661Speter { 17312661Speter ret = ++pt; /* start the file after it */ 17412661Speter } 17512661Speter 17612661Speter return(ret); 17712661Speter} 17812661Speter 1798097Sjkh/* A free guaranteed to take NULL ptrs */ 1808097Sjkhvoid 1818097Sjkhsafe_free(void *ptr) 1828097Sjkh{ 1838097Sjkh if (ptr) 1848097Sjkh free(ptr); 1858097Sjkh} 1868097Sjkh 1878208Sjkh/* A malloc that checks errors */ 1888208Sjkhvoid * 1898208Sjkhsafe_malloc(size_t size) 1908208Sjkh{ 1918208Sjkh void *ptr; 1928208Sjkh 1938363Sjkh if (size <= 0) 19483842Smurray msgFatal("Invalid malloc size of %ld!", (long)size); 1958208Sjkh ptr = malloc(size); 1968208Sjkh if (!ptr) 1978208Sjkh msgFatal("Out of memory!"); 19812661Speter bzero(ptr, size); 1998208Sjkh return ptr; 2008208Sjkh} 2018208Sjkh 2028363Sjkh/* A realloc that checks errors */ 2038363Sjkhvoid * 2048363Sjkhsafe_realloc(void *orig, size_t size) 2058363Sjkh{ 2068363Sjkh void *ptr; 2078363Sjkh 2088363Sjkh if (size <= 0) 20983842Smurray msgFatal("Invalid realloc size of %ld!", (long)size); 210108804Sobrien ptr = reallocf(orig, size); 2118363Sjkh if (!ptr) 2128363Sjkh msgFatal("Out of memory!"); 2138363Sjkh return ptr; 2148363Sjkh} 2158363Sjkh 21617034Sjkh/* Create a path biased from the VAR_INSTALL_ROOT variable (if not /) */ 21717034Sjkhchar * 21817034Sjkhroot_bias(char *path) 21917034Sjkh{ 22017034Sjkh static char tmp[FILENAME_MAX]; 22117034Sjkh char *cp = variable_get(VAR_INSTALL_ROOT); 22217034Sjkh 22317034Sjkh if (!strcmp(cp, "/")) 22417034Sjkh return path; 22517034Sjkh strcpy(tmp, variable_get(VAR_INSTALL_ROOT)); 22617034Sjkh strcat(tmp, path); 22717034Sjkh return tmp; 22817034Sjkh} 22917034Sjkh 2308097Sjkh/* 23126598Sjkh * These next routines are kind of specialized just for building item lists 2328097Sjkh * for dialog_menu(). 2338097Sjkh */ 2348174Sjkh 23515242Sjkh/* Add an item to an item list */ 23615242SjkhdialogMenuItem * 23715242Sjkhitem_add(dialogMenuItem *list, char *prompt, char *title, 23815242Sjkh int (*checked)(dialogMenuItem *self), 23915242Sjkh int (*fire)(dialogMenuItem *self), 24015242Sjkh void (*selected)(dialogMenuItem *self, int is_selected), 241209359Srandi void *data, void *aux, int *curr, int *max) 2428097Sjkh{ 24315242Sjkh dialogMenuItem *d; 2448097Sjkh 2458097Sjkh if (*curr == *max) { 2468097Sjkh *max += 20; 247108804Sobrien list = (dialogMenuItem *)safe_realloc(list, sizeof(dialogMenuItem) * *max); 2488097Sjkh } 24915242Sjkh d = &list[(*curr)++]; 25015419Sjkh bzero(d, sizeof(*d)); 25115242Sjkh d->prompt = prompt ? strdup(prompt) : NULL; 25215242Sjkh d->title = title ? strdup(title) : NULL; 25315242Sjkh d->checked = checked; 25415242Sjkh d->fire = fire; 25515242Sjkh d->selected = selected; 25615242Sjkh d->data = data; 25783842Smurray d->aux = (long)aux; 2588097Sjkh return list; 2598097Sjkh} 2608097Sjkh 2618097Sjkh/* Toss the items out */ 2628097Sjkhvoid 26315242Sjkhitems_free(dialogMenuItem *list, int *curr, int *max) 2648097Sjkh{ 26515242Sjkh int i; 26615242Sjkh 26715242Sjkh for (i = 0; list[i].prompt; i++) { 26815242Sjkh safe_free(list[i].prompt); 26915242Sjkh safe_free(list[i].title); 27015242Sjkh } 2718097Sjkh safe_free(list); 2728097Sjkh *curr = *max = 0; 2738097Sjkh} 2748097Sjkh 2758556Sjkhint 27617005SjkhMkdir(char *ipath) 2778556Sjkh{ 2788556Sjkh struct stat sb; 27917005Sjkh int final; 2808709Sjkh char *p, *path; 2818556Sjkh 28216718Sjkh if (file_readable(ipath) || Fake) 28315242Sjkh return DITEM_SUCCESS; 2848709Sjkh 28517005Sjkh path = strcpy(alloca(strlen(ipath) + 1), ipath); 2868837Sjkh if (isDebug()) 2878837Sjkh msgDebug("mkdir(%s)\n", path); 2888556Sjkh p = path; 2898556Sjkh if (p[0] == '/') /* Skip leading '/'. */ 2908556Sjkh ++p; 29117005Sjkh for (final = FALSE; !final; ++p) { 2928556Sjkh if (p[0] == '\0' || (p[0] == '/' && p[1] == '\0')) 29317005Sjkh final = TRUE; 2948556Sjkh else if (p[0] != '/') 2958556Sjkh continue; 2968556Sjkh *p = '\0'; 2978556Sjkh if (stat(path, &sb)) { 2988556Sjkh if (errno != ENOENT) { 2998556Sjkh msgConfirm("Couldn't stat directory %s: %s", path, strerror(errno)); 30015242Sjkh return DITEM_FAILURE; 3018556Sjkh } 3028837Sjkh if (isDebug()) 3038837Sjkh msgDebug("mkdir(%s..)\n", path); 3048556Sjkh if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { 3058556Sjkh msgConfirm("Couldn't create directory %s: %s", path,strerror(errno)); 30615242Sjkh return DITEM_FAILURE; 3078556Sjkh } 3088556Sjkh } 3098556Sjkh *p = '/'; 3108556Sjkh } 31115242Sjkh return DITEM_SUCCESS; 3128556Sjkh} 3138556Sjkh 3148556Sjkhint 315107525SmarcelMkdir_command(char *key, void *dir) 316107525Smarcel{ 317107525Smarcel return (Mkdir((char*)dir)); 318107525Smarcel} 319107525Smarcel 320107525Smarcelint 3218606SjkhMount(char *mountp, void *dev) 3228556Sjkh{ 3238556Sjkh struct ufs_args ufsargs; 3248606Sjkh char device[80]; 3258556Sjkh char mountpoint[FILENAME_MAX]; 3268556Sjkh 32716718Sjkh if (Fake) 32816718Sjkh return DITEM_SUCCESS; 32916718Sjkh 3308607Sjkh if (*((char *)dev) != '/') { 33122931Sjkh sprintf(device, "%s/dev/%s", RunningAsInit ? "/mnt" : "", (char *)dev); 33222868Sjkh sprintf(mountpoint, "%s%s", RunningAsInit ? "/mnt" : "", mountp); 3338606Sjkh } 3348606Sjkh else { 3358606Sjkh strcpy(device, dev); 3368606Sjkh strcpy(mountpoint, mountp); 3378606Sjkh } 3388556Sjkh memset(&ufsargs,0,sizeof ufsargs); 3398556Sjkh 34017005Sjkh if (Mkdir(mountpoint)) { 3418709Sjkh msgConfirm("Unable to make directory mountpoint for %s!", mountpoint); 34215242Sjkh return DITEM_FAILURE; 3438709Sjkh } 3448837Sjkh if (isDebug()) 3458881Srgrimes msgDebug("mount %s %s\n", device, mountpoint); 34613428Sphk 3478556Sjkh ufsargs.fspec = device; 34834679Sjkh if (mount("ufs", mountpoint, RunningAsInit ? MNT_ASYNC | MNT_NOATIME : 0, 34930956Sobrien (caddr_t)&ufsargs) == -1) { 35012661Speter msgConfirm("Error mounting %s on %s : %s", device, mountpoint, strerror(errno)); 35115242Sjkh return DITEM_FAILURE; 3528556Sjkh } 35315242Sjkh return DITEM_SUCCESS; 3548556Sjkh} 35515242Sjkh 356107525Smarcelint 357107525SmarcelMount_msdosfs(char *mountp, void *dev) 358107525Smarcel{ 359107525Smarcel struct msdosfs_args mount_args; 360107525Smarcel char device[80]; 361107525Smarcel char mountpoint[FILENAME_MAX]; 362107525Smarcel 363107525Smarcel if (Fake) 364107525Smarcel return DITEM_SUCCESS; 365107525Smarcel 366107525Smarcel if (*((char *)dev) != '/') { 367107525Smarcel sprintf(device, "%s/dev/%s", RunningAsInit ? "/mnt" : "", (char *)dev); 368107525Smarcel sprintf(mountpoint, "%s%s", RunningAsInit ? "/mnt" : "", mountp); 369107525Smarcel } 370107525Smarcel else { 371107525Smarcel strcpy(device, dev); 372107525Smarcel strcpy(mountpoint, mountp); 373107525Smarcel } 374107525Smarcel 375107525Smarcel if (Mkdir(mountpoint)) { 376107525Smarcel msgConfirm("Unable to make directory mountpoint for %s!", mountpoint); 377107525Smarcel return DITEM_FAILURE; 378107525Smarcel } 379107525Smarcel if (isDebug()) 380107525Smarcel msgDebug("mount %s %s\n", device, mountpoint); 381107525Smarcel 382107525Smarcel memset(&mount_args, 0, sizeof(mount_args)); 383107525Smarcel mount_args.fspec = device; 384107525Smarcel mount_args.magic = MSDOSFS_ARGSMAGIC; 385107525Smarcel mount_args.mask = S_IRWXU | S_IRWXG | S_IRWXO; 386107525Smarcel if (mount("msdosfs", mountpoint, RunningAsInit ? MNT_ASYNC|MNT_NOATIME : 0, 387107525Smarcel (caddr_t)&mount_args) == -1) { 388107525Smarcel msgConfirm("Error mounting %s on %s : %s", device, mountpoint, strerror(errno)); 389107525Smarcel return DITEM_FAILURE; 390107525Smarcel } 391107525Smarcel return DITEM_SUCCESS; 392107525Smarcel} 393107525Smarcel 39415242SjkhWINDOW * 39521243SjkhopenLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height) 39621243Sjkh{ 39722099Sjkh WINDOW *win; 39822099Sjkh static char help[FILENAME_MAX]; 39922099Sjkh 40021243Sjkh /* We need a curses window */ 40121243Sjkh win = newwin(LINES, COLS, 0, 0); 40221243Sjkh if (win) { 40321243Sjkh /* Say where our help comes from */ 40421243Sjkh if (helpfile) { 40522099Sjkh use_helpline("Press F1 for more information on this screen."); 40622099Sjkh use_helpfile(systemHelpFile(helpfile, help)); 40721243Sjkh } 40821243Sjkh /* Setup a nice screen for us to splat stuff onto */ 40921243Sjkh draw_box(win, y, x, height, width, dialog_attr, border_attr); 41021243Sjkh wattrset(win, dialog_attr); 41123588Sjkh mvwaddstr(win, y, x + (COLS - strlen(title)) / 2, title); 41221243Sjkh } 41321243Sjkh return win; 41421243Sjkh} 41521243Sjkh 41621243SjkhComposeObj * 41721243SjkhinitLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max) 41821243Sjkh{ 41921243Sjkh ComposeObj *obj = NULL, *first; 42021243Sjkh int n; 42121243Sjkh 42221243Sjkh /* Loop over the layout list, create the objects, and add them 42321243Sjkh onto the chain of objects that dialog uses for traversal*/ 42421243Sjkh 42521243Sjkh n = 0; 42621243Sjkh while (layout[n].help != NULL) { 42722099Sjkh int t = TYPE_OF_OBJ(layout[n].type); 42822099Sjkh 42922099Sjkh switch (t) { 43021243Sjkh case STRINGOBJ: 43121243Sjkh layout[n].obj = NewStringObj(win, layout[n].prompt, layout[n].var, 43221243Sjkh layout[n].y + y, layout[n].x + x, layout[n].len, layout[n].maxlen); 43322099Sjkh ((StringObj *)layout[n].obj)->attr_mask = ATTR_OF_OBJ(layout[n].type); 43421243Sjkh break; 43521243Sjkh 43621243Sjkh case BUTTONOBJ: 43721243Sjkh layout[n].obj = NewButtonObj(win, layout[n].prompt, layout[n].var, layout[n].y + y, layout[n].x + x); 43821243Sjkh break; 43921243Sjkh 44021243Sjkh default: 44121243Sjkh msgFatal("Don't support this object yet!"); 44221243Sjkh } 44322099Sjkh AddObj(&obj, t, (void *) layout[n].obj); 44421243Sjkh n++; 44521243Sjkh } 44621243Sjkh *max = n - 1; 44721243Sjkh /* Find the first object in the list */ 44821243Sjkh for (first = obj; first->prev; first = first->prev); 44921243Sjkh return first; 45021243Sjkh} 45121243Sjkh 45221243Sjkhint 45321243SjkhlayoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, int *n, int max, int *cbutton, int *cancel) 45421243Sjkh{ 45521243Sjkh char help_line[80]; 45621243Sjkh int ret, i, len = strlen(layout[*n].help); 45721243Sjkh 45821243Sjkh /* Display the help line at the bottom of the screen */ 45921243Sjkh for (i = 0; i < 79; i++) 46021243Sjkh help_line[i] = (i < len) ? layout[*n].help[i] : ' '; 46121243Sjkh help_line[i] = '\0'; 46221243Sjkh use_helpline(help_line); 46321243Sjkh display_helpline(win, LINES - 1, COLS - 1); 46422099Sjkh wrefresh(win); 46521243Sjkh 46621243Sjkh /* Ask for libdialog to do its stuff */ 46721243Sjkh ret = PollObj(obj); 46821243Sjkh /* Handle special case stuff that libdialog misses. Sigh */ 46921243Sjkh switch (ret) { 47021243Sjkh case SEL_ESC: /* Bail out */ 47121243Sjkh *cancel = TRUE; 47221243Sjkh return FALSE; 47321243Sjkh 47421243Sjkh /* This doesn't work for list dialogs. Oh well. Perhaps 47521243Sjkh should special case the move from the OK button ``up'' 47621243Sjkh to make it go to the interface list, but then it gets 47721243Sjkh awkward for the user to go back and correct screw up's 47821243Sjkh in the per-interface section */ 47921243Sjkh case KEY_DOWN: 48021243Sjkh case SEL_CR: 48121243Sjkh case SEL_TAB: 48221243Sjkh if (*n < max) 48321243Sjkh ++*n; 48421243Sjkh else 48521243Sjkh *n = 0; 48621243Sjkh break; 48721243Sjkh 48821243Sjkh /* The user has pressed enter over a button object */ 48921243Sjkh case SEL_BUTTON: 49021243Sjkh if (cbutton && *cbutton) 49121243Sjkh *cancel = TRUE; 49221243Sjkh else 49321243Sjkh *cancel = FALSE; 49421243Sjkh return FALSE; 49521243Sjkh 49621243Sjkh case KEY_UP: 49721243Sjkh case SEL_BACKTAB: 49821243Sjkh if (*n) 49921243Sjkh --*n; 50021243Sjkh else 50121243Sjkh *n = max; 50221243Sjkh break; 50321243Sjkh 50421243Sjkh case KEY_F(1): 50521243Sjkh display_helpfile(); 50621243Sjkh 50721243Sjkh /* They tried some key combination we don't support - tootle them forcefully! */ 50821243Sjkh default: 50921243Sjkh beep(); 51021243Sjkh } 51121243Sjkh return TRUE; 51221243Sjkh} 51321243Sjkh 51421243SjkhWINDOW * 51515242Sjkhsavescr(void) 51615242Sjkh{ 51715242Sjkh WINDOW *w; 51815242Sjkh 51915242Sjkh w = dupwin(newscr); 52015242Sjkh return w; 52115242Sjkh} 52215242Sjkh 52315242Sjkhvoid 52415242Sjkhrestorescr(WINDOW *w) 52515242Sjkh{ 52615242Sjkh touchwin(w); 52715242Sjkh wrefresh(w); 52815242Sjkh delwin(w); 52915242Sjkh} 53021243Sjkh 531160380Ssimon/* 532160380Ssimon * Get a sysctl variable as a string or "<unknown>" if sysctl fails. 533160380Ssimon * Caller must free returned string. 534160380Ssimon */ 535160380Ssimonchar * 536160380Ssimongetsysctlbyname(const char *sysctlname) 537160380Ssimon{ 538160380Ssimon char *buf; 539160380Ssimon size_t sz, buf_sz = 0; 540160380Ssimon const char unk_str[] = "<unknown>"; 541160380Ssimon 542160380Ssimon sysctlbyname(sysctlname, NULL, &buf_sz, NULL, 0); 543160380Ssimon buf_sz = MAX(sizeof(unk_str), buf_sz) + 1; 544160380Ssimon sz = buf_sz - 1; 545160380Ssimon buf = (char *)safe_malloc(buf_sz); 546160380Ssimon 547160380Ssimon if (sysctlbyname(sysctlname, buf, &sz, NULL, 0) != -1) 548160380Ssimon buf[sz] = '\0'; 549160380Ssimon else 550160380Ssimon strlcpy(buf, unk_str, buf_sz); 551160380Ssimon 552160380Ssimon return buf; 553160380Ssimon} 554