1 /*  VER 049   TAB P   $Id: util.c,v 1.14.2.1 2002/01/29 06:44:48 egil Exp $
2  *
3  *  file utilities
4  *
5  *  copyright 1996, 1997 Egil Kvaleberg, egil@kvaleberg.no
6  *  the GNU General Public License applies
7  *
8  *  $Log: util.c,v $
9  *  Revision 1.14.2.1  2002/01/29 06:44:48  egil
10  *  Changing from xmalloc, xrealloc, xstrcpy to
11  *  malloc_perfect, realloc_perfect and strdup_perfect
12  *
13  *  Revision 1.14  1999/04/07 08:02:11  src
14  *  Implemented --profile
15  *
16  *  Revision 1.13  1999/03/24 03:53:02  src
17  *  Implemented "newsx" as magic exclude pattern
18  *
19  *  Revision 1.12  1999/03/11 07:30:01  src
20  *  Implemented check for spool free space
21  *
22  *  Revision 1.11  1999/03/07 14:58:19  src
23  *  Read newsconfig supported. Storage API supported.
24  *
25  *  Revision 1.10  1998/09/14 06:30:25  src
26  *  *** empty log message ***
27  *
28  *  Revision 1.9  1998/09/14 06:07:19  src
29  *  Cleaned up dbz -Wall
30  *
31  *  Revision 1.8  1998/09/11 09:17:44  src
32  *  Check path consistency (--no-path) and length (--max-path)
33  *  GNU style option --help, --version, --dry-run, changed --noxx to --no-xx
34  *  Check for putenv and setenv, added xstrcpy
35  *
36  *  Revision 1.7  1998/09/09 07:32:15  src
37  *  Version 1.1
38  *
39  *  Revision 1.6  1998/07/12 09:39:31  src
40  *  newsx version 1.0
41  */
42 
43 #include "common.h"
44 #include "proto.h"
45 #include "options.h"
46 #include "stat.h"
47 
48 /*
49  *  append the contents of a file to another file
50  *  returns 0 on error, 1 if all OK
51  */
52 int
append_file(FILE * f,char * name,FILE * af)53 append_file(FILE *f,char *name,FILE *af)
54 {
55     int n;
56     char buf[1024];
57 
58     if (fseek(f,0L,2) != 0) {
59 	log_msg(L_ERRno,"can't seek to end of \"%s\"", name);
60 	return 0;
61     }
62 
63     while ((n = fread(buf,1,sizeof(buf),af)) > 0) {
64 	if (fwrite(buf,1,n,f) != n) {
65 	    /* append failed */
66 	    log_msg(L_ERR,"can't append to \"%s\"", name);
67 	    return 0;
68 	}
69     }
70 
71     if (fflush(f) != 0) {
72 	log_msg(L_ERRno,"can't flush \"%s\"", name);
73 	return 0;
74     }
75     if (fseek(f,0L,0) != 0) {
76 	log_msg(L_ERRno,"can't seek to start of \"%s\"", name);
77 	return 0;
78     }
79     return 1;
80 }
81 
82 /*
83  *  rename a file
84  *  returns 0 on error
85  */
86 int
rename_file(char * from,char * to)87 rename_file(char *from,char *to)
88 {
89     if (rename(from,to) == EOF) {
90 	log_msg(L_ERRno,"can't rename \"%s\" to \"%s\"", from,to);
91 	return 0;
92     }
93     return 1;
94 }
95 
96 /*
97  *  check if it is a regular file
98  *  as an added bonus, sets file size is desired
99  */
100 int
is_regular(FILE * f,char * name,long * sizep)101 is_regular(FILE *f, char *name, long *sizep)
102 {
103     struct stat st;
104 
105     /* verify that it is a regular file */
106     if (fstat(fileno(f),&st) < 0) {
107 	log_msg(L_ERRno,"can't fstat \"%s\"", name);
108 	return 0;
109     }
110     /* BUG: both of these must be set: S_IRUSR S_IWUSR */
111     if (!S_ISREG(st.st_mode)) {
112 	log_msg(L_ERR,"\"%s\" is not a regular file", name);
113 	return 0;
114     }
115     if (sizep) *sizep = (long)(st.st_size);
116     return 1;
117 }
118 
119 /*
120  *  build a file name, with a fixed default choice as well as a
121  *  first prioroty alternative
122  *  both names may be absolute or relative paths
123  */
124 void
build_alt_filename(char * where,char * home,char * fixed,char * alt)125 build_alt_filename(char *where, char *home, char *fixed, char *alt)
126 {
127     char *name = (alt && alt[0]) ? alt : fixed;
128 
129     if (name[0]=='/' || name[0]=='.') {
130 	build_filename(where,name,NULL,NULL,NULL);
131     } else {
132 	build_filename(where,home,"/",name,NULL);
133     }
134 }
135 
136 /*
137  *  build a file name, max length PATH_MAX
138  *  argument is a list of up to arguments, padded with NULL to make 4
139  *  NOTE: a NULL-terminated argument list would have been neater,
140  *        but it is simply not worth the effort to make it portable
141  */
142 void
build_filename(char * where,char * arg1,char * arg2,char * arg3,char * arg4)143 build_filename(char *where,char *arg1,char *arg2,char *arg3,char *arg4)
144 {
145     int len = 0;
146     int n;
147     char **argp;
148     char *argv[5];
149 
150     argv[0] = arg1;
151     argv[1] = arg2;
152     argv[2] = arg3;
153     argv[3] = arg4;
154     argv[4] = NULL;
155 
156     for (argp = argv; *argp; ++argp) {
157 	if ((len += (n=strlen(*argp))) >= PATH_MAX) {
158 	    log_msg(L_ERR,"file name longer than %d chars", PATH_MAX-1);
159 	    exit_cleanup(1);
160 	}
161 	strcpy(where+len-n,*argp);
162     }
163 }
164 
165 /*
166  *  convert time to text string, local time
167  *  return static pointer
168  *  "Wed Apr 10 11:00:00 1996"
169  */
170 char *
text_time(time_t t)171 text_time(time_t t)
172 {
173     static char buf[50];
174     char *p;
175 
176     strcpy(buf,asctime(localtime(&t)));
177     /* remove trailing newline */
178     if ((p=strchr(buf,'\n'))) *p = '\0';
179 
180     return buf;
181 }
182 
183 /*
184  *  skip blanks
185  */
186 char *
skipsp(char * p)187 skipsp(char *p)
188 {
189     while (*p==' ' || *p=='\t') ++p;
190     return p;
191 }
192 
193 /*
194  *  memory allocation - never fail
195  */
196 void *
malloc_perfect(unsigned int size)197 malloc_perfect(unsigned int size)
198 {
199     void *p;
200 
201     if (!(p = malloc(size))) {
202 	log_msg(L_ERR,"out of memory");
203 	unlock_exit(1);
204     }
205     return p;
206 }
207 
208 /*
209  *  memory reallocation - never fail
210  */
211 void *
realloc_perfect(void * p,unsigned int size)212 realloc_perfect(void *p,unsigned int size)
213 {
214     if (!(p = realloc(p,size))) {
215 	log_msg(L_ERR,"reallocation error, out of memory");
216 	unlock_exit(1);
217     }
218     return p;
219 }
220 
221 /*
222  *  string allocate and copy - never fail
223  */
224 char *
strdup_perfect(const char * str)225 strdup_perfect(const char *str)
226 {
227     return strcpy(malloc_perfect(strlen(str)+1),str);
228 }
229