1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * logadm/fn.c -- "filename" string module 27*7c478bd9Sstevel@tonic-gate * 28*7c478bd9Sstevel@tonic-gate * this file contains routines for the manipulation of filenames. 29*7c478bd9Sstevel@tonic-gate * they aren't particularly fast (at least they weren't designed 30*7c478bd9Sstevel@tonic-gate * for performance), but they are simple and put all the malloc/free 31*7c478bd9Sstevel@tonic-gate * stuff for these strings in a central place. most routines in 32*7c478bd9Sstevel@tonic-gate * logadm that return filenames return a struct fn, and most routines 33*7c478bd9Sstevel@tonic-gate * that return lists of strings return a struct fn_list. 34*7c478bd9Sstevel@tonic-gate */ 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include <stdio.h> 39*7c478bd9Sstevel@tonic-gate #include <libintl.h> 40*7c478bd9Sstevel@tonic-gate #include <strings.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 43*7c478bd9Sstevel@tonic-gate #include "err.h" 44*7c478bd9Sstevel@tonic-gate #include "fn.h" 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* 49*7c478bd9Sstevel@tonic-gate * constants controlling how we malloc space. bigger means fewer 50*7c478bd9Sstevel@tonic-gate * calls to malloc. smaller means less wasted space. 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate #define FN_MIN 1024 /* initial size of string buffers */ 53*7c478bd9Sstevel@tonic-gate #define FN_MAX 10240 /* maximum size allowed before fatal "overflow" error */ 54*7c478bd9Sstevel@tonic-gate #define FN_INC 1024 /* increments in buffer size as strings grow */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate /* info created by fn_new(), private to this module */ 57*7c478bd9Sstevel@tonic-gate struct fn { 58*7c478bd9Sstevel@tonic-gate char *fn_buf; /* first location in buf */ 59*7c478bd9Sstevel@tonic-gate char *fn_buflast; /* last location in buf */ 60*7c478bd9Sstevel@tonic-gate char *fn_rptr; /* read pointer (next unread character) */ 61*7c478bd9Sstevel@tonic-gate char *fn_wptr; /* write pointer (points at null terminator) */ 62*7c478bd9Sstevel@tonic-gate struct fn *fn_next; /* next in list */ 63*7c478bd9Sstevel@tonic-gate struct stat fn_stbuf; 64*7c478bd9Sstevel@tonic-gate int fn_n; 65*7c478bd9Sstevel@tonic-gate }; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* info created by fn_list_new(), private to this module */ 68*7c478bd9Sstevel@tonic-gate struct fn_list { 69*7c478bd9Sstevel@tonic-gate struct fn *fnl_first; /* first element of list */ 70*7c478bd9Sstevel@tonic-gate struct fn *fnl_last; /* last element of list */ 71*7c478bd9Sstevel@tonic-gate struct fn *fnl_rptr; /* read pointer for iterating through list */ 72*7c478bd9Sstevel@tonic-gate }; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * fn_new -- create a new filename buffer, possibly with initial contents 76*7c478bd9Sstevel@tonic-gate * 77*7c478bd9Sstevel@tonic-gate * use like this: 78*7c478bd9Sstevel@tonic-gate * struct fn *fnp = fn_new("this is a string"); 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate struct fn * 81*7c478bd9Sstevel@tonic-gate fn_new(const char *s) 82*7c478bd9Sstevel@tonic-gate { 83*7c478bd9Sstevel@tonic-gate struct fn *fnp = MALLOC(sizeof (struct fn)); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate fnp->fn_n = -1; 86*7c478bd9Sstevel@tonic-gate bzero(&fnp->fn_stbuf, sizeof (fnp->fn_stbuf)); 87*7c478bd9Sstevel@tonic-gate fnp->fn_next = NULL; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* if passed-in string contains at least 1 non-null character... */ 90*7c478bd9Sstevel@tonic-gate if (s && *s) { 91*7c478bd9Sstevel@tonic-gate int len = strlen(s); 92*7c478bd9Sstevel@tonic-gate int buflen = roundup(len + 1, FN_INC); 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate /* start with buffer filled with passed-in string */ 95*7c478bd9Sstevel@tonic-gate fnp->fn_buf = MALLOC(buflen); 96*7c478bd9Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[buflen - 1]; 97*7c478bd9Sstevel@tonic-gate (void) strlcpy(fnp->fn_buf, s, buflen); 98*7c478bd9Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 99*7c478bd9Sstevel@tonic-gate fnp->fn_wptr = &fnp->fn_buf[len]; 100*7c478bd9Sstevel@tonic-gate } else { 101*7c478bd9Sstevel@tonic-gate /* start with empty buffer */ 102*7c478bd9Sstevel@tonic-gate fnp->fn_buf = MALLOC(FN_MIN); 103*7c478bd9Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[FN_MIN - 1]; 104*7c478bd9Sstevel@tonic-gate *fnp->fn_buf = '\0'; 105*7c478bd9Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 106*7c478bd9Sstevel@tonic-gate fnp->fn_wptr = fnp->fn_buf; 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate return (fnp); 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * fn_dup -- duplicate a filename buffer 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate struct fn * 116*7c478bd9Sstevel@tonic-gate fn_dup(struct fn *fnp) 117*7c478bd9Sstevel@tonic-gate { 118*7c478bd9Sstevel@tonic-gate struct fn *ret = fn_new(fn_s(fnp)); 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate ret->fn_n = fnp->fn_n; 121*7c478bd9Sstevel@tonic-gate ret->fn_stbuf = fnp->fn_stbuf; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate return (ret); 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* 127*7c478bd9Sstevel@tonic-gate * fn_dirname -- return the dirname part of a filename 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate struct fn * 130*7c478bd9Sstevel@tonic-gate fn_dirname(struct fn *fnp) 131*7c478bd9Sstevel@tonic-gate { 132*7c478bd9Sstevel@tonic-gate char *ptr; 133*7c478bd9Sstevel@tonic-gate struct fn *ret; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate if ((ptr = strrchr(fn_s(fnp), '/')) == NULL) 136*7c478bd9Sstevel@tonic-gate return (fn_new(".")); 137*7c478bd9Sstevel@tonic-gate else { 138*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 139*7c478bd9Sstevel@tonic-gate ret = fn_new(fn_s(fnp)); 140*7c478bd9Sstevel@tonic-gate *ptr = '/'; 141*7c478bd9Sstevel@tonic-gate return (ret); 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * fn_setn -- set the "n" value for a filename 147*7c478bd9Sstevel@tonic-gate * 148*7c478bd9Sstevel@tonic-gate * the "n" value is initially -1, and is used by logadm to store 149*7c478bd9Sstevel@tonic-gate * the suffix for rotated log files. the function fn_list_popoldest() 150*7c478bd9Sstevel@tonic-gate * looks at these "n" values when sorting filenames to determine which 151*7c478bd9Sstevel@tonic-gate * old log file is the oldest and should be expired first. 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate void 154*7c478bd9Sstevel@tonic-gate fn_setn(struct fn *fnp, int n) 155*7c478bd9Sstevel@tonic-gate { 156*7c478bd9Sstevel@tonic-gate fnp->fn_n = n; 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate /* 160*7c478bd9Sstevel@tonic-gate * fn_setstat -- store a struct stat with a filename 161*7c478bd9Sstevel@tonic-gate * 162*7c478bd9Sstevel@tonic-gate * the glob functions typically fill in these struct stats since they 163*7c478bd9Sstevel@tonic-gate * have to stat while globbing anyway. just turned out to be a common 164*7c478bd9Sstevel@tonic-gate * piece of information that was conveniently stored with the associated 165*7c478bd9Sstevel@tonic-gate * filename. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate void 168*7c478bd9Sstevel@tonic-gate fn_setstat(struct fn *fnp, struct stat *stp) 169*7c478bd9Sstevel@tonic-gate { 170*7c478bd9Sstevel@tonic-gate fnp->fn_stbuf = *stp; 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate * fn_getstat -- return a pointer to the stat info stored by fn_setstat() 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate struct stat * 177*7c478bd9Sstevel@tonic-gate fn_getstat(struct fn *fnp) 178*7c478bd9Sstevel@tonic-gate { 179*7c478bd9Sstevel@tonic-gate return (&fnp->fn_stbuf); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /* 183*7c478bd9Sstevel@tonic-gate * fn_free -- free a filename buffer 184*7c478bd9Sstevel@tonic-gate */ 185*7c478bd9Sstevel@tonic-gate void 186*7c478bd9Sstevel@tonic-gate fn_free(struct fn *fnp) 187*7c478bd9Sstevel@tonic-gate { 188*7c478bd9Sstevel@tonic-gate if (fnp) { 189*7c478bd9Sstevel@tonic-gate if (fnp->fn_buf) 190*7c478bd9Sstevel@tonic-gate FREE(fnp->fn_buf); 191*7c478bd9Sstevel@tonic-gate FREE(fnp); 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * fn_renew -- reset a filename buffer 197*7c478bd9Sstevel@tonic-gate * 198*7c478bd9Sstevel@tonic-gate * calling fn_renew(fnp, s) is the same as calling: 199*7c478bd9Sstevel@tonic-gate * fn_free(fnp); 200*7c478bd9Sstevel@tonic-gate * fn_new(s); 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate void 203*7c478bd9Sstevel@tonic-gate fn_renew(struct fn *fnp, const char *s) 204*7c478bd9Sstevel@tonic-gate { 205*7c478bd9Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_wptr = fnp->fn_buf; 206*7c478bd9Sstevel@tonic-gate fn_puts(fnp, s); 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate /* 210*7c478bd9Sstevel@tonic-gate * fn_putc -- append a character to a filename 211*7c478bd9Sstevel@tonic-gate * 212*7c478bd9Sstevel@tonic-gate * this is the function that handles growing the filename buffer 213*7c478bd9Sstevel@tonic-gate * automatically and calling err() if it overflows. 214*7c478bd9Sstevel@tonic-gate */ 215*7c478bd9Sstevel@tonic-gate void 216*7c478bd9Sstevel@tonic-gate fn_putc(struct fn *fnp, int c) 217*7c478bd9Sstevel@tonic-gate { 218*7c478bd9Sstevel@tonic-gate if (fnp->fn_wptr >= fnp->fn_buflast) { 219*7c478bd9Sstevel@tonic-gate int buflen = fnp->fn_buflast + 1 - fnp->fn_buf; 220*7c478bd9Sstevel@tonic-gate char *newbuf; 221*7c478bd9Sstevel@tonic-gate char *src; 222*7c478bd9Sstevel@tonic-gate char *dst; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* overflow, allocate more space or die if at FN_MAX */ 225*7c478bd9Sstevel@tonic-gate if (buflen >= FN_MAX) 226*7c478bd9Sstevel@tonic-gate err(0, "fn buffer overflow"); 227*7c478bd9Sstevel@tonic-gate buflen += FN_INC; 228*7c478bd9Sstevel@tonic-gate newbuf = MALLOC(buflen); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* copy string into new buffer */ 231*7c478bd9Sstevel@tonic-gate src = fnp->fn_buf; 232*7c478bd9Sstevel@tonic-gate dst = newbuf; 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* just copy up to wptr, rest is history anyway */ 235*7c478bd9Sstevel@tonic-gate while (src < fnp->fn_wptr) 236*7c478bd9Sstevel@tonic-gate *dst++ = *src++; 237*7c478bd9Sstevel@tonic-gate fnp->fn_rptr = &newbuf[fnp->fn_rptr - fnp->fn_buf]; 238*7c478bd9Sstevel@tonic-gate FREE(fnp->fn_buf); 239*7c478bd9Sstevel@tonic-gate fnp->fn_buf = newbuf; 240*7c478bd9Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[buflen - 1]; 241*7c478bd9Sstevel@tonic-gate fnp->fn_wptr = dst; 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate *fnp->fn_wptr++ = c; 244*7c478bd9Sstevel@tonic-gate *fnp->fn_wptr = '\0'; 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* 248*7c478bd9Sstevel@tonic-gate * fn_puts -- append a string to a filename 249*7c478bd9Sstevel@tonic-gate */ 250*7c478bd9Sstevel@tonic-gate void 251*7c478bd9Sstevel@tonic-gate fn_puts(struct fn *fnp, const char *s) 252*7c478bd9Sstevel@tonic-gate { 253*7c478bd9Sstevel@tonic-gate /* non-optimal, but simple! */ 254*7c478bd9Sstevel@tonic-gate while (s && *s) 255*7c478bd9Sstevel@tonic-gate fn_putc(fnp, *s++); 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * fn_putfn -- append a filename buffer to a filename 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate void 262*7c478bd9Sstevel@tonic-gate fn_putfn(struct fn *fnp, struct fn *srcfnp) 263*7c478bd9Sstevel@tonic-gate { 264*7c478bd9Sstevel@tonic-gate int c; 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate fn_rewind(srcfnp); 267*7c478bd9Sstevel@tonic-gate while (c = fn_getc(srcfnp)) 268*7c478bd9Sstevel@tonic-gate fn_putc(fnp, c); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate /* 272*7c478bd9Sstevel@tonic-gate * fn_rewind -- reset the "read pointer" to the beginning of a filename 273*7c478bd9Sstevel@tonic-gate */ 274*7c478bd9Sstevel@tonic-gate void 275*7c478bd9Sstevel@tonic-gate fn_rewind(struct fn *fnp) 276*7c478bd9Sstevel@tonic-gate { 277*7c478bd9Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate /* 281*7c478bd9Sstevel@tonic-gate * fn_getc -- "read" the next character of a filename 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate int 284*7c478bd9Sstevel@tonic-gate fn_getc(struct fn *fnp) 285*7c478bd9Sstevel@tonic-gate { 286*7c478bd9Sstevel@tonic-gate if (fnp->fn_rptr > fnp->fn_buflast || *fnp->fn_rptr == '\0') 287*7c478bd9Sstevel@tonic-gate return (0); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate return (*fnp->fn_rptr++); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* 293*7c478bd9Sstevel@tonic-gate * fn_peekc -- "peek" at the next character of a filename 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate int 296*7c478bd9Sstevel@tonic-gate fn_peekc(struct fn *fnp) 297*7c478bd9Sstevel@tonic-gate { 298*7c478bd9Sstevel@tonic-gate if (fnp->fn_rptr > fnp->fn_buflast || *fnp->fn_rptr == '\0') 299*7c478bd9Sstevel@tonic-gate return (0); 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate return (*fnp->fn_rptr); 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * fn_s -- return a pointer to a null-terminated string containing the filename 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate char * 308*7c478bd9Sstevel@tonic-gate fn_s(struct fn *fnp) 309*7c478bd9Sstevel@tonic-gate { 310*7c478bd9Sstevel@tonic-gate return (fnp->fn_buf); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate /* 314*7c478bd9Sstevel@tonic-gate * fn_list_new -- create a new list of filenames 315*7c478bd9Sstevel@tonic-gate * 316*7c478bd9Sstevel@tonic-gate * by convention, an empty list is represented by an allocated 317*7c478bd9Sstevel@tonic-gate * struct fn_list which contains a NULL linked list, rather than 318*7c478bd9Sstevel@tonic-gate * by a NULL fn_list pointer. in other words: 319*7c478bd9Sstevel@tonic-gate * 320*7c478bd9Sstevel@tonic-gate * struct fn_list *fnlp = some_func_returning_a_list(); 321*7c478bd9Sstevel@tonic-gate * if (fn_list_empty(fnlp)) 322*7c478bd9Sstevel@tonic-gate * ... 323*7c478bd9Sstevel@tonic-gate * 324*7c478bd9Sstevel@tonic-gate * is preferable to checking if the fnlp returned is NULL. 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate struct fn_list * 327*7c478bd9Sstevel@tonic-gate fn_list_new(const char * const *slist) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate struct fn_list *fnlp = MALLOC(sizeof (struct fn_list)); 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate fnlp->fnl_first = fnlp->fnl_last = fnlp->fnl_rptr = NULL; 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate while (slist && *slist) 334*7c478bd9Sstevel@tonic-gate fn_list_adds(fnlp, *slist++); 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate return (fnlp); 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * fn_list_dup -- duplicate a list of filenames 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate struct fn_list * 343*7c478bd9Sstevel@tonic-gate fn_list_dup(struct fn_list *fnlp) 344*7c478bd9Sstevel@tonic-gate { 345*7c478bd9Sstevel@tonic-gate struct fn_list *ret = fn_list_new(NULL); 346*7c478bd9Sstevel@tonic-gate struct fn *fnp; 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate fn_list_rewind(fnlp); 349*7c478bd9Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 350*7c478bd9Sstevel@tonic-gate fn_list_addfn(ret, fn_dup(fnp)); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate return (ret); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* 356*7c478bd9Sstevel@tonic-gate * fn_list_free -- free a list of filenames 357*7c478bd9Sstevel@tonic-gate */ 358*7c478bd9Sstevel@tonic-gate void 359*7c478bd9Sstevel@tonic-gate fn_list_free(struct fn_list *fnlp) 360*7c478bd9Sstevel@tonic-gate { 361*7c478bd9Sstevel@tonic-gate struct fn *fnp; 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate fn_list_rewind(fnlp); 364*7c478bd9Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 365*7c478bd9Sstevel@tonic-gate fn_free(fnp); 366*7c478bd9Sstevel@tonic-gate FREE(fnlp); 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate /* 370*7c478bd9Sstevel@tonic-gate * fn_list_adds -- add a string to a list of filenames 371*7c478bd9Sstevel@tonic-gate */ 372*7c478bd9Sstevel@tonic-gate void 373*7c478bd9Sstevel@tonic-gate fn_list_adds(struct fn_list *fnlp, const char *s) 374*7c478bd9Sstevel@tonic-gate { 375*7c478bd9Sstevel@tonic-gate fn_list_addfn(fnlp, fn_new(s)); 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * fn_list_addfn -- add a filename (i.e. struct fn *) to a list of filenames 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate void 382*7c478bd9Sstevel@tonic-gate fn_list_addfn(struct fn_list *fnlp, struct fn *fnp) 383*7c478bd9Sstevel@tonic-gate { 384*7c478bd9Sstevel@tonic-gate fnp->fn_next = NULL; 385*7c478bd9Sstevel@tonic-gate if (fnlp->fnl_first == NULL) 386*7c478bd9Sstevel@tonic-gate fnlp->fnl_first = fnlp->fnl_last = fnlp->fnl_rptr = fnp; 387*7c478bd9Sstevel@tonic-gate else { 388*7c478bd9Sstevel@tonic-gate fnlp->fnl_last->fn_next = fnp; 389*7c478bd9Sstevel@tonic-gate fnlp->fnl_last = fnp; 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate /* 394*7c478bd9Sstevel@tonic-gate * fn_list_rewind -- reset the "read pointer" to the beginning of the list 395*7c478bd9Sstevel@tonic-gate */ 396*7c478bd9Sstevel@tonic-gate void 397*7c478bd9Sstevel@tonic-gate fn_list_rewind(struct fn_list *fnlp) 398*7c478bd9Sstevel@tonic-gate { 399*7c478bd9Sstevel@tonic-gate fnlp->fnl_rptr = fnlp->fnl_first; 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* 403*7c478bd9Sstevel@tonic-gate * fn_list_next -- return the filename at the read pointer and advance it 404*7c478bd9Sstevel@tonic-gate */ 405*7c478bd9Sstevel@tonic-gate struct fn * 406*7c478bd9Sstevel@tonic-gate fn_list_next(struct fn_list *fnlp) 407*7c478bd9Sstevel@tonic-gate { 408*7c478bd9Sstevel@tonic-gate struct fn *ret = fnlp->fnl_rptr; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate if (fnlp->fnl_rptr == fnlp->fnl_last) 411*7c478bd9Sstevel@tonic-gate fnlp->fnl_rptr = NULL; 412*7c478bd9Sstevel@tonic-gate else if (fnlp->fnl_rptr != NULL) 413*7c478bd9Sstevel@tonic-gate fnlp->fnl_rptr = fnlp->fnl_rptr->fn_next; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate return (ret); 416*7c478bd9Sstevel@tonic-gate } 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate /* 419*7c478bd9Sstevel@tonic-gate * fn_list_addfn_list -- move filenames from fnlp2 to end of fnlp 420*7c478bd9Sstevel@tonic-gate * 421*7c478bd9Sstevel@tonic-gate * frees fnlp2 after moving all the filenames off of it. 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate void 424*7c478bd9Sstevel@tonic-gate fn_list_addfn_list(struct fn_list *fnlp, struct fn_list *fnlp2) 425*7c478bd9Sstevel@tonic-gate { 426*7c478bd9Sstevel@tonic-gate struct fn *fnp2 = fnlp2->fnl_first; 427*7c478bd9Sstevel@tonic-gate struct fn *nextfnp2; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /* for each fn in the second list... */ 430*7c478bd9Sstevel@tonic-gate while (fnp2) { 431*7c478bd9Sstevel@tonic-gate if (fnp2 == fnlp2->fnl_last) 432*7c478bd9Sstevel@tonic-gate nextfnp2 = NULL; 433*7c478bd9Sstevel@tonic-gate else 434*7c478bd9Sstevel@tonic-gate nextfnp2 = fnp2->fn_next; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate /* append it to the first list */ 437*7c478bd9Sstevel@tonic-gate fn_list_addfn(fnlp, fnp2); 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate fnp2 = nextfnp2; 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate /* all the fn's were moved off the second list */ 442*7c478bd9Sstevel@tonic-gate fnlp2->fnl_first = fnlp2->fnl_last = fnlp2->fnl_rptr = NULL; 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate /* done with the second list */ 445*7c478bd9Sstevel@tonic-gate fn_list_free(fnlp2); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate /* 449*7c478bd9Sstevel@tonic-gate * fn_list_appendrange -- append a range of characters to each filename in list 450*7c478bd9Sstevel@tonic-gate * 451*7c478bd9Sstevel@tonic-gate * range of characters appended is the character at *s up to but not including 452*7c478bd9Sstevel@tonic-gate * the character at *limit. NULL termination is not required. 453*7c478bd9Sstevel@tonic-gate */ 454*7c478bd9Sstevel@tonic-gate void 455*7c478bd9Sstevel@tonic-gate fn_list_appendrange(struct fn_list *fnlp, const char *s, const char *limit) 456*7c478bd9Sstevel@tonic-gate { 457*7c478bd9Sstevel@tonic-gate struct fn *fnp = fnlp->fnl_first; 458*7c478bd9Sstevel@tonic-gate struct fn *nextfnp; 459*7c478bd9Sstevel@tonic-gate const char *ptr; 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate /* for each fn in the list... */ 462*7c478bd9Sstevel@tonic-gate while (fnp) { 463*7c478bd9Sstevel@tonic-gate if (fnp == fnlp->fnl_last) 464*7c478bd9Sstevel@tonic-gate nextfnp = NULL; 465*7c478bd9Sstevel@tonic-gate else 466*7c478bd9Sstevel@tonic-gate nextfnp = fnp->fn_next; 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /* append the range */ 469*7c478bd9Sstevel@tonic-gate for (ptr = s; ptr < limit; ptr++) 470*7c478bd9Sstevel@tonic-gate fn_putc(fnp, *ptr); 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate fnp = nextfnp; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate /* 477*7c478bd9Sstevel@tonic-gate * fn_list_totalsize -- sum up all the st_size fields in the stat structs 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate size_t 480*7c478bd9Sstevel@tonic-gate fn_list_totalsize(struct fn_list *fnlp) 481*7c478bd9Sstevel@tonic-gate { 482*7c478bd9Sstevel@tonic-gate struct fn *fnp; 483*7c478bd9Sstevel@tonic-gate size_t ret = 0; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate fn_list_rewind(fnlp); 486*7c478bd9Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 487*7c478bd9Sstevel@tonic-gate ret += fnp->fn_stbuf.st_size; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate return (ret); 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate /* 493*7c478bd9Sstevel@tonic-gate * fn_list_popoldest -- remove oldest file from list and return it 494*7c478bd9Sstevel@tonic-gate * 495*7c478bd9Sstevel@tonic-gate * this function uses the "n" values (set by fn_setn()) to determine 496*7c478bd9Sstevel@tonic-gate * which file is oldest, or when there's a tie it turns to the modification 497*7c478bd9Sstevel@tonic-gate * times in the stat structs, or when there's still a tie lexical sorting. 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate struct fn * 500*7c478bd9Sstevel@tonic-gate fn_list_popoldest(struct fn_list *fnlp) 501*7c478bd9Sstevel@tonic-gate { 502*7c478bd9Sstevel@tonic-gate struct fn *fnp; 503*7c478bd9Sstevel@tonic-gate struct fn *ret = NULL; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate fn_list_rewind(fnlp); 506*7c478bd9Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 507*7c478bd9Sstevel@tonic-gate if (ret == NULL) 508*7c478bd9Sstevel@tonic-gate ret = fnp; 509*7c478bd9Sstevel@tonic-gate else if (fnp->fn_n > ret->fn_n || 510*7c478bd9Sstevel@tonic-gate (fnp->fn_n == ret->fn_n && 511*7c478bd9Sstevel@tonic-gate (fnp->fn_stbuf.st_mtime < ret->fn_stbuf.st_mtime || 512*7c478bd9Sstevel@tonic-gate ((fnp->fn_stbuf.st_mtime == ret->fn_stbuf.st_mtime && 513*7c478bd9Sstevel@tonic-gate strcmp(fnp->fn_buf, ret->fn_buf) > 0))))) 514*7c478bd9Sstevel@tonic-gate ret = fnp; 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate if (ret == NULL) 517*7c478bd9Sstevel@tonic-gate return (NULL); 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate /* oldest file is ret, remove it from list */ 520*7c478bd9Sstevel@tonic-gate if (fnlp->fnl_first == ret) 521*7c478bd9Sstevel@tonic-gate fnlp->fnl_first = ret->fn_next; 522*7c478bd9Sstevel@tonic-gate else { 523*7c478bd9Sstevel@tonic-gate fn_list_rewind(fnlp); 524*7c478bd9Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 525*7c478bd9Sstevel@tonic-gate if (fnp->fn_next == ret) { 526*7c478bd9Sstevel@tonic-gate fnp->fn_next = ret->fn_next; 527*7c478bd9Sstevel@tonic-gate break; 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate ret->fn_next = NULL; 532*7c478bd9Sstevel@tonic-gate return (ret); 533*7c478bd9Sstevel@tonic-gate } 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate /* 536*7c478bd9Sstevel@tonic-gate * fn_list_empty -- true if the list is empty 537*7c478bd9Sstevel@tonic-gate */ 538*7c478bd9Sstevel@tonic-gate boolean_t 539*7c478bd9Sstevel@tonic-gate fn_list_empty(struct fn_list *fnlp) 540*7c478bd9Sstevel@tonic-gate { 541*7c478bd9Sstevel@tonic-gate return (fnlp->fnl_first == NULL); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* 545*7c478bd9Sstevel@tonic-gate * fn_list_count -- return number of filenames in list 546*7c478bd9Sstevel@tonic-gate */ 547*7c478bd9Sstevel@tonic-gate int 548*7c478bd9Sstevel@tonic-gate fn_list_count(struct fn_list *fnlp) 549*7c478bd9Sstevel@tonic-gate { 550*7c478bd9Sstevel@tonic-gate int ret = 0; 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * if this operation were more common, we'd cache the count 554*7c478bd9Sstevel@tonic-gate * in the struct fn_list, but it isn't very common so we just 555*7c478bd9Sstevel@tonic-gate * count 'em up here 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate fn_list_rewind(fnlp); 558*7c478bd9Sstevel@tonic-gate while (fn_list_next(fnlp) != NULL) 559*7c478bd9Sstevel@tonic-gate ret++; 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate return (ret); 562*7c478bd9Sstevel@tonic-gate } 563