1 /*
2 fetchlist.c
3
4 $Id: fetchlist.c,v 1.10 2003/01/10 23:11:43 bears Exp $
5 */
6
7 #if HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <stdio.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include "fetchlist.h"
15 #include "configfile.h"
16 #include "log.h"
17 #include "util.h"
18 #include "portable.h"
19
20 struct Elem
21 {
22 Str name;
23 FetchMode mode;
24 };
25
26 static struct Fetchlist
27 {
28 struct Elem *elem;
29 int size;
30 int max;
31 Bool dirty;
32 } fetchlist = { NULL, 0, 0, FALSE };
33
34 static void
clearList(void)35 clearList( void )
36 {
37 fetchlist.size = 0;
38 fetchlist.dirty = FALSE;
39 }
40
41 static int
compareElem(const void * elem1,const void * elem2)42 compareElem( const void *elem1, const void *elem2 )
43 {
44 const struct Elem* e1 = (const struct Elem*)elem1;
45 const struct Elem* e2 = (const struct Elem*)elem2;
46 return strcmp( e1->name, e2->name );
47 }
48
49 static struct Elem *
searchElem(const char * name)50 searchElem( const char *name )
51 {
52 int i;
53
54 for ( i = 0; i < fetchlist.size; ++i )
55 if ( strcmp( name, fetchlist.elem[ i ].name ) == 0 )
56 return &fetchlist.elem[ i ];
57 return NULL;
58 }
59
60 static void
appGrp(const char * name,FetchMode mode)61 appGrp( const char *name, FetchMode mode )
62 {
63 struct Elem elem;
64
65 if ( fetchlist.max < fetchlist.size + 1 )
66 {
67 if ( ! ( fetchlist.elem
68 = realloc( fetchlist.elem,
69 ( fetchlist.max + 50 )
70 * sizeof( fetchlist.elem[ 0 ] ) ) ) )
71 Log_fatal( "Could not realloc fetchlist" );
72 fetchlist.max += 50;
73 }
74 Utl_cpyStr( elem.name, name );
75 elem.mode = mode;
76 fetchlist.elem[ fetchlist.size++ ] = elem;
77 }
78
79 void
Fetchlist_read(void)80 Fetchlist_read( void )
81 {
82 FILE *f;
83 Str file;
84 char *p;
85 FetchMode mode = OVER;
86 Bool valid;
87 int ret;
88 Str line, grp, modeStr;
89
90 Log_dbg( LOG_DBG_FETCH, "Reading %s", file );
91 snprintf( file, MAXCHAR, "%s/fetchlist", Cfg_spoolDir() );
92 clearList();
93 if ( ! ( f = fopen( file, "r" ) ) )
94 {
95 Log_inf( "No file %s", file );
96 return;
97 }
98 while ( fgets( line, MAXCHAR, f ) )
99 {
100 p = Utl_stripWhiteSpace( line );
101 if ( *p == '#' || *p == '\0' )
102 continue;
103 ret = sscanf( p, MAXCHAR_FMT " " MAXCHAR_FMT, grp, modeStr );
104 valid = TRUE;
105 if ( ret < 1 || ret > 2 )
106 valid = FALSE;
107 else if ( ret >= 2 )
108 {
109 if ( strcmp( modeStr, "full" ) == 0 )
110 mode = FULL;
111 else if ( strcmp( modeStr, "thread" ) == 0 )
112 mode = THREAD;
113 else if ( strcmp( modeStr, "over" ) == 0 )
114 mode = OVER;
115 else
116 valid = FALSE;
117 }
118 if ( ! valid )
119 {
120 Log_err( "Invalid entry in %s: %s", file, line );
121 continue;
122 }
123 appGrp( grp, mode );
124 }
125 if ( ferror( f ) )
126 Log_err( "Error reading %s: %s", file, strerror( errno ) );
127 if ( fclose( f ) != 0 )
128 Log_err( "Error closing %s; %s", file, strerror( errno ) );
129 }
130
131 Bool
Fetchlist_write(void)132 Fetchlist_write( void )
133 {
134 int i;
135 FILE *f;
136 Str file, tmpfname;
137 const char *modeStr = "";
138 Bool res;
139
140 /* Any changes? */
141 if ( ! fetchlist.dirty )
142 return TRUE;
143
144 qsort( fetchlist.elem, (size_t)fetchlist.size,
145 sizeof( fetchlist.elem[ 0 ] ), compareElem );
146
147 snprintf( file, MAXCHAR, "%s/fetchlist", Cfg_spoolDir() );
148 snprintf( tmpfname, MAXCHAR, "%s/.#%d.fetchlist",
149 Cfg_spoolDir(), (int) getpid() );
150
151 if ( ! ( f = fopen( tmpfname, "w" ) ) )
152 {
153 Log_err( "Could not open %s for writing", file );
154 return FALSE;
155 }
156 res = TRUE;
157 for ( i = 0; i < fetchlist.size; ++i )
158 {
159 switch ( fetchlist.elem[ i ].mode )
160 {
161 case FULL:
162 modeStr = "full"; break;
163 case THREAD:
164 modeStr = "thread"; break;
165 case OVER:
166 modeStr = "over"; break;
167 }
168 fprintf( f, "%s %s\n", fetchlist.elem[ i ].name, modeStr );
169 if ( ferror( f ) )
170 {
171 Log_err( "Error writing %s: %s", tmpfname, strerror( errno ) );
172 clearerr( f );
173 res = FALSE;
174 }
175 }
176 if ( fclose( f ) != 0 )
177 {
178 Log_err( "Error closing %s: %s", tmpfname, strerror( errno ) );
179 res = FALSE;
180 }
181
182 if ( res )
183 {
184 if ( rename( tmpfname, file ) < 0 )
185 {
186 Log_err( "Rename of %s to %s failed: %s", tmpfname, file,
187 strerror( errno ) );
188 res = FALSE;
189 }
190 }
191
192 return res;
193 }
194
195 int
Fetchlist_size(void)196 Fetchlist_size( void )
197 {
198 return fetchlist.size;
199 }
200
201 Bool
Fetchlist_contains(const char * name,FetchMode * mode)202 Fetchlist_contains( const char *name, FetchMode *mode )
203 {
204 struct Elem *elem = searchElem( name );
205 if ( elem == NULL )
206 return FALSE;
207 if ( mode != NULL )
208 *mode = elem->mode;
209 return TRUE;
210 }
211
212 Bool
Fetchlist_element(const char ** name,FetchMode * mode,int idx)213 Fetchlist_element( const char **name, FetchMode *mode, int idx )
214 {
215 if ( idx < 0 || idx >= fetchlist.size )
216 return FALSE;
217 *name = fetchlist.elem[ idx ].name;
218 *mode = fetchlist.elem[ idx ].mode;
219 return TRUE;
220 }
221
222 Bool
Fetchlist_add(const char * name,FetchMode mode)223 Fetchlist_add( const char *name, FetchMode mode )
224 {
225 struct Elem *elem = searchElem( name );
226 fetchlist.dirty = TRUE;
227 if ( elem == NULL )
228 {
229 appGrp( name, mode );
230 return TRUE;
231 }
232 Utl_cpyStr( elem->name, name );
233 elem->mode = mode;
234 return FALSE;
235 }
236
237 Bool
Fetchlist_remove(const char * name)238 Fetchlist_remove( const char *name )
239 {
240 struct Elem *elem = searchElem( name );
241 if ( elem == NULL )
242 return FALSE;
243 fetchlist.dirty = TRUE;
244 *elem = fetchlist.elem[ fetchlist.size - 1 ];
245 --fetchlist.size;
246 return TRUE;
247 }
248