1 1.79 christos /* $NetBSD: create.c,v 1.79 2024/12/05 17:17:43 christos Exp $ */ 2 1.9 cgd 3 1.1 cgd /*- 4 1.8 cgd * Copyright (c) 1989, 1993 5 1.8 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.43 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.45 jmc #if HAVE_NBTOOL_CONFIG_H 33 1.45 jmc #include "nbtool_config.h" 34 1.45 jmc #endif 35 1.45 jmc 36 1.13 lukem #include <sys/cdefs.h> 37 1.39 tv #if defined(__RCSID) && !defined(lint) 38 1.9 cgd #if 0 39 1.8 cgd static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 40 1.9 cgd #else 41 1.79 christos __RCSID("$NetBSD: create.c,v 1.79 2024/12/05 17:17:43 christos Exp $"); 42 1.9 cgd #endif 43 1.1 cgd #endif /* not lint */ 44 1.1 cgd 45 1.1 cgd #include <sys/param.h> 46 1.1 cgd #include <sys/stat.h> 47 1.29 simonb 48 1.44 lukem #if ! HAVE_NBTOOL_CONFIG_H 49 1.13 lukem #include <dirent.h> 50 1.38 tv #endif 51 1.38 tv 52 1.13 lukem #include <errno.h> 53 1.5 cgd #include <fcntl.h> 54 1.5 cgd #include <grp.h> 55 1.5 cgd #include <pwd.h> 56 1.37 lukem #include <stdio.h> 57 1.29 simonb #include <stdarg.h> 58 1.72 christos #include <stdint.h> 59 1.35 lukem #include <stdlib.h> 60 1.13 lukem #include <string.h> 61 1.13 lukem #include <time.h> 62 1.5 cgd #include <unistd.h> 63 1.29 simonb 64 1.37 lukem #ifndef NO_MD5 65 1.37 lukem #include <md5.h> 66 1.37 lukem #endif 67 1.37 lukem #ifndef NO_RMD160 68 1.50 christos #include <rmd160.h> 69 1.37 lukem #endif 70 1.37 lukem #ifndef NO_SHA1 71 1.37 lukem #include <sha1.h> 72 1.37 lukem #endif 73 1.47 elad #ifndef NO_SHA2 74 1.50 christos #include <sha2.h> 75 1.47 elad #endif 76 1.37 lukem 77 1.5 cgd #include "extern.h" 78 1.1 cgd 79 1.5 cgd #define INDENTNAMELEN 15 80 1.5 cgd #define MAXLINELEN 80 81 1.5 cgd 82 1.5 cgd static gid_t gid; 83 1.5 cgd static uid_t uid; 84 1.5 cgd static mode_t mode; 85 1.18 mrg static u_long flags; 86 1.5 cgd 87 1.73 christos static void output(FILE *, int, int *, const char *, ...) 88 1.73 christos __printflike(4, 5); 89 1.73 christos static int statd(FILE *, FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, 90 1.73 christos u_long *); 91 1.73 christos static void statf(FILE *, int, FTSENT *); 92 1.1 cgd 93 1.5 cgd void 94 1.73 christos cwalk(FILE *fp) 95 1.1 cgd { 96 1.13 lukem FTS *t; 97 1.13 lukem FTSENT *p; 98 1.33 lukem time_t clocktime; 99 1.34 lukem char host[MAXHOSTNAMELEN + 1]; 100 1.55 christos const char *user; 101 1.41 grant char *argv[2]; 102 1.41 grant char dot[] = "."; 103 1.63 christos int indent = 0; 104 1.55 christos 105 1.41 grant argv[0] = dot; 106 1.41 grant argv[1] = NULL; 107 1.5 cgd 108 1.36 lukem time(&clocktime); 109 1.36 lukem gethostname(host, sizeof(host)); 110 1.14 mrg host[sizeof(host) - 1] = '\0'; 111 1.55 christos if ((user = getlogin()) == NULL) { 112 1.55 christos struct passwd *pw; 113 1.76 sevan user = (pw = getpwuid(getuid())) != NULL ? pw->pw_name : 114 1.55 christos "<unknown>"; 115 1.55 christos } 116 1.55 christos 117 1.62 christos if (!nflag) 118 1.73 christos fprintf(fp, 119 1.62 christos "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n" 120 1.62 christos "#\t date: %s", 121 1.62 christos user, host, fullpath, ctime(&clocktime)); 122 1.1 cgd 123 1.54 rillig if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL) 124 1.17 wsanchez mtree_err("fts_open: %s", strerror(errno)); 125 1.36 lukem while ((p = fts_read(t)) != NULL) { 126 1.63 christos if (jflag) 127 1.63 christos indent = p->fts_level * 4; 128 1.36 lukem if (check_excludes(p->fts_name, p->fts_path)) { 129 1.36 lukem fts_set(t, p, FTS_SKIP); 130 1.36 lukem continue; 131 1.36 lukem } 132 1.69 christos if (!find_only(p->fts_path)) { 133 1.69 christos fts_set(t, p, FTS_SKIP); 134 1.69 christos continue; 135 1.69 christos } 136 1.1 cgd switch(p->fts_info) { 137 1.1 cgd case FTS_D: 138 1.68 christos if (!bflag) 139 1.73 christos fprintf(fp, "\n"); 140 1.62 christos if (!nflag) 141 1.73 christos fprintf(fp, "# %s\n", p->fts_path); 142 1.73 christos statd(fp, t, p, &uid, &gid, &mode, &flags); 143 1.73 christos statf(fp, indent, p); 144 1.1 cgd break; 145 1.1 cgd case FTS_DP: 146 1.68 christos if (p->fts_level > 0) 147 1.66 christos if (!nflag) 148 1.73 christos fprintf(fp, "%*s# %s\n", indent, "", 149 1.66 christos p->fts_path); 150 1.68 christos if (p->fts_level > 0 || flavor == F_FREEBSD9) { 151 1.73 christos fprintf(fp, "%*s..\n", indent, ""); 152 1.68 christos if (!bflag) 153 1.73 christos fprintf(fp, "\n"); 154 1.66 christos } 155 1.5 cgd break; 156 1.1 cgd case FTS_DNR: 157 1.1 cgd case FTS_ERR: 158 1.1 cgd case FTS_NS: 159 1.36 lukem mtree_err("%s: %s", 160 1.36 lukem p->fts_path, strerror(p->fts_errno)); 161 1.5 cgd break; 162 1.1 cgd default: 163 1.5 cgd if (!dflag) 164 1.73 christos statf(fp, indent, p); 165 1.5 cgd break; 166 1.36 lukem 167 1.1 cgd } 168 1.36 lukem } 169 1.77 christos if (errno != 0) 170 1.77 christos mtree_err("fts_read: %s", strerror(errno)); 171 1.36 lukem fts_close(t); 172 1.5 cgd if (sflag && keys & F_CKSUM) 173 1.40 soren mtree_err("%s checksum: %u", fullpath, crc_total); 174 1.5 cgd } 175 1.1 cgd 176 1.5 cgd static void 177 1.75 christos dosum(FILE *fp, int indent, FTSENT *p, int *offset, int flag, 178 1.75 christos char * (*func)(const char *, char *), const char *key) 179 1.75 christos { 180 1.75 christos char *digestbuf; 181 1.75 christos 182 1.75 christos if ((keys & flag) == 0) 183 1.75 christos return; 184 1.75 christos 185 1.75 christos digestbuf = (*func)(p->fts_accpath, NULL); 186 1.75 christos if (digestbuf != NULL) { 187 1.75 christos output(fp, indent, offset, "%s=%s", key, digestbuf); 188 1.75 christos free(digestbuf); 189 1.75 christos return; 190 1.75 christos } 191 1.75 christos 192 1.75 christos if (qflag) { 193 1.75 christos warn("%s: %s failed", p->fts_path, key); 194 1.75 christos return; 195 1.75 christos } 196 1.75 christos 197 1.75 christos mtree_err("%s: %s failed: %s", p->fts_path, key, strerror(errno)); 198 1.75 christos } 199 1.75 christos 200 1.75 christos static char * 201 1.75 christos crcFile(const char *fname, char *dummy __unused) 202 1.75 christos { 203 1.75 christos char *ptr; 204 1.75 christos uint32_t val, len; 205 1.75 christos int fd, e; 206 1.75 christos 207 1.75 christos if ((fd = open(fname, O_RDONLY)) == -1) 208 1.75 christos goto out; 209 1.75 christos 210 1.75 christos e = crc(fd, &val, &len); 211 1.75 christos close(fd); 212 1.75 christos if (e) 213 1.75 christos goto out; 214 1.75 christos 215 1.75 christos if (asprintf(&ptr, "%u", val) < 0) 216 1.75 christos goto out; 217 1.75 christos 218 1.75 christos return ptr; 219 1.75 christos out: 220 1.75 christos mtree_err("%s: %s", fname, strerror(errno)); 221 1.75 christos return NULL; 222 1.75 christos } 223 1.75 christos 224 1.75 christos static void 225 1.73 christos statf(FILE *fp, int indent, FTSENT *p) 226 1.5 cgd { 227 1.75 christos int offset; 228 1.65 christos const char *name = NULL; 229 1.5 cgd 230 1.73 christos offset = fprintf(fp, "%*s%s%s", indent, "", 231 1.46 lukem S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); 232 1.5 cgd 233 1.63 christos if (offset > (INDENTNAMELEN + indent)) 234 1.63 christos offset = MAXLINELEN; 235 1.5 cgd else 236 1.73 christos offset += fprintf(fp, "%*s", 237 1.73 christos (INDENTNAMELEN + indent) - offset, ""); 238 1.5 cgd 239 1.68 christos if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag)) 240 1.73 christos output(fp, indent, &offset, "type=%s", 241 1.63 christos inotype(p->fts_statp->st_mode)); 242 1.15 ross if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) { 243 1.30 lukem if (keys & F_UNAME && 244 1.30 lukem (name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL) 245 1.73 christos output(fp, indent, &offset, "uname=%s", name); 246 1.65 christos if (keys & F_UID || (keys & F_UNAME && name == NULL)) 247 1.73 christos output(fp, indent, &offset, "uid=%u", 248 1.73 christos p->fts_statp->st_uid); 249 1.15 ross } 250 1.15 ross if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) { 251 1.30 lukem if (keys & F_GNAME && 252 1.30 lukem (name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL) 253 1.73 christos output(fp, indent, &offset, "gname=%s", name); 254 1.65 christos if (keys & F_GID || (keys & F_GNAME && name == NULL)) 255 1.73 christos output(fp, indent, &offset, "gid=%u", 256 1.73 christos p->fts_statp->st_gid); 257 1.15 ross } 258 1.5 cgd if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 259 1.73 christos output(fp, indent, &offset, "mode=%#o", 260 1.63 christos p->fts_statp->st_mode & MBITS); 261 1.32 lukem if (keys & F_DEV && 262 1.32 lukem (S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode))) 263 1.73 christos output(fp, indent, &offset, "device=%#jx", 264 1.70 christos (uintmax_t)p->fts_statp->st_rdev); 265 1.5 cgd if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 266 1.74 christos output(fp, indent, &offset, "nlink=%ju", 267 1.74 christos (uintmax_t)p->fts_statp->st_nlink); 268 1.68 christos if (keys & F_SIZE && 269 1.71 christos (flavor == F_FREEBSD9 || S_ISREG(p->fts_statp->st_mode))) 270 1.73 christos output(fp, indent, &offset, "size=%ju", 271 1.70 christos (uintmax_t)p->fts_statp->st_size); 272 1.53 rillig if (keys & F_TIME) 273 1.45 jmc #if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H) 274 1.73 christos output(fp, indent, &offset, "time=%jd.%09ld", 275 1.70 christos (intmax_t)p->fts_statp->st_mtimespec.tv_sec, 276 1.10 jtc p->fts_statp->st_mtimespec.tv_nsec); 277 1.28 hubertf #else 278 1.73 christos output(fp, indent, &offset, "time=%jd.%09ld", 279 1.70 christos (intmax_t)p->fts_statp->st_mtime, (long)0); 280 1.17 wsanchez #endif 281 1.75 christos if (S_ISREG(p->fts_statp->st_mode)) { 282 1.75 christos dosum(fp, indent, p, &offset, F_CKSUM, crcFile, "cksum"); 283 1.37 lukem #ifndef NO_MD5 284 1.75 christos dosum(fp, indent, p, &offset, F_MD5, MD5File, MD5KEY); 285 1.37 lukem #endif /* ! NO_MD5 */ 286 1.37 lukem #ifndef NO_RMD160 287 1.75 christos dosum(fp, indent, p, &offset, F_RMD160, RMD160File, RMD160KEY); 288 1.37 lukem #endif /* ! NO_RMD160 */ 289 1.37 lukem #ifndef NO_SHA1 290 1.75 christos dosum(fp, indent, p, &offset, F_SHA1, SHA1File, SHA1KEY); 291 1.37 lukem #endif /* ! NO_SHA1 */ 292 1.47 elad #ifndef NO_SHA2 293 1.75 christos dosum(fp, indent, p, &offset, F_SHA256, SHA256_File, SHA256KEY); 294 1.60 christos #ifdef SHA384_BLOCK_LENGTH 295 1.75 christos dosum(fp, indent, p, &offset, F_SHA384, SHA384_File, SHA384KEY); 296 1.60 christos #endif 297 1.75 christos dosum(fp, indent, p, &offset, F_SHA512, SHA512_File, SHA512KEY); 298 1.75 christos #endif /* ! NO_SHA2 */ 299 1.47 elad } 300 1.5 cgd if (keys & F_SLINK && 301 1.5 cgd (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 302 1.73 christos output(fp, indent, &offset, "link=%s", 303 1.63 christos vispath(rlink(p->fts_accpath))); 304 1.38 tv #if HAVE_STRUCT_STAT_ST_FLAGS 305 1.59 spz if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { 306 1.59 spz char *str = flags_to_string(p->fts_statp->st_flags, "none"); 307 1.73 christos output(fp, indent, &offset, "flags=%s", str); 308 1.59 spz free(str); 309 1.59 spz } 310 1.38 tv #endif 311 1.36 lukem putchar('\n'); 312 1.1 cgd } 313 1.1 cgd 314 1.21 mrg /* XXX 315 1.21 mrg * FLAGS2INDEX will fail once the user and system settable bits need more 316 1.21 mrg * than one byte, respectively. 317 1.21 mrg */ 318 1.21 mrg #define FLAGS2INDEX(x) (((x >> 8) & 0x0000ff00) | (x & 0x000000ff)) 319 1.21 mrg 320 1.19 christos #define MTREE_MAXGID 5000 321 1.19 christos #define MTREE_MAXUID 5000 322 1.21 mrg #define MTREE_MAXMODE (MBITS + 1) 323 1.38 tv #if HAVE_STRUCT_STAT_ST_FLAGS 324 1.21 mrg #define MTREE_MAXFLAGS (FLAGS2INDEX(CH_MASK) + 1) /* 1808 */ 325 1.38 tv #else 326 1.38 tv #define MTREE_MAXFLAGS 1 327 1.38 tv #endif 328 1.19 christos #define MTREE_MAXS 16 329 1.1 cgd 330 1.5 cgd static int 331 1.73 christos statd(FILE *fp, FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, 332 1.73 christos u_long *pflags) 333 1.1 cgd { 334 1.13 lukem FTSENT *p; 335 1.13 lukem gid_t sgid; 336 1.13 lukem uid_t suid; 337 1.13 lukem mode_t smode; 338 1.38 tv u_long sflags = 0; 339 1.65 christos const char *name = NULL; 340 1.1 cgd gid_t savegid; 341 1.1 cgd uid_t saveuid; 342 1.1 cgd mode_t savemode; 343 1.18 mrg u_long saveflags; 344 1.18 mrg u_short maxgid, maxuid, maxmode, maxflags; 345 1.19 christos u_short g[MTREE_MAXGID], u[MTREE_MAXUID], 346 1.19 christos m[MTREE_MAXMODE], f[MTREE_MAXFLAGS]; 347 1.36 lukem static int first = 1; 348 1.1 cgd 349 1.36 lukem savegid = *pgid; 350 1.36 lukem saveuid = *puid; 351 1.36 lukem savemode = *pmode; 352 1.36 lukem saveflags = *pflags; 353 1.5 cgd if ((p = fts_children(t, 0)) == NULL) { 354 1.5 cgd if (errno) 355 1.17 wsanchez mtree_err("%s: %s", RP(parent), strerror(errno)); 356 1.5 cgd return (1); 357 1.1 cgd } 358 1.1 cgd 359 1.13 lukem memset(g, 0, sizeof(g)); 360 1.13 lukem memset(u, 0, sizeof(u)); 361 1.13 lukem memset(m, 0, sizeof(m)); 362 1.18 mrg memset(f, 0, sizeof(f)); 363 1.1 cgd 364 1.18 mrg maxuid = maxgid = maxmode = maxflags = 0; 365 1.1 cgd for (; p; p = p->fts_link) { 366 1.68 christos if (flavor == F_NETBSD6 || !dflag || 367 1.68 christos (dflag && S_ISDIR(p->fts_statp->st_mode))) { 368 1.68 christos smode = p->fts_statp->st_mode & MBITS; 369 1.68 christos if (smode < MTREE_MAXMODE && ++m[smode] > maxmode) { 370 1.68 christos savemode = smode; 371 1.68 christos maxmode = m[smode]; 372 1.68 christos } 373 1.68 christos sgid = p->fts_statp->st_gid; 374 1.68 christos if (sgid < MTREE_MAXGID && ++g[sgid] > maxgid) { 375 1.68 christos savegid = sgid; 376 1.68 christos maxgid = g[sgid]; 377 1.68 christos } 378 1.68 christos suid = p->fts_statp->st_uid; 379 1.68 christos if (suid < MTREE_MAXUID && ++u[suid] > maxuid) { 380 1.68 christos saveuid = suid; 381 1.68 christos maxuid = u[suid]; 382 1.68 christos } 383 1.18 mrg 384 1.38 tv #if HAVE_STRUCT_STAT_ST_FLAGS 385 1.68 christos sflags = FLAGS2INDEX(p->fts_statp->st_flags); 386 1.68 christos if (sflags < MTREE_MAXFLAGS && ++f[sflags] > maxflags) { 387 1.68 christos saveflags = p->fts_statp->st_flags; 388 1.68 christos maxflags = f[sflags]; 389 1.68 christos } 390 1.68 christos #endif 391 1.18 mrg } 392 1.1 cgd } 393 1.36 lukem /* 394 1.36 lukem * If the /set record is the same as the last one we do not need to 395 1.36 lukem * output a new one. So first we check to see if anything changed. 396 1.36 lukem * Note that we always output a /set record for the first directory. 397 1.36 lukem */ 398 1.36 lukem if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) || 399 1.36 lukem ((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) || 400 1.36 lukem ((keys & F_MODE) && (*pmode != savemode)) || 401 1.36 lukem ((keys & F_FLAGS) && (*pflags != saveflags)) || 402 1.36 lukem first) { 403 1.36 lukem first = 0; 404 1.68 christos if (flavor != F_NETBSD6 && dflag) 405 1.73 christos fprintf(fp, "/set type=dir"); 406 1.68 christos else 407 1.73 christos fprintf(fp, "/set type=file"); 408 1.36 lukem if (keys & (F_UID | F_UNAME)) { 409 1.36 lukem if (keys & F_UNAME && 410 1.36 lukem (name = user_from_uid(saveuid, 1)) != NULL) 411 1.73 christos fprintf(fp, " uname=%s", name); 412 1.65 christos if (keys & F_UID || (keys & F_UNAME && name == NULL)) 413 1.73 christos fprintf(fp, " uid=%lu", (u_long)saveuid); 414 1.36 lukem } 415 1.36 lukem if (keys & (F_GID | F_GNAME)) { 416 1.36 lukem if (keys & F_GNAME && 417 1.36 lukem (name = group_from_gid(savegid, 1)) != NULL) 418 1.73 christos fprintf(fp, " gname=%s", name); 419 1.65 christos if (keys & F_GID || (keys & F_GNAME && name == NULL)) 420 1.73 christos fprintf(fp, " gid=%lu", (u_long)savegid); 421 1.36 lukem } 422 1.36 lukem if (keys & F_MODE) 423 1.73 christos fprintf(fp, " mode=%#lo", (u_long)savemode); 424 1.36 lukem if (keys & F_NLINK) 425 1.73 christos fprintf(fp, " nlink=1"); 426 1.59 spz if (keys & F_FLAGS) { 427 1.59 spz char *str = flags_to_string(saveflags, "none"); 428 1.73 christos fprintf(fp, " flags=%s", str); 429 1.59 spz free(str); 430 1.59 spz } 431 1.73 christos fprintf(fp, "\n"); 432 1.36 lukem *puid = saveuid; 433 1.36 lukem *pgid = savegid; 434 1.36 lukem *pmode = savemode; 435 1.36 lukem *pflags = saveflags; 436 1.15 ross } 437 1.5 cgd return (0); 438 1.1 cgd } 439 1.1 cgd 440 1.5 cgd void 441 1.73 christos output(FILE *fp, int indent, int *offset, const char *fmt, ...) 442 1.5 cgd { 443 1.5 cgd va_list ap; 444 1.5 cgd char buf[1024]; 445 1.29 simonb 446 1.5 cgd va_start(ap, fmt); 447 1.36 lukem vsnprintf(buf, sizeof(buf), fmt, ap); 448 1.5 cgd va_end(ap); 449 1.5 cgd 450 1.8 cgd if (*offset + strlen(buf) > MAXLINELEN - 3) { 451 1.73 christos fprintf(fp, " \\\n%*s", INDENTNAMELEN + indent, ""); 452 1.63 christos *offset = INDENTNAMELEN + indent; 453 1.5 cgd } 454 1.73 christos *offset += fprintf(fp, " %s", buf) + 1; 455 1.1 cgd } 456