1/* 2 * Miscellaneous support routines.. 3 * 4 * $FreeBSD$ 5 * 6 * Copyright (c) 1995 7 * Jordan Hubbard. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer, 14 * verbatim and that no modifications are made prior to this 15 * point in the file. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34#include "sade.h" 35#include <ctype.h> 36#include <unistd.h> 37#include <sys/stat.h> 38#include <sys/errno.h> 39#include <sys/file.h> 40#include <sys/types.h> 41#include <dirent.h> 42#include <sys/wait.h> 43#include <sys/param.h> 44#include <sys/mount.h> 45#include <ufs/ufs/ufsmount.h> 46#include <sys/reboot.h> 47#include <sys/disklabel.h> 48#include <fs/msdosfs/msdosfsmount.h> 49 50/* Quick check to see if a file is readable */ 51Boolean 52file_readable(char *fname) 53{ 54 if (!access(fname, F_OK)) 55 return TRUE; 56 return FALSE; 57} 58 59/* Quick check to see if a file is executable */ 60Boolean 61file_executable(char *fname) 62{ 63 if (!access(fname, X_OK)) 64 return TRUE; 65 return FALSE; 66} 67 68/* Concatenate two strings into static storage */ 69char * 70string_concat(char *one, char *two) 71{ 72 static char tmp[FILENAME_MAX]; 73 74 /* Yes, we're deliberately cavalier about not checking for overflow */ 75 strcpy(tmp, one); 76 strcat(tmp, two); 77 return tmp; 78} 79 80/* sane strncpy() function */ 81char * 82sstrncpy(char *dst, const char *src, int size) 83{ 84 dst[size] = '\0'; 85 return strncpy(dst, src, size); 86} 87 88/* Concatenate three strings into static storage */ 89char * 90string_concat3(char *one, char *two, char *three) 91{ 92 static char tmp[FILENAME_MAX]; 93 94 /* Yes, we're deliberately cavalier about not checking for overflow */ 95 strcpy(tmp, one); 96 strcat(tmp, two); 97 strcat(tmp, three); 98 return tmp; 99} 100 101/* Clip the whitespace off the end of a string */ 102char * 103string_prune(char *str) 104{ 105 int len = str ? strlen(str) : 0; 106 107 while (len && isspace(str[len - 1])) 108 str[--len] = '\0'; 109 return str; 110} 111 112/* run the whitespace off the front of a string */ 113char * 114string_skipwhite(char *str) 115{ 116 while (*str && isspace(*str)) 117 ++str; 118 return str; 119} 120 121/* copy optionally and allow second arg to be null */ 122char * 123string_copy(char *s1, char *s2) 124{ 125 if (!s1) 126 return NULL; 127 if (!s2) 128 s1[0] = '\0'; 129 else 130 strcpy(s1, s2); 131 return s1; 132} 133 134/* convert an integer to a string, using a static buffer */ 135char * 136itoa(int value) 137{ 138 static char buf[13]; 139 140 snprintf(buf, 12, "%d", value); 141 return buf; 142} 143 144Boolean 145directory_exists(const char *dirname) 146{ 147 DIR *tptr; 148 149 if (!dirname) 150 return FALSE; 151 if (!strlen(dirname)) 152 return FALSE; 153 154 tptr = opendir(dirname); 155 if (!tptr) 156 return (FALSE); 157 158 closedir(tptr); 159 return (TRUE); 160} 161 162char * 163pathBaseName(const char *path) 164{ 165 char *pt; 166 char *ret = (char *)path; 167 168 pt = strrchr(path,(int)'/'); 169 170 if (pt != 0) /* if there is a slash */ 171 { 172 ret = ++pt; /* start the file after it */ 173 } 174 175 return(ret); 176} 177 178/* A free guaranteed to take NULL ptrs */ 179void 180safe_free(void *ptr) 181{ 182 if (ptr) 183 free(ptr); 184} 185 186/* A malloc that checks errors */ 187void * 188safe_malloc(size_t size) 189{ 190 void *ptr; 191 192 if (size <= 0) 193 msgFatal("Invalid malloc size of %ld!", (long)size); 194 ptr = malloc(size); 195 if (!ptr) 196 msgFatal("Out of memory!"); 197 bzero(ptr, size); 198 return ptr; 199} 200 201/* A realloc that checks errors */ 202void * 203safe_realloc(void *orig, size_t size) 204{ 205 void *ptr; 206 207 if (size <= 0) 208 msgFatal("Invalid realloc size of %ld!", (long)size); 209 ptr = reallocf(orig, size); 210 if (!ptr) 211 msgFatal("Out of memory!"); 212 return ptr; 213} 214 215/* Create a path biased from the VAR_INSTALL_ROOT variable (if not /) */ 216char * 217root_bias(char *path) 218{ 219 static char tmp[FILENAME_MAX]; 220 char *cp = variable_get(VAR_INSTALL_ROOT); 221 222 if (!strcmp(cp, "/")) 223 return path; 224 strcpy(tmp, variable_get(VAR_INSTALL_ROOT)); 225 strcat(tmp, path); 226 return tmp; 227} 228 229/* 230 * These next routines are kind of specialized just for building item lists 231 * for dialog_menu(). 232 */ 233 234/* Add an item to an item list */ 235dialogMenuItem * 236item_add(dialogMenuItem *list, char *prompt, char *title, 237 int (*checked)(dialogMenuItem *self), 238 int (*fire)(dialogMenuItem *self), 239 void (*selected)(dialogMenuItem *self, int is_selected), 240 void *data, int *aux, int *curr, int *max) 241{ 242 dialogMenuItem *d; 243 244 if (*curr == *max) { 245 *max += 20; 246 list = (dialogMenuItem *)safe_realloc(list, sizeof(dialogMenuItem) * *max); 247 } 248 d = &list[(*curr)++]; 249 bzero(d, sizeof(*d)); 250 d->prompt = prompt ? strdup(prompt) : NULL; 251 d->title = title ? strdup(title) : NULL; 252 d->checked = checked; 253 d->fire = fire; 254 d->selected = selected; 255 d->data = data; 256 d->aux = (long)aux; 257 return list; 258} 259 260/* Toss the items out */ 261void 262items_free(dialogMenuItem *list, int *curr, int *max) 263{ 264 int i; 265 266 for (i = 0; list[i].prompt; i++) { 267 safe_free(list[i].prompt); 268 safe_free(list[i].title); 269 } 270 safe_free(list); 271 *curr = *max = 0; 272} 273 274int 275Mkdir(char *ipath) 276{ 277 struct stat sb; 278 int final; 279 char *p, *path; 280 281 if (file_readable(ipath) || Fake) 282 return DITEM_SUCCESS; 283 284 path = strcpy(alloca(strlen(ipath) + 1), ipath); 285 if (isDebug()) 286 msgDebug("mkdir(%s)\n", path); 287 p = path; 288 if (p[0] == '/') /* Skip leading '/'. */ 289 ++p; 290 for (final = FALSE; !final; ++p) { 291 if (p[0] == '\0' || (p[0] == '/' && p[1] == '\0')) 292 final = TRUE; 293 else if (p[0] != '/') 294 continue; 295 *p = '\0'; 296 if (stat(path, &sb)) { 297 if (errno != ENOENT) { 298 msgConfirm("Couldn't stat directory %s: %s", path, strerror(errno)); 299 return DITEM_FAILURE; 300 } 301 if (isDebug()) 302 msgDebug("mkdir(%s..)\n", path); 303 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { 304 msgConfirm("Couldn't create directory %s: %s", path,strerror(errno)); 305 return DITEM_FAILURE; 306 } 307 } 308 *p = '/'; 309 } 310 return DITEM_SUCCESS; 311} 312 313int 314Mkdir_command(char *key, void *dir) 315{ 316 return (Mkdir((char*)dir)); 317} 318 319int 320Mount(char *mountp, void *dev) 321{ 322 struct ufs_args ufsargs; 323 char device[80]; 324 char mountpoint[FILENAME_MAX]; 325 326 if (Fake) 327 return DITEM_SUCCESS; 328 329 if (*((char *)dev) != '/') { 330 sprintf(device, "/dev/%s", (char *)dev); 331 sprintf(mountpoint, "%s", mountp); 332 } 333 else { 334 strcpy(device, dev); 335 strcpy(mountpoint, mountp); 336 } 337 memset(&ufsargs,0,sizeof ufsargs); 338 339 if (Mkdir(mountpoint)) { 340 msgConfirm("Unable to make directory mountpoint for %s!", mountpoint); 341 return DITEM_FAILURE; 342 } 343 if (isDebug()) 344 msgDebug("mount %s %s\n", device, mountpoint); 345 346 ufsargs.fspec = device; 347 if (mount("ufs", mountpoint, 0, 348 (caddr_t)&ufsargs) == -1) { 349 msgConfirm("Error mounting %s on %s : %s", device, mountpoint, strerror(errno)); 350 return DITEM_FAILURE; 351 } 352 return DITEM_SUCCESS; 353} 354 355WINDOW * 356openLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height) 357{ 358 WINDOW *win; 359 static char help[FILENAME_MAX]; 360 361 /* We need a curses window */ 362 win = newwin(LINES, COLS, 0, 0); 363 if (win) { 364 /* Say where our help comes from */ 365 if (helpfile) { 366 use_helpline("Press F1 for more information on this screen."); 367 use_helpfile(systemHelpFile(helpfile, help)); 368 } 369 /* Setup a nice screen for us to splat stuff onto */ 370 draw_box(win, y, x, height, width, dialog_attr, border_attr); 371 wattrset(win, dialog_attr); 372 mvwaddstr(win, y, x + (COLS - strlen(title)) / 2, title); 373 } 374 return win; 375} 376 377ComposeObj * 378initLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max) 379{ 380 ComposeObj *obj = NULL, *first; 381 int n; 382 383 /* Loop over the layout list, create the objects, and add them 384 onto the chain of objects that dialog uses for traversal*/ 385 386 n = 0; 387 while (layout[n].help != NULL) { 388 int t = TYPE_OF_OBJ(layout[n].type); 389 390 switch (t) { 391 case STRINGOBJ: 392 layout[n].obj = NewStringObj(win, layout[n].prompt, layout[n].var, 393 layout[n].y + y, layout[n].x + x, layout[n].len, layout[n].maxlen); 394 ((StringObj *)layout[n].obj)->attr_mask = ATTR_OF_OBJ(layout[n].type); 395 break; 396 397 case BUTTONOBJ: 398 layout[n].obj = NewButtonObj(win, layout[n].prompt, layout[n].var, layout[n].y + y, layout[n].x + x); 399 break; 400 401 default: 402 msgFatal("Don't support this object yet!"); 403 } 404 AddObj(&obj, t, (void *) layout[n].obj); 405 n++; 406 } 407 *max = n - 1; 408 /* Find the first object in the list */ 409 for (first = obj; first->prev; first = first->prev); 410 return first; 411} 412 413int 414layoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, int *n, int max, int *cbutton, int *cancel) 415{ 416 char help_line[80]; 417 int ret, i, len = strlen(layout[*n].help); 418 419 /* Display the help line at the bottom of the screen */ 420 for (i = 0; i < 79; i++) 421 help_line[i] = (i < len) ? layout[*n].help[i] : ' '; 422 help_line[i] = '\0'; 423 use_helpline(help_line); 424 display_helpline(win, LINES - 1, COLS - 1); 425 wrefresh(win); 426 427 /* Ask for libdialog to do its stuff */ 428 ret = PollObj(obj); 429 /* Handle special case stuff that libdialog misses. Sigh */ 430 switch (ret) { 431 case SEL_ESC: /* Bail out */ 432 *cancel = TRUE; 433 return FALSE; 434 435 /* This doesn't work for list dialogs. Oh well. Perhaps 436 should special case the move from the OK button ``up'' 437 to make it go to the interface list, but then it gets 438 awkward for the user to go back and correct screw up's 439 in the per-interface section */ 440 case KEY_DOWN: 441 case SEL_CR: 442 case SEL_TAB: 443 if (*n < max) 444 ++*n; 445 else 446 *n = 0; 447 break; 448 449 /* The user has pressed enter over a button object */ 450 case SEL_BUTTON: 451 if (cbutton && *cbutton) 452 *cancel = TRUE; 453 else 454 *cancel = FALSE; 455 return FALSE; 456 457 case KEY_UP: 458 case SEL_BACKTAB: 459 if (*n) 460 --*n; 461 else 462 *n = max; 463 break; 464 465 case KEY_F(1): 466 display_helpfile(); 467 468 /* They tried some key combination we don't support - tootle them forcefully! */ 469 default: 470 beep(); 471 } 472 return TRUE; 473} 474 475WINDOW * 476savescr(void) 477{ 478 WINDOW *w; 479 480 w = dupwin(newscr); 481 return w; 482} 483 484void 485restorescr(WINDOW *w) 486{ 487 touchwin(w); 488 wrefresh(w); 489 delwin(w); 490} 491 492