Line data Source code
1 : /*
2 : Copyright (c) 2017 by Danny Goossen, Gioxa Ltd.
3 :
4 : This file is part of the oc-runner
5 :
6 : MIT License
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : /*! @file utils.c
29 : * @brief extra / modified c-functions
30 : * @author danny@gioxa.com
31 : * @date 10/5/17
32 : * @copyright (c) 2017 Danny Goossen,Gioxa Ltd.
33 : */
34 :
35 : #define _GNU_SOURCE
36 : #include <stdio.h>
37 :
38 : // stdio.h with _GNU_SOURCE already defines _XOPEN_SOURCE 500
39 : //#define _XOPEN_SOURCE 500
40 : #include <ftw.h>
41 : typedef unsigned short int u_short;
42 : #include <fts.h>
43 :
44 : #include "deployd.h"
45 :
46 : #ifndef OPEN_MAX
47 : #define OPEN_MAX 1023
48 : #endif
49 :
50 : #include "wordexp_var.h"
51 :
52 :
53 : /*------------------------------------------------------------------------
54 : * Convert string to uppercase
55 : *------------------------------------------------------------------------*/
56 9 : void upper_string(char s[]) {
57 18 : if (!s) return;
58 : int c = 0;
59 :
60 43 : while (s[c] != '\0') {
61 35 : if (s[c] >= 'a' && s[c] <= 'z') {
62 33 : s[c] = s[c] - 32;
63 : }
64 35 : c++;
65 : }
66 : }
67 : /*------------------------------------------------------------------------
68 : * Convert string to lower case
69 : *------------------------------------------------------------------------*/
70 39 : void lower_string(char s[]) {
71 78 : if (!s) return;
72 : int c = 0;
73 :
74 389 : while (s[c] != '\0') {
75 351 : if (s[c] >= 'A' && s[c] <= 'Z') {
76 32 : s[c] = s[c] + 32;
77 : }
78 351 : c++;
79 : }
80 : }
81 :
82 : /*------------------------------------------------------------------------
83 : * Convert non null terminated string to uppercase
84 : *------------------------------------------------------------------------*/
85 :
86 3 : void upper_string_n(char s[],size_t n) {
87 6 : if (!s) return;
88 : int c = 0;
89 :
90 3 : while (s[c] != '\0' && c<n) {
91 2 : if (s[c] >= 'a' && s[c] <= 'z') {
92 2 : s[c] = s[c] - 32;
93 : }
94 2 : c++;
95 : }
96 : }
97 :
98 : /*
99 : void split_path_file(char** p, char** f,const char *pf) {
100 : if (!pf || strlen(pf)==0) return;
101 : const char *slash = pf;
102 : char *next;
103 : while ((next = strpbrk(slash + 1, "\\/"))) slash = next;
104 : if (pf != slash) slash++;
105 : *p = cJSON_strdup_n((const unsigned char *)pf, slash - pf);
106 : *f = strdup(slash);
107 : }
108 : */
109 :
110 4 : void split_path_file_2_path(char** p, const char *pf) {
111 8 : if (!pf || strlen(pf)==0) return;
112 : const char *slash = pf;
113 : char *next;
114 22 : while ((next = strpbrk(slash + 1, "\\/"))) slash = next;
115 4 : if (pf != slash) slash++;
116 4 : *p =cJSON_strdup_n((const unsigned char *)pf, slash - pf);
117 : }
118 :
119 :
120 : void * memrchr(const void *s,int c, size_t n)
121 : {
122 : const unsigned char *cp;
123 :
124 20 : if (n != 0) {
125 20 : cp = (unsigned char *)s + n;
126 : do {
127 160 : if (*(--cp) == (unsigned char)c)
128 : return (void *)cp;
129 143 : } while (--n != 0);
130 : }
131 : return (void *)0;
132 : }
133 :
134 :
135 7 : char * normalizePath(const char* pwd, const char * src, char* res) {
136 : size_t res_len;
137 7 : size_t src_len = strlen(src);
138 :
139 7 : const char * ptr = src;
140 7 : const char * end = &src[src_len];
141 : const char * next;
142 :
143 7 : if (src_len == 0 || src[0] != '/') {
144 : // relative path
145 : size_t pwd_len;
146 :
147 0 : pwd_len = strlen(pwd);
148 0 : memcpy(res, pwd, pwd_len);
149 0 : res_len = pwd_len;
150 : } else {
151 : res_len = 0;
152 : }
153 60 : for (ptr = src; ptr < end; ptr=next+1) {
154 : size_t len;
155 53 : next = (char*)memchr(ptr, '/', end-ptr);
156 53 : if (next == NULL) {
157 7 : next = end;
158 : }
159 53 : len = next-ptr;
160 53 : switch(len) {
161 : case 2:
162 11 : if (ptr[0] == '.' && ptr[1] == '.') {
163 3 : const char * slash = (char*)memrchr(res, '/', res_len);
164 3 : if (slash != NULL) {
165 3 : res_len = slash - res;
166 : }
167 3 : continue;
168 : }
169 : break;
170 : case 1:
171 2 : if (ptr[0] == '.') {
172 1 : continue;
173 : }
174 : break;
175 : case 0:
176 7 : continue;
177 : }
178 :
179 42 : if (res_len != 1)
180 42 : res[res_len++] = '/';
181 :
182 42 : memcpy(&res[res_len], ptr, len);
183 42 : res_len += len;
184 : }
185 :
186 7 : if (res_len == 0) {
187 0 : res[res_len++] = '/';
188 : }
189 7 : res[res_len] = '\0';
190 7 : return res;
191 : }
192 :
193 : /**
194 : \brief nftw() extended with payload \a data for callback function
195 : The function nftw_x() is the same as nftw(), except that it has one additional argument, \a data as payload for the fn()
196 : \see https://linux.die.net/man/3/nftw for the base function nftw()
197 : */
198 : static int
199 2 : nftw_x(const char *path, int (*fn)(const char *, const struct stat *, int,
200 : struct FTW *,void * data), int nfds, int ftwflags,void * data)
201 : {
202 : const char *paths[2];
203 : struct FTW ftw;
204 : FTSENT *cur;
205 : FTS *ftsp;
206 : int ftsflags, fnflag, error, postorder, sverrno;
207 :
208 : /* XXX - nfds is currently unused */
209 2 : if (nfds < 1 || nfds > OPEN_MAX) {
210 0 : errno = EINVAL;
211 0 : return (-1);
212 : }
213 :
214 2 : ftsflags = FTS_COMFOLLOW;
215 2 : if (!(ftwflags & FTW_CHDIR))
216 2 : ftsflags |= FTS_NOCHDIR;
217 2 : if (ftwflags & FTW_MOUNT)
218 0 : ftsflags |= FTS_XDEV;
219 2 : if (ftwflags & FTW_PHYS)
220 2 : ftsflags |= FTS_PHYSICAL;
221 2 : postorder = (ftwflags & FTW_DEPTH) != 0;
222 2 : paths[0] = path;
223 2 : paths[1] = NULL;
224 2 : ftsp = fts_open((char * const *)paths, ftsflags, NULL);
225 2 : if (ftsp == NULL)
226 : return (-1);
227 : error = 0;
228 13 : while ((cur = fts_read(ftsp)) != NULL) {
229 11 : switch (cur->fts_info) {
230 : case FTS_D:
231 4 : if (postorder)
232 0 : continue;
233 : fnflag = FTW_D;
234 : break;
235 : case FTS_DNR:
236 : fnflag = FTW_DNR;
237 : break;
238 : case FTS_DP:
239 4 : if (!postorder)
240 4 : continue;
241 : fnflag = FTW_DP;
242 : break;
243 : case FTS_F:
244 : case FTS_DEFAULT:
245 3 : fnflag = FTW_F;
246 3 : break;
247 : case FTS_NS:
248 : case FTS_NSOK:
249 0 : fnflag = FTW_NS;
250 0 : break;
251 : case FTS_SL:
252 0 : fnflag = FTW_SL;
253 0 : break;
254 : case FTS_SLNONE:
255 0 : fnflag = FTW_SLN;
256 0 : break;
257 : case FTS_DC:
258 0 : errno = ELOOP;
259 : /* FALLTHROUGH */
260 : default:
261 : error = -1;
262 : goto done;
263 : }
264 7 : ftw.base = cur->fts_pathlen - cur->fts_namelen;
265 7 : ftw.level = cur->fts_level;
266 7 : error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw,data);
267 7 : if (error != 0)
268 : break;
269 : }
270 : done:
271 2 : sverrno = errno;
272 2 : (void) fts_close(ftsp);
273 2 : errno = sverrno;
274 2 : return (error);
275 : }
276 :
277 : /**
278 : \brief callback funtion for nftw() rm -r
279 : */
280 31 : static int remove_it(const char *path, __attribute__((unused)) const struct stat *s, int flag, __attribute__((unused)) struct FTW *f)
281 : {
282 31 : int status=0;
283 : int (*rm_func)( const char * );
284 :
285 31 : switch( flag ) {
286 : default: rm_func = unlink; break;
287 20 : case FTW_DP: rm_func = rmdir;
288 : }
289 31 : status = (rm_func( path ), status != 0 );
290 : // perror( path );
291 31 : return status;
292 : }
293 :
294 : /**
295 : \brief wrapper for nftw_x payload used for getfilelist_item()
296 : */
297 : struct payload{
298 : cJSON ** filelist;
299 : };
300 :
301 : /**
302 : \brief add path to filelist with attributes from \p mode
303 : \param path to add to list
304 : \param mode attributes to add
305 : \return 0 on success
306 : */
307 10 : static int add_to_file_list(const char *path,int mode,cJSON ** filelist)
308 : {
309 10 : int result=0;
310 10 : size_t len=strlen(path);
311 10 : if ((S_ISDIR(mode) && len>2 && strcmp(path+len-2, ".")!=0 && len >3 && strcmp(path+len-3, "..")!=0 )|| !S_ISDIR(mode))
312 : {
313 10 : if (!*filelist) *filelist=cJSON_CreateArray();
314 10 : if (*filelist)
315 : {
316 10 : cJSON * tmpo=cJSON_CreateObject();
317 10 : cJSON_AddStringToObject(tmpo, "path", path);
318 10 : cJSON_AddNumberToObject(tmpo, "mode", mode);
319 10 : cJSON_AddItemToArray(*filelist,tmpo);
320 : }
321 : else
322 : result=1;
323 : }
324 10 : return result;
325 : }
326 :
327 : /**
328 : * \brief calback function for the nftw_x for getfilelist_item()
329 : */
330 7 : static int list_it(const char *path, const struct stat *s, int flag, __attribute__((unused)) struct FTW *f,void* data)
331 : {
332 7 : int status=0;
333 : switch( flag ) {
334 : default: ; break;
335 : /* we'll handle dir/symlinks/files */
336 : case FTW_SL:
337 : case FTW_F:
338 : case FTW_D:
339 7 : status=add_to_file_list( path,s->st_mode ,data) ;break;
340 : }
341 7 : return status;
342 : }
343 :
344 : /**
345 : \brief get filelist from \p item, traverse if \p item is a directory.
346 : \param projectdir base directory
347 : \param item to process
348 : \param filelist pointer to the result
349 : */
350 7 : static void getfilelist_item(const char * projectdir,const char *item,cJSON ** filelist)
351 : {
352 7 : debug("getfilelist_item %s in %s\n",item,projectdir);
353 : struct stat sb;
354 7 : if (strlen(item)>=PATH_MAX)
355 : {
356 0 : debug("item exceeds PATHMAX length\n");
357 0 : return;
358 : }
359 : char normalized_path_buf[PATH_MAX];
360 7 : const char * normalized_path=normalizePath(projectdir, item, normalized_path_buf);
361 7 : debug("normalized_path from %s => %s\n",item, normalized_path);
362 7 : if (!normalized_path)
363 : {
364 0 : debug("normalized path error\n");
365 : }
366 : char realpathbuffer[PATH_MAX];
367 : // check if we stay within the project dir
368 7 : char * therealpath=realpath(item, realpathbuffer);
369 7 : debug("therealpath %s\n",therealpath);
370 7 : if (therealpath)
371 : {
372 :
373 6 : if (strncmp(therealpath, projectdir, strlen(projectdir))!=0 && strncmp(therealpath,"/cache/",7)!=0)
374 : {
375 1 : debug("real_path outside project dir path\n");
376 1 : return;
377 : }
378 : }
379 : else
380 : {
381 1 : error("problem finding real path for %s: %s\n",item,strerror(errno));
382 1 : return;
383 : }
384 5 : if (stat(item, &sb) == 0 && S_ISDIR(sb.st_mode))
385 : {
386 :
387 : //add_to_file_list(normalized_path, sb.st_mode, filelist);
388 2 : if (nftw_x((char*)normalized_path, list_it, 6 ,FTW_PHYS ,(void*)filelist)) //| FTW_DEPTH
389 : {
390 0 : perror( normalized_path );
391 0 : error("nftw return non 0\n");
392 0 : return ;
393 : }
394 : }
395 3 : else if (stat(item, &sb) == 0 && (S_ISLNK(sb.st_mode)|| S_ISREG(sb.st_mode)))
396 3 : add_to_file_list(normalized_path, sb.st_mode, filelist);
397 : }
398 :
399 :
400 : // public
401 1 : int getfilelist(const char * projectdir,cJSON * paths,cJSON ** filelist)
402 : {
403 1 : if (!projectdir || !paths || !filelist ) return -1;
404 : char tmp[PATH_MAX];
405 : cJSON * path;
406 6 : cJSON_ArrayForEach(path,paths)
407 : {
408 5 : int res =snprintf((char*)tmp,PATH_MAX,"%s/%s",projectdir,path->valuestring);
409 5 : if (res>=PATH_MAX) continue;
410 5 : debug("get filelist for path %s\n",tmp);
411 : wordexp_t word_re;
412 : // errors on undef and commands
413 5 : switch (wordexp(tmp, &word_re, WRDE_UNDEF))
414 : {
415 : case 0: /* Successful. */
416 : {
417 : int i;
418 4 : debug("wordexp arti path found %d matches",word_re.we_wordc);
419 11 : for (i=0;i<word_re.we_wordc;i++)
420 : {
421 :
422 7 : getfilelist_item(projectdir,word_re.we_wordv[i],filelist);
423 : }
424 4 : wordfree (&word_re);
425 : }
426 4 : break;
427 : case WRDE_NOSPACE:
428 : /* If the error was WRDE_NOSPACE,
429 : then perhaps part of the result was allocated. */
430 0 : error("WRDE_NOSPACE \n");
431 0 : wordfree (&word_re);
432 0 : break;
433 : default: /* Some other error. */
434 1 : error("some othe wordexp error \n");
435 1 : break;
436 : }
437 : //cleanup
438 : }
439 : return 0;
440 : }
441 :
442 8 : void vrmdir(const char *dir, ...) {
443 9 : if (!dir) return;
444 7 : char *tmp=CSPRINTF(dir);
445 : struct stat sb;
446 :
447 7 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
448 : {
449 7 : if (nftw((char*)tmp, remove_it, 6 ,FTW_PHYS | FTW_DEPTH))
450 : {
451 0 : perror( tmp );
452 : }
453 : }
454 7 : if (tmp) free(tmp);
455 : }
456 :
457 2 : void vrmdir_s(const char *dir, ...) {
458 3 : if (!dir) return;
459 1 : char *tmp=CSPRINTF(dir);
460 : struct stat sb;
461 :
462 1 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
463 : {
464 1 : if (nftw((char*)tmp, remove_it, 6 , FTW_DEPTH))
465 : {
466 0 : perror( tmp );
467 : }
468 : }
469 1 : if (tmp) free(tmp);
470 : }
471 :
472 5 : int v_exist_dir(const char *dir, ...)
473 : {
474 5 : if (!dir) return 0;
475 4 : char *tmp=CSPRINTF(dir);
476 : struct stat sb;
477 4 : int result=0;
478 4 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
479 2 : result=1;
480 4 : if (tmp) free(tmp);
481 4 : return result;
482 : }
483 :
484 : // mdir -p
485 6 : void vmkdir(const char *dir, ...) {
486 7 : if (!dir) return;
487 5 : char *tmp=CSPRINTF(dir);
488 5 : char *p=NULL;
489 5 : size_t len=0;
490 : struct stat sb;
491 5 : if (tmp)
492 : {
493 5 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
494 : {
495 : //debug("directory %s exists\n",tmp);
496 : }
497 : else
498 : {
499 5 : len = strlen(tmp);
500 5 : if(tmp[len - 1] == '/')
501 1 : tmp[len - 1] = 0;
502 : //debug("mkdir %s\n",tmp);
503 88 : for(p = tmp + 1; *p; p++)
504 83 : if(*p == '/') {
505 13 : *p = 0;
506 13 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
507 : {
508 : //debug("sub directory %s exists\n",tmp);
509 : }
510 : else{
511 : //debug("mkdir sub %s\n",tmp);
512 7 : mkdir(tmp,S_IRWXG | S_IRWXU);
513 : }
514 13 : *p = '/';
515 : }
516 : //debug("mkdir sub %s\n",tmp);
517 5 : mkdir(tmp, S_IRWXG | S_IRWXU);
518 : }
519 5 : free(tmp);
520 : }
521 : }
522 :
523 4 : char * vcmkdir(const char *dir, ...) {
524 4 : if (!dir) return NULL;
525 3 : char *tmp=CSPRINTF(dir);
526 3 : char *p=NULL;
527 3 : size_t len=0;
528 : struct stat sb;
529 3 : if (tmp)
530 : {
531 3 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
532 : {
533 : //debug("directory %s exists\n",tmp);
534 : }
535 : else
536 : {
537 3 : len = strlen(tmp);
538 3 : if(tmp[len - 1] == '/')
539 1 : tmp[len - 1] = 0;
540 : //debug("mkdir %s\n",tmp);
541 45 : for(p = tmp + 1; *p; p++)
542 42 : if(*p == '/') {
543 6 : *p = 0;
544 6 : if (stat(tmp, &sb) == 0 && S_ISDIR(sb.st_mode))
545 : {
546 : //debug("sub directory %s exists\n",tmp);
547 : }
548 : else{
549 : //debug("mkdir sub %s\n",tmp);
550 3 : mkdir(tmp,S_IRWXG | S_IRWXU);
551 : }
552 6 : *p = '/';
553 : }
554 : //debug("mkdir sub %s\n",tmp);
555 3 : mkdir(tmp, S_IRWXG | S_IRWXU);
556 : }
557 : }
558 3 : return tmp;
559 : }
560 :
561 :
562 10 : int write_file_v(const char *data,size_t len,const char * filepath,... )
563 : {
564 10 : if (!filepath) return -1;
565 9 : char * filename=CSPRINTF(filepath);
566 9 : if (!data) return -1;
567 9 : if(!filename)
568 : {
569 0 : error("processing filepath, no memory???\n");
570 0 : return -1;
571 : }
572 :
573 : FILE * f;
574 9 : if (len)
575 8 : f = fopen ( filename, "wb" );
576 : else
577 : {
578 1 : len=strlen(data);
579 1 : f = fopen ( filename, "w" );
580 : }
581 9 : if ( !f ) {
582 : /* handle error */
583 2 : free(filename);
584 2 : return -1;
585 : }
586 7 : size_t wrote=fwrite(data, 1, len, f);
587 7 : fclose(f);
588 7 : free(filename);
589 7 : return (wrote!=len);
590 : }
591 :
592 :
593 3 : char * read_a_file_v(const char * filename,...)
594 : {
595 3 : if(!filename) return NULL;
596 2 : char * dirpath=CSPRINTF(filename);
597 :
598 2 : if(!dirpath)
599 : {
600 0 : error("processing filepath, no memory???\n");
601 0 : return NULL;
602 : }
603 :
604 2 : int f=open(dirpath,O_RDONLY);
605 2 : if (f==INVALID_SOCKET)
606 : {
607 :
608 1 : debug("read_v file %s: %s\n",dirpath,strerror(errno));
609 1 : free(dirpath);
610 1 : return NULL;
611 : }
612 1 : dynbuffer *mem=dynbuffer_init();
613 : char buf[0x10000];
614 1 : bzero(buf, 0x10000);
615 :
616 1 : ssize_t n=0;
617 3 : while ((n=read(f,buf,0xffff)) > 0)
618 :
619 : // while( ( fgets( buf, 1023, f )) != NULL )
620 : {
621 1 : dynbuffer_write_n(buf, n, mem );
622 1 : bzero(buf, 0x10000);
623 : }
624 : // fclose(f);
625 1 : free(dirpath);
626 1 : close(f);
627 1 : char * result=NULL;
628 1 : dynbuffer_pop(&mem, &result, NULL);
629 1 : return result;
630 : }
631 :
632 5 : char * read_a_file(const char * dirpath)
633 : {
634 5 : if (!dirpath) return NULL;
635 : //FILE *f = fopen(dirpath, "r");
636 : //if (f == NULL)
637 4 : int f=open(dirpath,O_RDONLY);
638 4 : if (f==INVALID_SOCKET)
639 : {
640 1 : debug("read_previous release.json: %s\n",strerror(errno));
641 1 : return NULL;
642 : }
643 3 : dynbuffer* mem=dynbuffer_init();
644 : char buf[0x10000];
645 3 : bzero(buf, 0x10000);
646 :
647 3 : ssize_t n=0;
648 9 : while ((n=read(f,buf,0xffff)) > 0)
649 :
650 : // while( ( fgets( buf, 1023, f )) != NULL )
651 : {
652 3 : dynbuffer_write_n(buf, n, mem );
653 3 : bzero(buf, 0x10000);
654 : }
655 : // fclose(f);
656 3 : close(f);
657 3 : char * result=NULL;
658 3 : dynbuffer_pop(&mem, &result, NULL);
659 3 : return result;
660 : }
661 :
662 : static int cp_file_x(const char * source,const char * destination, int append);
663 :
664 :
665 5 : int cp_file(const char * source,const char * destination)
666 : {
667 5 : return(cp_file_x(source, destination, 0));
668 : }
669 5 : int append_file_2_file(const char * source,const char * destination)
670 : {
671 5 : return(cp_file_x(source, destination, 1));
672 : }
673 :
674 3 : int append_data_2_file(const char * data,const char * destination)
675 : {
676 : FILE *exeout;
677 3 : exeout = fopen(destination, "ab");
678 3 : if (exeout == NULL) {
679 : /* handle error */
680 1 : debug("error opening: %s\n",destination);
681 1 : perror("file open for writing");
682 1 : return(-1);
683 : }
684 :
685 2 : size_t n=strlen(data);
686 2 : size_t m = fwrite(data, 1, n, exeout);
687 2 : if (fclose(exeout)) perror("close output file");
688 2 : return (int)m;
689 : }
690 :
691 10 : static int cp_file_x(const char * source,const char * destination, int append)
692 : {
693 10 : if (!source || !destination) return -1;
694 6 : ssize_t count=0;
695 : FILE *exein, *exeout;
696 6 : exein = fopen(source, "rb");
697 6 : if (exein == NULL) {
698 : /* handle error */
699 2 : debug("error opening: %s\n",source);
700 2 : perror("file open for reading");
701 2 : return(-1);
702 : }
703 4 : if (append)
704 2 : exeout = fopen(destination, "ab");
705 : else
706 2 : exeout = fopen(destination, "wb");
707 4 : if (exeout == NULL) {
708 : /* handle error */
709 2 : debug("error opening: %s\n",destination);
710 2 : perror("file open for writing");
711 2 : if (fclose(exein)) perror("close input file");
712 : return(-1);
713 : }
714 : size_t n, m;
715 : unsigned char buff[8192];
716 : do {
717 4 : n = fread(buff, 1, sizeof buff, exein);
718 4 : if (n) m = fwrite(buff, 1, n, exeout);
719 : else m = 0;
720 4 : count=count+m;
721 4 : } while ((n > 0) && (n == m));
722 2 : if (m)
723 : {
724 0 : perror("copy");
725 0 : count=-1;
726 : }
727 2 : if (fclose(exeout)) perror("close output file");
728 2 : if (fclose(exein)) perror("close input file");
729 2 : return (int)count;
730 : }
731 :
732 :
733 : static char const SIZE_PREFIXES[] = "kMGTPEZY";
734 :
735 : const char *
736 10 : format_size(char buf[FORMAT_SIZE_BUF], uint64_t sz)
737 : {
738 10 : memset(buf,0,FORMAT_SIZE_BUF);
739 10 : int pfx = 0;
740 : unsigned int m, rem, hrem;
741 : uint64_t a,n;
742 10 : if (sz <= 0) {
743 1 : memcpy(buf, "0 B", 3);
744 1 : return buf;
745 : }
746 9 : a = sz;
747 9 : if (a < 1000) {
748 1 : n = a;
749 1 : snprintf(buf, FORMAT_SIZE_BUF, "%llu B", n);
750 1 : return buf;
751 : }
752 3 : for (pfx = 0, hrem = 0; ; pfx++) {
753 11 : rem = a % 1000ULL;
754 11 : a = a / 1000ULL;
755 11 : if (!SIZE_PREFIXES[pfx + 1] || a < 1000ULL)
756 : break;
757 3 : hrem |= rem;
758 3 : }
759 8 : n = a;
760 8 : if (n < 10) {
761 4 : if (rem >= 950) {
762 1 : buf[0] = '1';
763 1 : buf[1] = '0';
764 1 : buf[2] = ' ';
765 1 : buf[3] = SIZE_PREFIXES[pfx];
766 1 : buf[4] = 'B';
767 1 : buf[5] = '\0';
768 1 : return buf;
769 : } else {
770 3 : m = rem / 100;
771 3 : rem = rem % 100;
772 3 : if (rem > 50 || (rem == 50 && ((m & 1) || hrem)))
773 1 : m++;
774 3 : snprintf(buf, FORMAT_SIZE_BUF,
775 3 : "%llu.%u %cB", n, m, SIZE_PREFIXES[pfx]);
776 : }
777 : } else {
778 4 : if (rem > 500 || (rem == 500 && ((n & 1) || hrem)))
779 1 : n++;
780 4 : if (n >= 1000 && SIZE_PREFIXES[pfx + 1]) {
781 1 : buf[0] = '1';
782 1 : buf[1] = '.';
783 1 : buf[2] = '0';
784 1 : buf[3] = ' ';
785 1 : buf[4] = SIZE_PREFIXES[pfx+1];
786 1 : buf[5] = 'B';
787 1 : buf[6] = '\0';
788 : } else {
789 3 : snprintf(buf, FORMAT_SIZE_BUF,
790 3 : "%llu %cB", n, SIZE_PREFIXES[pfx]);
791 : }
792 : }
793 : return buf;
794 : }
795 :
796 :
797 :
798 :
799 34 : char * cvaprintf(const char * __restrict format , va_list vargs)
800 : {
801 : va_list vargf;
802 34 : va_copy(vargf, vargs);
803 :
804 34 : int size=vsnprintf(NULL,0 ,format,vargs);
805 34 : va_end(vargs);
806 34 : if (size<0) return NULL; else size++;
807 :
808 34 : char * result=calloc(1,size);
809 34 : size=vsnprintf(result,size ,format,vargf);
810 34 : va_end(vargf);
811 34 : if (size<0)
812 : {
813 0 : if (result) free(result);
814 : result=NULL;
815 : }
816 34 : return result;
817 : }
818 :
819 1 : void strip_nl(char * data)
820 : {
821 1 : if(data)
822 : {
823 2 : while (strlen(data)>1 && data[strlen(data)-1]=='\n') data[strlen(data)-1]='\0';
824 : }
825 1 : return;
826 : }
827 :
828 4 : char * get_opt_value(const char * optarg,const char* default_value)
829 : {
830 4 : char * result=NULL;
831 4 : if (optarg)
832 : {
833 2 : result=calloc(1,strlen(optarg)+1);
834 2 : sprintf(result,"%s",optarg);
835 : }
836 2 : else if (default_value)
837 : {
838 1 : result=calloc(1,strlen(default_value)+1);
839 1 : sprintf(result,"%s",default_value);
840 : }
841 : else
842 : {
843 1 : result=calloc(1,1);
844 : }
845 4 : return result;
846 : }
847 :
848 : #ifndef HAVEPIPE2
849 : #define pipe2(x,y) ({ int res=pipe(x); if (res==0) { fcntl(x[0], F_SETFL, y); fcntl(x[1], F_SETFL, y);} res;})
850 : #endif
851 :
852 2 : int pipe_redirect_stderr(int my_pipe[2])
853 : {
854 2 : int t=0;
855 2 : if ((t=pipe2(my_pipe,O_NONBLOCK|FD_CLOEXEC))==0)
856 : {
857 2 : int e = dup(fileno(stderr));
858 2 : dup2(my_pipe[1], 2);
859 2 : return e;
860 : }
861 : else
862 : return -1;
863 : }
864 :
865 2 : void pipe_redirect_undo(int my_pipe[2],int saved_stderr,char**errormsg)
866 : {
867 2 : if (saved_stderr !=-1)
868 : {
869 : char reading_buf[1024];
870 2 : memset(reading_buf, 0, 1024);
871 2 : fcntl(my_pipe[0], F_SETFL, O_NONBLOCK);
872 2 : ssize_t r=read(my_pipe[0], reading_buf, 1024);
873 2 : if (r>0)
874 2 : asprintf(errormsg, "%s",reading_buf);
875 2 : dup2(saved_stderr,fileno(stderr));
876 2 : close(saved_stderr);
877 2 : if (my_pipe[0]>0)close(my_pipe[0]);
878 2 : if (my_pipe[1]>0)close(my_pipe[1]);
879 : }
880 2 : }
881 :
882 :
883 11 : int xis_dir (const char *d)
884 : {
885 : DIR *dirptr;
886 :
887 11 : if (access ( d, F_OK ) != -1 ) {
888 : // file exists
889 5 : if ((dirptr = opendir (d)) != NULL) {
890 5 : closedir (dirptr);
891 : } else {
892 : return -2; /* d exists, but not dir */
893 : }
894 : } else {
895 : return -1; /* d does not exist */
896 : }
897 :
898 5 : return 0;
899 : }
|