/* $Id: common.c 1555 2006-08-17 20:10:28Z mipsator $ */
/*
* Copyright (c) 2003-2006 Damien Couderc
* Copyright (c) 2003-2004 Xavier Santolaria <xavier@santolaria.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* - Neither the name of the copyright holder(s) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* Credits for patches :
* - Ted Unangst
*/
#include <sys/param.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include "compat/pmk_string.h"
#include "compat/pmk_stdio.h"
#include "compat/pmk_unistd.h"
#include "common.h"
/*#define MKVAR_DEBUG 1*/
FILE *pmk_log_fp;
/**************
* get_line() *
***********************************************************************
DESCR
get a line from a file and remove newline character
IN
fd : file descriptor
line : buffer that will contain the line
lsize : size of the buffer
OUT
returns a boolean :
- true when a line is available
- false when error or eof occured
***********************************************************************/
bool get_line(FILE *fd, char *line, size_t lsize) {
char *p;
if (fgets(line, lsize, fd) != NULL) {
p = line;
while (*p != CHAR_EOS) {
if (*p == '\n') {
/* remove trailing newline */
*p= CHAR_EOS;
}
p++;
}
return(true);
} else {
/* reached eof or error */
return(false);
}
}
/****************
* env_to_opt() *
***********************************************************************
DESCR
put env variable in an option
IN
env_name : variable name
opt : option struct
OUT
returns true if env_name exists
***********************************************************************/
bool env_to_opt(char *env_name, pmkcmdopt *opt) {
bool rval;
char *env_val;
env_val = getenv(env_name);
if (env_val == NULL) {
/* env variable name not found */
rval = false;
} else {
/* okay get it */
if (strlcpy_b(opt->value, env_val,
sizeof(opt->value)) == false) {
rval = true;
} else {
rval = false;
}
}
return(rval);
}
/******************
* get_make_var() *
***********************************************************************
DESCR
get variable content from make
IN
varname: name of the variable like for example CC
result: storage of result
rsize: result size
OUT
boolean
***********************************************************************/
bool get_make_var(char *varname, char *result, size_t rsize) {
FILE *mfp,
*tfp;
bool rval;
char mfn[MAXPATHLEN],
varstr[TMP_BUF_LEN];
if (strlcpy_b(mfn, TMP_MK_FILE, sizeof(mfn)) == false) {
errorf("failed to create temporary file");
return(false);
}
mfp = tmps_open(TMP_MK_FILE, "w", mfn, sizeof(mfn), strlen(MK_FILE_EXT));
if (mfp != NULL) {
/* create a tmp makefile with the following format :
all:
@printf ${VARNAME}
/!\ should check content of VARNAME, could result
in a security breach.
*/
fprintf(mfp, MKVAR_FMT_MK, varname, MKVAR_FILE);
fclose(mfp);
#ifdef MKVAR_DEBUG
debugf(MKVAR_FMT_MK, varname, MKVAR_FILE);
#endif
} else {
#ifdef MKVAR_DEBUG
errorf("failed to open '%s' : %s.", mfn, strerror(errno));
#endif
return(false);
}
if (snprintf_b(varstr, sizeof(varstr), MKVAR_FMT_CMD, mfn) == false)
return(false);
if (system(varstr) == 0) {
tfp = fopen(MKVAR_FILE, "r");
if (tfp != NULL) {
/* catch output of make */
if (get_line(tfp, result, rsize) == false) {
#ifdef MKVAR_DEBUG
errorf("failed to get result from '%s' : %s.",
varstr, strerror(errno));
#endif
rval = false;
}
fclose(tfp);
rval = true;
} else {
#ifdef MKVAR_DEBUG
errorf("failed to open '%s' : %s.", varstr,
strerror(errno));
#endif
rval = false;
}
} else {
#ifdef MKVAR_DEBUG
errorf("failed to execute '%s' : %s.", varstr,
strerror(errno));
#endif
rval = false;
}
if (unlink(mfn) == -1) {
/* cannot remove temporary file */
errorf("cannot remove temporary file: '%s' : %s.",
mfn, strerror(errno));
}
if (unlink(MKVAR_FILE) == -1) {
/* cannot remove temporary file */
#ifdef MKVAR_DEBUG
errorf("cannot remove temporary file: '%s' : %s.",
mfn, strerror(errno));
#endif
}
return(rval);
}
/******************
* str_to_ulong() *
***********************************************************************
DESCR
convert a string into an unsigned long
IN
XXX
OUT
XXX
***********************************************************************/
bool str_to_ulong(char *str, int base, unsigned long *value) {
char *ep;
*value = strtoul(str, &ep, base);
if (*str == '\0' || *ep != '\0') {
return(false); /* not a number */
}
if ((errno == ERANGE) && (*value == ULONG_MAX)) {
return(false); /* out of range */
}
return(true);
}
/*******************
* str_to_dynary() *
***********************************************************************
DESCR
split a string into a dynamic array (one separator)
IN
str : string to split
sep : separator
OUT
dynary or NULL
NOTE
move to dynary.c ?
***********************************************************************/
dynary *str_to_dynary(char *str, char sep) {
static char buf[2];
snprintf(buf, sizeof(buf), "%c", sep); /* should not overflow */
return(str_to_dynary_adv(str, buf));
}
/***********************
* str_to_dynary_adv() *
***********************************************************************
DESCR
split a string into a dynamic array (list of separators)
IN
str : string to split
sep : separators list
OUT
dynary or NULL
NOTE
move to dynary.c ?
***********************************************************************/
dynary *str_to_dynary_adv(char *str, char *seplst) {
char buf[MAXPATHLEN],
*pbuf;
dynary *da;
int s;
if (str == NULL) {
/* protect against NULL */
return(NULL);
}
/* init dynary */
da = da_init();
if (da == NULL) {
return(NULL);
}
s = sizeof(buf);
pbuf = buf;
while (*str != CHAR_EOS) {
/* check if character is in separator list */
if (strchr(seplst, *str) != NULL) {
*pbuf = CHAR_EOS;
if (da_push(da, strdup(buf)) == false) {
da_destroy(da);
return(NULL);
}
pbuf = buf;
s = sizeof(buf);
} else {
*pbuf = *str;
pbuf++;
s--;
if (s == 0) {
/* not enough space in buffer */
da_destroy(da);
return(NULL);
}
}
str++;
}
*pbuf = CHAR_EOS;
if (da_push(da, strdup(buf)) == false) {
da_destroy(da);
return(NULL);
}
return(da);
}
/*******************
* find_file_dir() *
***********************************************************************
DESCR
find if one dir contain a given file in the specified list of path
IN
da : path list
fname : file to search
fpath : storage of the directory
fplen : size of the storage
OUT
boolean
***********************************************************************/
bool find_file_dir(dynary *da, char *fname, char *fpath, size_t fplen) {
char tstr[MAXPATHLEN],
*path;
unsigned int i;
for (i = 0 ; i < da_usize(da) ; i++) {
path = da_idx(da, i);
strlcpy(tstr, path, sizeof(tstr)); /* no check */
strlcat(tstr, "/", sizeof(tstr)); /* no check */
if (strlcat_b(tstr, fname, sizeof(tstr)) == true) {
if (access(tstr, F_OK) == 0) { /* no race condition here */
if (strlcpy_b(fpath, path, fplen) == true) {
/* fpath correctly set */
return(true);
} else {
errorf("strlcpy failed in find_file_dir().");
return(false);
}
}
}
}
/* not found */
return(false);
}
/***************
* find_file() *
***********************************************************************
DESCR
find a file in the specified list of path
IN
da : path list
fname : file to search
fpath : storage of the full path
fplen : size of the storage
OUT
boolean
***********************************************************************/
bool find_file(dynary *da, char *fname, char *fpath, size_t fplen) {
bool rval = false;
if (find_file_dir(da, fname, fpath, fplen) == true) {
strlcat(fpath, "/", fplen); /* no check */
if (strlcat_b(fpath, fname, fplen) == true) {
/* fpath set correctly */
rval = true;
}
}
return(rval);
}
/*******************
* get_file_path() *
***********************************************************************
DESCR
get path of given filename in given path list
IN
filename : name of the file to look for
path : string of the list of path
storage : storage for resulting path
size : size of storage
OUT
returns true if filename is found in one of the list's path
***********************************************************************/
bool get_file_path(char *filename, char *path, char *storage, size_t size) {
bool rval = false;
dynary *bplst;
/* fill dynary with path */
bplst= str_to_dynary(path, PATH_STR_DELIMITER);
if (bplst == NULL) {
errorf("failed to put a path into a dynamic array.");
return(false);
}
/* try to locate binary */
if (find_file(bplst, filename, storage, size) == true) {
rval = true;
} else {
rval = false;
}
da_destroy(bplst);
return(rval);
}
/************
* errorf() *
***********************************************************************
DESCR
formated simple error
IN
fmt : format string followed by arguments
OUT
NONE
***********************************************************************/
void errorf(const char *fmt, ...) {
char buf[TMP_BUF_LEN];
va_list plst;
va_start(plst, fmt);
vsnprintf(buf, sizeof(buf), fmt, plst);
va_end(plst);
fprintf(stderr, "Error : %s\n", buf);
}
/*****************
* errorf_line() *
***********************************************************************
DESCR
formated parse error
IN
filename : parsed file name
line : line of error
fmt : format string followed by arguments
OUT
NONE
***********************************************************************/
void errorf_line(char *filename, int line, const char *fmt, ...) {
char buf[TMP_BUF_LEN];
va_list plst;
va_start(plst, fmt);
vsnprintf(buf, sizeof(buf), fmt, plst);
va_end(plst);
fprintf(stderr, "Error in '%s' line %d : %s\n", filename, line, buf);
}
/************
* debugf() *
***********************************************************************
DESCR
formated debug message
IN
fmt : format string followed by arguments
OUT
NONE
***********************************************************************/
void debugf(const char *fmt, ...) {
char buf[TMP_BUF_LEN];
va_list plst;
va_start(plst, fmt);
vsnprintf(buf, sizeof(buf), fmt, plst);
va_end(plst);
fprintf(stdout, "!DEBUG! %s\n", buf);
fflush(stdout);
}
/******************
* pmk_log_open() *
***********************************************************************
DESCR
open log file
IN
logname : log file name
OUT
returns true if opened
***********************************************************************/
bool pmk_log_open(char *logname) {
if (pmk_log_fp != NULL) {
errorf("'%s' is already open.", logname);
return(false);
}
pmk_log_fp = fopen(logname, "w");
if (pmk_log_fp == NULL) {
errorf("while opening '%s'.", logname);
return(false);
} else {
return(true);
}
}
/*******************
* pmk_log_close() *
***********************************************************************
DESCR
close log file
IN
NONE
OUT
NONE
***********************************************************************/
void pmk_log_close(void) {
fflush(pmk_log_fp);
fclose(pmk_log_fp);
}
/*************
* pmk_log() *
***********************************************************************
DESCR
log formatted line
IN
fmt : format string
OUT
boolean
***********************************************************************/
bool pmk_log(const char *fmt, ...) {
char buf[TMP_BUF_LEN];
va_list plst;
va_start(plst, fmt);
vsnprintf(buf, sizeof(buf), fmt, plst);
va_end(plst);
if (pmk_log_fp != NULL) {
fprintf(pmk_log_fp, buf);
fflush(pmk_log_fp);
fprintf(stdout, buf);
fflush(stdout);
return(true);
} else {
errorf("unable to log.");
return(false);
}
}
/***********
* fcopy() *
***********************************************************************
DESCR
copy file
IN
src : file to copy
dst : destination file
mode : destination perms
OUT
boolean
***********************************************************************/
bool fcopy(char *src, char *dst, mode_t mode) {
char cbuf[S_BLKSIZE];
bool do_loop = true,
rval = true;
int src_fd,
dst_fd;
ssize_t rsz;
/* try to open both source and destination files */
src_fd = open(src, O_RDONLY, 0);
if (src_fd == -1) {
errorf("cannot open '%s' : %s.", src, strerror(errno));
return(false);
}
/*debugf("mode = %o", mode);*/
dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (dst_fd == -1) {
close(src_fd);
errorf("cannot open '%s' : %s.", dst, strerror(errno));
return(false);
}
while (do_loop == true) {
/* reading data */
rsz = read(src_fd, cbuf, sizeof(cbuf));
switch(rsz) {
case -1:
/* read error */
errorf("failed to read '%s' : %s.", src, strerror(errno));
do_loop = false;
rval = false;
break;
case 0:
/* no more data to copy */
do_loop = false;
break;
default:
/* data read, trying to write */
if (write(dst_fd, cbuf, rsz) != rsz) {
/* write failed */
errorf("failed to write '%s' : %s.", dst, strerror(errno));
do_loop = false;
rval = false;
}
break;
}
}
close(src_fd);
close(dst_fd);
return(rval);
}
/**************
* tmp_open() *
***********************************************************************
DESCR
open temporary file
IN
tfile : template file name
mode : file mode
buf : buffer for the randomized file name
bsize : buffer size
OUT
file structure or NULL
***********************************************************************/
FILE *tmp_open(char *tfile, char *mode, char *buf, size_t bsize) {
int fd;
/* copy file name in buf */
if (strlcpy_b(buf, tfile, bsize) == false)
return(NULL);
/* randomize file name */
fd = mkstemp(buf);
if (fd == -1) {
return(NULL);
}
return(fdopen(fd, mode));
}
/**************
* tmps_open() *
***********************************************************************
DESCR
open temporary file with suffix
IN
tfile : template file name
mode : file mode
buf : buffer for the randomized file name
bsize : buffer size
slen : suffix length
OUT
file structure or NULL
***********************************************************************/
FILE *tmps_open(char *tfile, char *mode, char *buf, size_t bsize, size_t slen) {
int fd;
/* copy file name in buf */
if (strlcpy_b(buf, tfile, bsize) == false)
return(NULL);
/* randomize file name */
fd = mkstemps(buf, slen);
if (fd == -1) {
return(NULL);
}
return(fdopen(fd, mode));
}
syntax highlighted by Code2HTML, v. 0.9.1