10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*2016Sbasabi * Common Development and Distribution License (the "License"). 6*2016Sbasabi * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*2016Sbasabi * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*2016Sbasabi * Use is subject to license terms. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * logadm/fn.c -- "filename" string module 260Sstevel@tonic-gate * 270Sstevel@tonic-gate * this file contains routines for the manipulation of filenames. 280Sstevel@tonic-gate * they aren't particularly fast (at least they weren't designed 290Sstevel@tonic-gate * for performance), but they are simple and put all the malloc/free 300Sstevel@tonic-gate * stuff for these strings in a central place. most routines in 310Sstevel@tonic-gate * logadm that return filenames return a struct fn, and most routines 320Sstevel@tonic-gate * that return lists of strings return a struct fn_list. 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <stdio.h> 380Sstevel@tonic-gate #include <libintl.h> 390Sstevel@tonic-gate #include <strings.h> 400Sstevel@tonic-gate #include <sys/types.h> 410Sstevel@tonic-gate #include <sys/stat.h> 420Sstevel@tonic-gate #include "err.h" 430Sstevel@tonic-gate #include "fn.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * constants controlling how we malloc space. bigger means fewer 490Sstevel@tonic-gate * calls to malloc. smaller means less wasted space. 500Sstevel@tonic-gate */ 510Sstevel@tonic-gate #define FN_MIN 1024 /* initial size of string buffers */ 520Sstevel@tonic-gate #define FN_MAX 10240 /* maximum size allowed before fatal "overflow" error */ 530Sstevel@tonic-gate #define FN_INC 1024 /* increments in buffer size as strings grow */ 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* info created by fn_new(), private to this module */ 560Sstevel@tonic-gate struct fn { 570Sstevel@tonic-gate char *fn_buf; /* first location in buf */ 580Sstevel@tonic-gate char *fn_buflast; /* last location in buf */ 590Sstevel@tonic-gate char *fn_rptr; /* read pointer (next unread character) */ 600Sstevel@tonic-gate char *fn_wptr; /* write pointer (points at null terminator) */ 610Sstevel@tonic-gate struct fn *fn_next; /* next in list */ 620Sstevel@tonic-gate struct stat fn_stbuf; 630Sstevel@tonic-gate int fn_n; 640Sstevel@tonic-gate }; 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* info created by fn_list_new(), private to this module */ 670Sstevel@tonic-gate struct fn_list { 680Sstevel@tonic-gate struct fn *fnl_first; /* first element of list */ 690Sstevel@tonic-gate struct fn *fnl_last; /* last element of list */ 700Sstevel@tonic-gate struct fn *fnl_rptr; /* read pointer for iterating through list */ 710Sstevel@tonic-gate }; 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * fn_new -- create a new filename buffer, possibly with initial contents 750Sstevel@tonic-gate * 760Sstevel@tonic-gate * use like this: 770Sstevel@tonic-gate * struct fn *fnp = fn_new("this is a string"); 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate struct fn * 800Sstevel@tonic-gate fn_new(const char *s) 810Sstevel@tonic-gate { 820Sstevel@tonic-gate struct fn *fnp = MALLOC(sizeof (struct fn)); 830Sstevel@tonic-gate 840Sstevel@tonic-gate fnp->fn_n = -1; 850Sstevel@tonic-gate bzero(&fnp->fn_stbuf, sizeof (fnp->fn_stbuf)); 860Sstevel@tonic-gate fnp->fn_next = NULL; 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* if passed-in string contains at least 1 non-null character... */ 890Sstevel@tonic-gate if (s && *s) { 900Sstevel@tonic-gate int len = strlen(s); 910Sstevel@tonic-gate int buflen = roundup(len + 1, FN_INC); 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* start with buffer filled with passed-in string */ 940Sstevel@tonic-gate fnp->fn_buf = MALLOC(buflen); 950Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[buflen - 1]; 960Sstevel@tonic-gate (void) strlcpy(fnp->fn_buf, s, buflen); 970Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 980Sstevel@tonic-gate fnp->fn_wptr = &fnp->fn_buf[len]; 990Sstevel@tonic-gate } else { 1000Sstevel@tonic-gate /* start with empty buffer */ 1010Sstevel@tonic-gate fnp->fn_buf = MALLOC(FN_MIN); 1020Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[FN_MIN - 1]; 1030Sstevel@tonic-gate *fnp->fn_buf = '\0'; 1040Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 1050Sstevel@tonic-gate fnp->fn_wptr = fnp->fn_buf; 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate return (fnp); 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * fn_dup -- duplicate a filename buffer 1130Sstevel@tonic-gate */ 1140Sstevel@tonic-gate struct fn * 1150Sstevel@tonic-gate fn_dup(struct fn *fnp) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate struct fn *ret = fn_new(fn_s(fnp)); 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate ret->fn_n = fnp->fn_n; 1200Sstevel@tonic-gate ret->fn_stbuf = fnp->fn_stbuf; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate return (ret); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* 1260Sstevel@tonic-gate * fn_dirname -- return the dirname part of a filename 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate struct fn * 1290Sstevel@tonic-gate fn_dirname(struct fn *fnp) 1300Sstevel@tonic-gate { 1310Sstevel@tonic-gate char *ptr; 1320Sstevel@tonic-gate struct fn *ret; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate if ((ptr = strrchr(fn_s(fnp), '/')) == NULL) 1350Sstevel@tonic-gate return (fn_new(".")); 1360Sstevel@tonic-gate else { 1370Sstevel@tonic-gate *ptr = '\0'; 1380Sstevel@tonic-gate ret = fn_new(fn_s(fnp)); 1390Sstevel@tonic-gate *ptr = '/'; 1400Sstevel@tonic-gate return (ret); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate /* 1450Sstevel@tonic-gate * fn_setn -- set the "n" value for a filename 1460Sstevel@tonic-gate * 1470Sstevel@tonic-gate * the "n" value is initially -1, and is used by logadm to store 1480Sstevel@tonic-gate * the suffix for rotated log files. the function fn_list_popoldest() 1490Sstevel@tonic-gate * looks at these "n" values when sorting filenames to determine which 1500Sstevel@tonic-gate * old log file is the oldest and should be expired first. 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate void 1530Sstevel@tonic-gate fn_setn(struct fn *fnp, int n) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate fnp->fn_n = n; 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * fn_setstat -- store a struct stat with a filename 1600Sstevel@tonic-gate * 1610Sstevel@tonic-gate * the glob functions typically fill in these struct stats since they 1620Sstevel@tonic-gate * have to stat while globbing anyway. just turned out to be a common 1630Sstevel@tonic-gate * piece of information that was conveniently stored with the associated 1640Sstevel@tonic-gate * filename. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate void 1670Sstevel@tonic-gate fn_setstat(struct fn *fnp, struct stat *stp) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate fnp->fn_stbuf = *stp; 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate /* 1730Sstevel@tonic-gate * fn_getstat -- return a pointer to the stat info stored by fn_setstat() 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate struct stat * 1760Sstevel@tonic-gate fn_getstat(struct fn *fnp) 1770Sstevel@tonic-gate { 1780Sstevel@tonic-gate return (&fnp->fn_stbuf); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * fn_free -- free a filename buffer 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate void 1850Sstevel@tonic-gate fn_free(struct fn *fnp) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate if (fnp) { 1880Sstevel@tonic-gate if (fnp->fn_buf) 1890Sstevel@tonic-gate FREE(fnp->fn_buf); 1900Sstevel@tonic-gate FREE(fnp); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * fn_renew -- reset a filename buffer 1960Sstevel@tonic-gate * 1970Sstevel@tonic-gate * calling fn_renew(fnp, s) is the same as calling: 1980Sstevel@tonic-gate * fn_free(fnp); 1990Sstevel@tonic-gate * fn_new(s); 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate void 2020Sstevel@tonic-gate fn_renew(struct fn *fnp, const char *s) 2030Sstevel@tonic-gate { 2040Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_wptr = fnp->fn_buf; 2050Sstevel@tonic-gate fn_puts(fnp, s); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * fn_putc -- append a character to a filename 2100Sstevel@tonic-gate * 2110Sstevel@tonic-gate * this is the function that handles growing the filename buffer 2120Sstevel@tonic-gate * automatically and calling err() if it overflows. 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate void 2150Sstevel@tonic-gate fn_putc(struct fn *fnp, int c) 2160Sstevel@tonic-gate { 2170Sstevel@tonic-gate if (fnp->fn_wptr >= fnp->fn_buflast) { 2180Sstevel@tonic-gate int buflen = fnp->fn_buflast + 1 - fnp->fn_buf; 2190Sstevel@tonic-gate char *newbuf; 2200Sstevel@tonic-gate char *src; 2210Sstevel@tonic-gate char *dst; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate /* overflow, allocate more space or die if at FN_MAX */ 2240Sstevel@tonic-gate if (buflen >= FN_MAX) 2250Sstevel@tonic-gate err(0, "fn buffer overflow"); 2260Sstevel@tonic-gate buflen += FN_INC; 2270Sstevel@tonic-gate newbuf = MALLOC(buflen); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* copy string into new buffer */ 2300Sstevel@tonic-gate src = fnp->fn_buf; 2310Sstevel@tonic-gate dst = newbuf; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* just copy up to wptr, rest is history anyway */ 2340Sstevel@tonic-gate while (src < fnp->fn_wptr) 2350Sstevel@tonic-gate *dst++ = *src++; 2360Sstevel@tonic-gate fnp->fn_rptr = &newbuf[fnp->fn_rptr - fnp->fn_buf]; 2370Sstevel@tonic-gate FREE(fnp->fn_buf); 2380Sstevel@tonic-gate fnp->fn_buf = newbuf; 2390Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[buflen - 1]; 2400Sstevel@tonic-gate fnp->fn_wptr = dst; 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate *fnp->fn_wptr++ = c; 2430Sstevel@tonic-gate *fnp->fn_wptr = '\0'; 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * fn_puts -- append a string to a filename 2480Sstevel@tonic-gate */ 2490Sstevel@tonic-gate void 2500Sstevel@tonic-gate fn_puts(struct fn *fnp, const char *s) 2510Sstevel@tonic-gate { 2520Sstevel@tonic-gate /* non-optimal, but simple! */ 2530Sstevel@tonic-gate while (s && *s) 2540Sstevel@tonic-gate fn_putc(fnp, *s++); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * fn_putfn -- append a filename buffer to a filename 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate void 2610Sstevel@tonic-gate fn_putfn(struct fn *fnp, struct fn *srcfnp) 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate int c; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate fn_rewind(srcfnp); 2660Sstevel@tonic-gate while (c = fn_getc(srcfnp)) 2670Sstevel@tonic-gate fn_putc(fnp, c); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * fn_rewind -- reset the "read pointer" to the beginning of a filename 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate void 2740Sstevel@tonic-gate fn_rewind(struct fn *fnp) 2750Sstevel@tonic-gate { 2760Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2800Sstevel@tonic-gate * fn_getc -- "read" the next character of a filename 2810Sstevel@tonic-gate */ 2820Sstevel@tonic-gate int 2830Sstevel@tonic-gate fn_getc(struct fn *fnp) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate if (fnp->fn_rptr > fnp->fn_buflast || *fnp->fn_rptr == '\0') 2860Sstevel@tonic-gate return (0); 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate return (*fnp->fn_rptr++); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * fn_peekc -- "peek" at the next character of a filename 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate int 2950Sstevel@tonic-gate fn_peekc(struct fn *fnp) 2960Sstevel@tonic-gate { 2970Sstevel@tonic-gate if (fnp->fn_rptr > fnp->fn_buflast || *fnp->fn_rptr == '\0') 2980Sstevel@tonic-gate return (0); 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate return (*fnp->fn_rptr); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * fn_s -- return a pointer to a null-terminated string containing the filename 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate char * 3070Sstevel@tonic-gate fn_s(struct fn *fnp) 3080Sstevel@tonic-gate { 3090Sstevel@tonic-gate return (fnp->fn_buf); 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate /* 3130Sstevel@tonic-gate * fn_list_new -- create a new list of filenames 3140Sstevel@tonic-gate * 3150Sstevel@tonic-gate * by convention, an empty list is represented by an allocated 3160Sstevel@tonic-gate * struct fn_list which contains a NULL linked list, rather than 3170Sstevel@tonic-gate * by a NULL fn_list pointer. in other words: 3180Sstevel@tonic-gate * 3190Sstevel@tonic-gate * struct fn_list *fnlp = some_func_returning_a_list(); 3200Sstevel@tonic-gate * if (fn_list_empty(fnlp)) 3210Sstevel@tonic-gate * ... 3220Sstevel@tonic-gate * 3230Sstevel@tonic-gate * is preferable to checking if the fnlp returned is NULL. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate struct fn_list * 3260Sstevel@tonic-gate fn_list_new(const char * const *slist) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate struct fn_list *fnlp = MALLOC(sizeof (struct fn_list)); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate fnlp->fnl_first = fnlp->fnl_last = fnlp->fnl_rptr = NULL; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate while (slist && *slist) 3330Sstevel@tonic-gate fn_list_adds(fnlp, *slist++); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate return (fnlp); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * fn_list_dup -- duplicate a list of filenames 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate struct fn_list * 3420Sstevel@tonic-gate fn_list_dup(struct fn_list *fnlp) 3430Sstevel@tonic-gate { 3440Sstevel@tonic-gate struct fn_list *ret = fn_list_new(NULL); 3450Sstevel@tonic-gate struct fn *fnp; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate fn_list_rewind(fnlp); 3480Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 3490Sstevel@tonic-gate fn_list_addfn(ret, fn_dup(fnp)); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate return (ret); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * fn_list_free -- free a list of filenames 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate void 3580Sstevel@tonic-gate fn_list_free(struct fn_list *fnlp) 3590Sstevel@tonic-gate { 3600Sstevel@tonic-gate struct fn *fnp; 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate fn_list_rewind(fnlp); 3630Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 3640Sstevel@tonic-gate fn_free(fnp); 3650Sstevel@tonic-gate FREE(fnlp); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * fn_list_adds -- add a string to a list of filenames 3700Sstevel@tonic-gate */ 3710Sstevel@tonic-gate void 3720Sstevel@tonic-gate fn_list_adds(struct fn_list *fnlp, const char *s) 3730Sstevel@tonic-gate { 3740Sstevel@tonic-gate fn_list_addfn(fnlp, fn_new(s)); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate /* 3780Sstevel@tonic-gate * fn_list_addfn -- add a filename (i.e. struct fn *) to a list of filenames 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate void 3810Sstevel@tonic-gate fn_list_addfn(struct fn_list *fnlp, struct fn *fnp) 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate fnp->fn_next = NULL; 3840Sstevel@tonic-gate if (fnlp->fnl_first == NULL) 3850Sstevel@tonic-gate fnlp->fnl_first = fnlp->fnl_last = fnlp->fnl_rptr = fnp; 3860Sstevel@tonic-gate else { 3870Sstevel@tonic-gate fnlp->fnl_last->fn_next = fnp; 3880Sstevel@tonic-gate fnlp->fnl_last = fnp; 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /* 3930Sstevel@tonic-gate * fn_list_rewind -- reset the "read pointer" to the beginning of the list 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate void 3960Sstevel@tonic-gate fn_list_rewind(struct fn_list *fnlp) 3970Sstevel@tonic-gate { 3980Sstevel@tonic-gate fnlp->fnl_rptr = fnlp->fnl_first; 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate /* 4020Sstevel@tonic-gate * fn_list_next -- return the filename at the read pointer and advance it 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate struct fn * 4050Sstevel@tonic-gate fn_list_next(struct fn_list *fnlp) 4060Sstevel@tonic-gate { 4070Sstevel@tonic-gate struct fn *ret = fnlp->fnl_rptr; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (fnlp->fnl_rptr == fnlp->fnl_last) 4100Sstevel@tonic-gate fnlp->fnl_rptr = NULL; 4110Sstevel@tonic-gate else if (fnlp->fnl_rptr != NULL) 4120Sstevel@tonic-gate fnlp->fnl_rptr = fnlp->fnl_rptr->fn_next; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate return (ret); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * fn_list_addfn_list -- move filenames from fnlp2 to end of fnlp 4190Sstevel@tonic-gate * 4200Sstevel@tonic-gate * frees fnlp2 after moving all the filenames off of it. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate void 4230Sstevel@tonic-gate fn_list_addfn_list(struct fn_list *fnlp, struct fn_list *fnlp2) 4240Sstevel@tonic-gate { 4250Sstevel@tonic-gate struct fn *fnp2 = fnlp2->fnl_first; 4260Sstevel@tonic-gate struct fn *nextfnp2; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate /* for each fn in the second list... */ 4290Sstevel@tonic-gate while (fnp2) { 4300Sstevel@tonic-gate if (fnp2 == fnlp2->fnl_last) 4310Sstevel@tonic-gate nextfnp2 = NULL; 4320Sstevel@tonic-gate else 4330Sstevel@tonic-gate nextfnp2 = fnp2->fn_next; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* append it to the first list */ 4360Sstevel@tonic-gate fn_list_addfn(fnlp, fnp2); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate fnp2 = nextfnp2; 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate /* all the fn's were moved off the second list */ 4410Sstevel@tonic-gate fnlp2->fnl_first = fnlp2->fnl_last = fnlp2->fnl_rptr = NULL; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate /* done with the second list */ 4440Sstevel@tonic-gate fn_list_free(fnlp2); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * fn_list_appendrange -- append a range of characters to each filename in list 4490Sstevel@tonic-gate * 4500Sstevel@tonic-gate * range of characters appended is the character at *s up to but not including 4510Sstevel@tonic-gate * the character at *limit. NULL termination is not required. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate void 4540Sstevel@tonic-gate fn_list_appendrange(struct fn_list *fnlp, const char *s, const char *limit) 4550Sstevel@tonic-gate { 4560Sstevel@tonic-gate struct fn *fnp = fnlp->fnl_first; 4570Sstevel@tonic-gate struct fn *nextfnp; 4580Sstevel@tonic-gate const char *ptr; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* for each fn in the list... */ 4610Sstevel@tonic-gate while (fnp) { 4620Sstevel@tonic-gate if (fnp == fnlp->fnl_last) 4630Sstevel@tonic-gate nextfnp = NULL; 4640Sstevel@tonic-gate else 4650Sstevel@tonic-gate nextfnp = fnp->fn_next; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /* append the range */ 4680Sstevel@tonic-gate for (ptr = s; ptr < limit; ptr++) 4690Sstevel@tonic-gate fn_putc(fnp, *ptr); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate fnp = nextfnp; 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate /* 4760Sstevel@tonic-gate * fn_list_totalsize -- sum up all the st_size fields in the stat structs 4770Sstevel@tonic-gate */ 478*2016Sbasabi off_t 4790Sstevel@tonic-gate fn_list_totalsize(struct fn_list *fnlp) 4800Sstevel@tonic-gate { 4810Sstevel@tonic-gate struct fn *fnp; 482*2016Sbasabi off_t ret = 0; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate fn_list_rewind(fnlp); 4850Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 4860Sstevel@tonic-gate ret += fnp->fn_stbuf.st_size; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate return (ret); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * fn_list_popoldest -- remove oldest file from list and return it 4930Sstevel@tonic-gate * 4940Sstevel@tonic-gate * this function uses the "n" values (set by fn_setn()) to determine 4950Sstevel@tonic-gate * which file is oldest, or when there's a tie it turns to the modification 4960Sstevel@tonic-gate * times in the stat structs, or when there's still a tie lexical sorting. 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate struct fn * 4990Sstevel@tonic-gate fn_list_popoldest(struct fn_list *fnlp) 5000Sstevel@tonic-gate { 5010Sstevel@tonic-gate struct fn *fnp; 5020Sstevel@tonic-gate struct fn *ret = NULL; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate fn_list_rewind(fnlp); 5050Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 5060Sstevel@tonic-gate if (ret == NULL) 5070Sstevel@tonic-gate ret = fnp; 5080Sstevel@tonic-gate else if (fnp->fn_n > ret->fn_n || 5090Sstevel@tonic-gate (fnp->fn_n == ret->fn_n && 5100Sstevel@tonic-gate (fnp->fn_stbuf.st_mtime < ret->fn_stbuf.st_mtime || 5110Sstevel@tonic-gate ((fnp->fn_stbuf.st_mtime == ret->fn_stbuf.st_mtime && 5120Sstevel@tonic-gate strcmp(fnp->fn_buf, ret->fn_buf) > 0))))) 5130Sstevel@tonic-gate ret = fnp; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate if (ret == NULL) 5160Sstevel@tonic-gate return (NULL); 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* oldest file is ret, remove it from list */ 5190Sstevel@tonic-gate if (fnlp->fnl_first == ret) 5200Sstevel@tonic-gate fnlp->fnl_first = ret->fn_next; 5210Sstevel@tonic-gate else { 5220Sstevel@tonic-gate fn_list_rewind(fnlp); 5230Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 5240Sstevel@tonic-gate if (fnp->fn_next == ret) { 5250Sstevel@tonic-gate fnp->fn_next = ret->fn_next; 5260Sstevel@tonic-gate break; 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate ret->fn_next = NULL; 5310Sstevel@tonic-gate return (ret); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * fn_list_empty -- true if the list is empty 5360Sstevel@tonic-gate */ 5370Sstevel@tonic-gate boolean_t 5380Sstevel@tonic-gate fn_list_empty(struct fn_list *fnlp) 5390Sstevel@tonic-gate { 5400Sstevel@tonic-gate return (fnlp->fnl_first == NULL); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * fn_list_count -- return number of filenames in list 5450Sstevel@tonic-gate */ 5460Sstevel@tonic-gate int 5470Sstevel@tonic-gate fn_list_count(struct fn_list *fnlp) 5480Sstevel@tonic-gate { 5490Sstevel@tonic-gate int ret = 0; 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /* 5520Sstevel@tonic-gate * if this operation were more common, we'd cache the count 5530Sstevel@tonic-gate * in the struct fn_list, but it isn't very common so we just 5540Sstevel@tonic-gate * count 'em up here 5550Sstevel@tonic-gate */ 5560Sstevel@tonic-gate fn_list_rewind(fnlp); 5570Sstevel@tonic-gate while (fn_list_next(fnlp) != NULL) 5580Sstevel@tonic-gate ret++; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate return (ret); 5610Sstevel@tonic-gate } 562