1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1991-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * This file contains the code to add new disk_type and partition 31*0Sstevel@tonic-gate * definitions to a format data file. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate #include "global.h" 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <ctype.h> 36*0Sstevel@tonic-gate #include <stdlib.h> 37*0Sstevel@tonic-gate #include <unistd.h> 38*0Sstevel@tonic-gate #include <string.h> 39*0Sstevel@tonic-gate #include <fcntl.h> 40*0Sstevel@tonic-gate #include <errno.h> 41*0Sstevel@tonic-gate #include <memory.h> 42*0Sstevel@tonic-gate #include <sys/fcntl.h> 43*0Sstevel@tonic-gate #include <sys/param.h> 44*0Sstevel@tonic-gate #include <time.h> 45*0Sstevel@tonic-gate #include <sys/time.h> 46*0Sstevel@tonic-gate #include <stdarg.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate #include "add_definition.h" 49*0Sstevel@tonic-gate #include "misc.h" 50*0Sstevel@tonic-gate #include "partition.h" 51*0Sstevel@tonic-gate #include "menu_command.h" 52*0Sstevel@tonic-gate #include "startup.h" 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate extern struct ctlr_type ctlr_types[]; 55*0Sstevel@tonic-gate extern int nctypes; 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate extern int errno; 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate /* Function prototypes */ 60*0Sstevel@tonic-gate #ifdef __STDC__ 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate static void add_disktype(FILE *fd, struct disk_info *disk_info); 63*0Sstevel@tonic-gate static void add_partition(FILE *fd, struct disk_info *, 64*0Sstevel@tonic-gate struct partition_info *); 65*0Sstevel@tonic-gate static int add_entry(int col, FILE *fd, char *format, ...); 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate #else /* __STDC__ */ 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate static void add_disktype(); 70*0Sstevel@tonic-gate static void add_partition(); 71*0Sstevel@tonic-gate static int add_entry(); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate #endif /* __STDC__ */ 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* 76*0Sstevel@tonic-gate * Add new definitions for the current disk/partition to a format data file. 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate int 79*0Sstevel@tonic-gate add_definition() 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate FILE *fd; 82*0Sstevel@tonic-gate char *filename; 83*0Sstevel@tonic-gate time_t clock; 84*0Sstevel@tonic-gate char *prompt; 85*0Sstevel@tonic-gate union { 86*0Sstevel@tonic-gate int xfoo; 87*0Sstevel@tonic-gate char deflt_str[MAXPATHLEN]; 88*0Sstevel@tonic-gate } x; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* 91*0Sstevel@tonic-gate * There must be a current disk and partition table 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate if (cur_disk == NULL) { 94*0Sstevel@tonic-gate err_print("No Current Disk.\n"); 95*0Sstevel@tonic-gate return (0); 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate if (cur_dtype == NULL) { 98*0Sstevel@tonic-gate err_print("Current disk type is not set.\n"); 99*0Sstevel@tonic-gate return (-1); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate if (cur_parts == NULL) { 102*0Sstevel@tonic-gate err_print("Current partition is not set.\n"); 103*0Sstevel@tonic-gate return (-1); 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * If neither the disk definition nor the partition 107*0Sstevel@tonic-gate * information has been changed, there's nothing to save. 108*0Sstevel@tonic-gate */ 109*0Sstevel@tonic-gate if (cur_dtype->dtype_filename != NULL && 110*0Sstevel@tonic-gate cur_parts->pinfo_filename != NULL) { 111*0Sstevel@tonic-gate err_print("\ 112*0Sstevel@tonic-gate Neither the disk type nor the partitioning has been changed.\n"); 113*0Sstevel@tonic-gate return (-1); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate /* 116*0Sstevel@tonic-gate * If saving the partition, and it's unnamed, the user should name 117*0Sstevel@tonic-gate * it first. 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate if (cur_parts->pinfo_name == NULL) { 120*0Sstevel@tonic-gate assert(cur_parts->pinfo_filename == NULL); 121*0Sstevel@tonic-gate err_print("Please name this partition type before saving it\n"); 122*0Sstevel@tonic-gate return (-1); 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate /* 125*0Sstevel@tonic-gate * Let the user know what we're doing 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate if (cur_dtype->dtype_filename == NULL && 128*0Sstevel@tonic-gate cur_parts->pinfo_filename == NULL) { 129*0Sstevel@tonic-gate fmt_print("Saving new disk and partition definitions\n"); 130*0Sstevel@tonic-gate } else if (cur_dtype->dtype_filename == NULL) { 131*0Sstevel@tonic-gate fmt_print("Saving new disk definition\n"); 132*0Sstevel@tonic-gate } else { 133*0Sstevel@tonic-gate assert(cur_parts->pinfo_filename == NULL); 134*0Sstevel@tonic-gate fmt_print("Saving new partition definition\n"); 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate /* 137*0Sstevel@tonic-gate * Ask for the file to which to append the new definitions 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate prompt = "Enter file name"; 140*0Sstevel@tonic-gate (void) strcpy(x.deflt_str, "./format.dat"); 141*0Sstevel@tonic-gate filename = (char *)input(FIO_OSTR, prompt, 142*0Sstevel@tonic-gate ':', (u_ioparam_t *)NULL, &x.xfoo, DATA_INPUT); 143*0Sstevel@tonic-gate assert(filename != NULL); 144*0Sstevel@tonic-gate /* 145*0Sstevel@tonic-gate * Open the file in append mode, or create it, if necessary 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate if ((fd = fopen(filename, "a")) == NULL) { 148*0Sstevel@tonic-gate err_print("Cannot open `%s' - %s\n", filename, 149*0Sstevel@tonic-gate strerror(errno)); 150*0Sstevel@tonic-gate destroy_data(filename); 151*0Sstevel@tonic-gate return (-1); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate /* 154*0Sstevel@tonic-gate * Write a header for the new definitions 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate if ((cur_dtype->dtype_filename == NULL) && 157*0Sstevel@tonic-gate (cur_parts->pinfo_filename == NULL)) { 158*0Sstevel@tonic-gate (void) fprintf(fd, "#\n# New disk/partition type "); 159*0Sstevel@tonic-gate } else if (cur_dtype->dtype_filename == NULL) { 160*0Sstevel@tonic-gate (void) fprintf(fd, "#\n# New disk type "); 161*0Sstevel@tonic-gate } else { 162*0Sstevel@tonic-gate (void) fprintf(fd, "#\n# New partition type "); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate (void) time(&clock); 165*0Sstevel@tonic-gate (void) fprintf(fd, " saved on %s#\n", ctime(&clock)); 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * Save the new definitions 168*0Sstevel@tonic-gate */ 169*0Sstevel@tonic-gate if (cur_dtype->dtype_filename == NULL) { 170*0Sstevel@tonic-gate add_disktype(fd, cur_disk); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate if (cur_parts->pinfo_filename == NULL) { 173*0Sstevel@tonic-gate add_partition(fd, cur_disk, cur_parts); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate /* 176*0Sstevel@tonic-gate * We're finished. Clean up 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate (void) fclose(fd); 179*0Sstevel@tonic-gate destroy_data(filename); 180*0Sstevel@tonic-gate return (0); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate /* 184*0Sstevel@tonic-gate * Add a disk_type definition to the file fd 185*0Sstevel@tonic-gate */ 186*0Sstevel@tonic-gate static void 187*0Sstevel@tonic-gate add_disktype(fd, disk_info) 188*0Sstevel@tonic-gate FILE *fd; 189*0Sstevel@tonic-gate struct disk_info *disk_info; 190*0Sstevel@tonic-gate { 191*0Sstevel@tonic-gate int col; 192*0Sstevel@tonic-gate struct disk_type *disk_type; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate disk_type = disk_info->disk_type; 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate (void) fprintf(fd, "disk_type = \"%s\" \\\n", 197*0Sstevel@tonic-gate disk_type->dtype_asciilabel); 198*0Sstevel@tonic-gate col = add_entry(0, fd, " : ctlr = %s", 199*0Sstevel@tonic-gate ((disk_info->disk_ctlr)->ctlr_ctype)->ctype_name); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate col = add_entry(col, fd, " : ncyl = %d", disk_type->dtype_ncyl); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate col = add_entry(col, fd, " : acyl = %d", disk_type->dtype_acyl); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate col = add_entry(col, fd, " : pcyl = %d", disk_type->dtype_pcyl); 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate col = add_entry(col, fd, " : nhead = %d", disk_type->dtype_nhead); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_PHEAD) { 210*0Sstevel@tonic-gate col = add_entry(col, fd, " : phead = %d", 211*0Sstevel@tonic-gate disk_type->dtype_phead); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate col = add_entry(col, fd, " : nsect = %d", disk_type->dtype_nsect); 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_PSECT) { 217*0Sstevel@tonic-gate col = add_entry(col, fd, " : psect = %d", 218*0Sstevel@tonic-gate disk_type->dtype_psect); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_BPT) { 222*0Sstevel@tonic-gate col = add_entry(col, fd, " : bpt = %d", disk_type->dtype_bpt); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate col = add_entry(col, fd, " : rpm = %d", disk_type->dtype_rpm); 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_FMTTIME) { 228*0Sstevel@tonic-gate col = add_entry(col, fd, " : fmt_time = %d", 229*0Sstevel@tonic-gate disk_type->dtype_fmt_time); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_CYLSKEW) { 233*0Sstevel@tonic-gate col = add_entry(col, fd, " : cyl_skew = %d", 234*0Sstevel@tonic-gate disk_type->dtype_cyl_skew); 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_TRKSKEW) { 238*0Sstevel@tonic-gate col = add_entry(col, fd, " : trk_skew = %d", 239*0Sstevel@tonic-gate disk_type->dtype_trk_skew); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_TRKS_ZONE) { 243*0Sstevel@tonic-gate col = add_entry(col, fd, " : trks_zone = %d", 244*0Sstevel@tonic-gate disk_type->dtype_trks_zone); 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_ATRKS) { 248*0Sstevel@tonic-gate col = add_entry(col, fd, " : atrks = %d", 249*0Sstevel@tonic-gate disk_type->dtype_atrks); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_ASECT) { 253*0Sstevel@tonic-gate col = add_entry(col, fd, " : asect = %d", 254*0Sstevel@tonic-gate disk_type->dtype_asect); 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_CACHE) { 258*0Sstevel@tonic-gate col = add_entry(col, fd, " : cache = %d", 259*0Sstevel@tonic-gate disk_type->dtype_cache); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_PREFETCH) { 263*0Sstevel@tonic-gate col = add_entry(col, fd, " : prefetch = %d", 264*0Sstevel@tonic-gate disk_type->dtype_threshold); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_CACHE_MIN) { 268*0Sstevel@tonic-gate col = add_entry(col, fd, " : min_prefetch = %d", 269*0Sstevel@tonic-gate disk_type->dtype_prefetch_min); 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_CACHE_MAX) { 273*0Sstevel@tonic-gate col = add_entry(col, fd, " : max_prefetch = %d", 274*0Sstevel@tonic-gate disk_type->dtype_prefetch_max); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_BPS) { 278*0Sstevel@tonic-gate col = add_entry(col, fd, " : bps = %d", 279*0Sstevel@tonic-gate disk_type->dtype_bps); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (disk_type->dtype_options & SUP_DRTYPE) { 283*0Sstevel@tonic-gate col = add_entry(col, fd, " : drive_type = %d", 284*0Sstevel@tonic-gate disk_type->dtype_dr_type); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * Terminate the last line, and print one blank line 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate (void) fprintf(fd, col == 0 ? "\n" : "\n\n"); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate /* 296*0Sstevel@tonic-gate * Once we exceed this length, wrap to a new line 297*0Sstevel@tonic-gate */ 298*0Sstevel@tonic-gate #define MAX_COLUMNS 50 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Add a partition definition to the file fd 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate static void 304*0Sstevel@tonic-gate add_partition(fd, disk_info, part) 305*0Sstevel@tonic-gate FILE *fd; 306*0Sstevel@tonic-gate struct disk_info *disk_info; 307*0Sstevel@tonic-gate struct partition_info *part; 308*0Sstevel@tonic-gate { 309*0Sstevel@tonic-gate int col; 310*0Sstevel@tonic-gate int i; 311*0Sstevel@tonic-gate struct disk_type *disk_type; 312*0Sstevel@tonic-gate struct dk_map32 *pp; 313*0Sstevel@tonic-gate char *s; 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate #if defined(_SUNOS_VTOC_8) 316*0Sstevel@tonic-gate struct dk_map2 *pv; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate #elif defined(_SUNOS_VTOC_16) 319*0Sstevel@tonic-gate struct dkl_partition *pv; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate #else 322*0Sstevel@tonic-gate #error No VTOC format defined. 323*0Sstevel@tonic-gate #endif /* defined (_SUNOS_VTOC_8) */ 324*0Sstevel@tonic-gate struct dk_map2 *dv; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate disk_type = disk_info->disk_type; 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate (void) fprintf(fd, "partition = \"%s\" \\\n", part->pinfo_name); 329*0Sstevel@tonic-gate (void) fprintf(fd, "\t : disk = \"%s\" : ctlr = %s \\\n", 330*0Sstevel@tonic-gate disk_type->dtype_asciilabel, 331*0Sstevel@tonic-gate ((disk_info->disk_ctlr)->ctlr_ctype)->ctype_name); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * Print the specifications for each useful partition 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate col = 0; 337*0Sstevel@tonic-gate pp = part->pinfo_map; 338*0Sstevel@tonic-gate pv = part->vtoc.v_part; 339*0Sstevel@tonic-gate dv = default_vtoc_map; 340*0Sstevel@tonic-gate for (i = 0; i < NDKMAP; i++, pp++, pv++, dv++) { 341*0Sstevel@tonic-gate if (pp->dkl_nblk != 0) { 342*0Sstevel@tonic-gate col = add_entry(col, fd, " : %c = ", 343*0Sstevel@tonic-gate i + PARTITION_BASE); 344*0Sstevel@tonic-gate if (pv->p_tag != dv->p_tag || 345*0Sstevel@tonic-gate pv->p_flag != dv->p_flag) { 346*0Sstevel@tonic-gate s = find_string(ptag_choices, 347*0Sstevel@tonic-gate (int)pv->p_tag); 348*0Sstevel@tonic-gate if (s != NULL) { 349*0Sstevel@tonic-gate col = add_entry(col, fd, " %s,", s); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate s = find_string(pflag_choices, 352*0Sstevel@tonic-gate (int)pv->p_flag); 353*0Sstevel@tonic-gate if (s != NULL) { 354*0Sstevel@tonic-gate col = add_entry(col, fd, " %s,", s); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate col = add_entry(col, fd, " %d, %d", pp->dkl_cylno, 358*0Sstevel@tonic-gate pp->dkl_nblk); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * Terminate the last line, and print one blank line 364*0Sstevel@tonic-gate */ 365*0Sstevel@tonic-gate (void) fprintf(fd, col == 0 ? "\n" : "\n\n"); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* 369*0Sstevel@tonic-gate * Add an entry to the file fd. col is the current starting column. 370*0Sstevel@tonic-gate * Return the resulting new column position. 371*0Sstevel@tonic-gate */ 372*0Sstevel@tonic-gate /*PRINTFLIKE3*/ 373*0Sstevel@tonic-gate static int 374*0Sstevel@tonic-gate add_entry(int col, FILE *fd, char *format, ...) 375*0Sstevel@tonic-gate { 376*0Sstevel@tonic-gate va_list ap; 377*0Sstevel@tonic-gate va_start(ap, format); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate if (col > MAX_COLUMNS) { 380*0Sstevel@tonic-gate (void) fprintf(fd, " \\\n"); 381*0Sstevel@tonic-gate col = 0; 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate if (col == 0) { 384*0Sstevel@tonic-gate col += fprintf(fd, "\t"); 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate col += vfprintf(fd, format, ap); 387*0Sstevel@tonic-gate va_end(ap); 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate return (col); 390*0Sstevel@tonic-gate } 391