int file_link(const char *src, const char *dest) { struct stat dest_stat; int r; r = stat(dest, &dest_stat); if (r == 0) { r = unlink(dest); if (r < 0) { opkg_perror(ERROR, "unable to remove `%s'", dest); return -1; } } else if (errno != ENOENT) { opkg_perror(ERROR, "unable to stat `%s'", dest); return -1; } r = symlink(src, dest); if (r < 0) { opkg_perror(DEBUG, "unable to create symlink '%s', falling back to copy", dest); return file_copy(src, dest); } return r; }
static int copy_file_data(FILE * src_file, FILE * dst_file) { size_t nread, nwritten; char buffer[BUFSIZ]; while (1) { nread = fread(buffer, 1, BUFSIZ, src_file); if (nread != BUFSIZ && ferror(src_file)) { opkg_perror(ERROR, "read"); return -1; } /* Check for EOF. */ if (nread == 0) return 0; nwritten = fwrite(buffer, 1, nread, dst_file); if (nwritten != nread) { if (ferror(dst_file)) opkg_perror(ERROR, "write"); else opkg_msg(ERROR, "Unable to write all data.\n"); return -1; } } }
int file_mkdir_hier(const char *path, long mode) { struct stat st; int r; r = stat(path, &st); if (r < 0 && errno == ENOENT) { int status; char *parent; parent = xdirname(path); status = file_mkdir_hier(parent, mode | 0300); free(parent); if (status < 0) return -1; r = mkdir(path, 0777); if (r < 0) { opkg_perror(ERROR, "Cannot create directory `%s'", path); return -1; } if (mode != -1) { r = chmod(path, mode); if (r < 0) { opkg_perror(ERROR, "Cannot set permissions of directory `%s'", path); return -1; } } } return 0; }
extern void *xcalloc(size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); if (ptr == NULL && nmemb != 0 && size != 0) { opkg_perror(ERROR, "calloc"); exit(EXIT_FAILURE); } return ptr; }
extern void *xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (ptr == NULL && size != 0) { opkg_perror(ERROR, "realloc"); exit(EXIT_FAILURE); } return ptr; }
extern void *xmalloc(size_t size) { void *ptr = malloc(size); if (ptr == NULL && size != 0) { opkg_perror(ERROR, "malloc"); exit(EXIT_FAILURE); } return ptr; }
/* Like system(3), but with error messages printed if the fork fails or if the child process dies due to an uncaught signal. Also, the return value is a bit simpler: -1 if there was any problem Otherwise, the 8-bit return value of the program ala WEXITSTATUS as defined in <sys/wait.h>. */ int xsystem(const char *argv[]) { int status; pid_t pid; pid = vfork(); switch (pid) { case -1: opkg_perror(ERROR, "%s: vfork", argv[0]); return -1; case 0: /* child */ execvp(argv[0], (char*const*)argv); _exit(-1); default: /* parent */ break; } if (waitpid(pid, &status, 0) == -1) { opkg_perror(ERROR, "%s: waitpid", argv[0]); return -1; } if (WIFSIGNALED(status)) { opkg_msg(ERROR, "%s: Child killed by signal %d.\n", argv[0], WTERMSIG(status)); return -1; } if (!WIFEXITED(status)) { /* shouldn't happen */ opkg_msg(ERROR, "%s: Your system is broken: got status %d " "from waitpid.\n", argv[0], status); return -1; } return WEXITSTATUS(status); }
unsigned long get_available_kbytes(char *filesystem) { int r; #ifdef HAVE_STATVFS struct statvfs f; r = statvfs(filesystem, &f); if (r == -1) { opkg_perror(ERROR, "Failed to statvfs for %s", filesystem); return 0; } // Actually ((sfs.f_bavail * sfs.f_frsize) / 1024) // and here we try to avoid overflow. if (f.f_frsize >= 1024) return (f.f_bavail * (f.f_frsize / 1024)); else if (f.f_frsize > 0) return f.f_bavail / (1024 / f.f_frsize); #else struct statfs f; r = statfs(filesystem, &f); if (r < 0) { opkg_perror(ERROR, "Failed to statfs for %s", filesystem); return 0; } // Actually ((sfs.f_bavail * sfs.f_bsize) / 1024) // and here we try to avoid overflow. if (f.f_bsize >= 1024) return (f.f_bavail * (f.f_bsize / 1024)); else if (f.f_bsize > 0) return f.f_bavail / (1024 / f.f_bsize); #endif opkg_msg(ERROR, "Unknown block size for target filesystem.\n"); return 0; }
extern char *xstrdup(const char *s) { char *t; if (s == NULL) return NULL; t = strdup(s); if (t == NULL) { opkg_perror(ERROR, "strdup"); exit(EXIT_FAILURE); } return t; }
char *file_sha256sum_alloc(const char *file_name) { static const int sha256sum_bin_len = 32; static const int sha256sum_hex_len = 64; static const unsigned char bin2hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; int i, err; FILE *file; char *sha256sum_hex; unsigned char sha256sum_bin[sha256sum_bin_len]; sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1); file = fopen(file_name, "r"); if (file == NULL) { opkg_perror(ERROR, "Failed to open file %s", file_name); free(sha256sum_hex); return NULL; } err = sha256_stream(file, sha256sum_bin); if (err) { opkg_msg(ERROR, "Could't compute sha256sum for %s.\n", file_name); fclose(file); free(sha256sum_hex); return NULL; } fclose(file); for (i = 0; i < sha256sum_bin_len; i++) { sha256sum_hex[i * 2] = bin2hex[sha256sum_bin[i] >> 4]; sha256sum_hex[i * 2 + 1] = bin2hex[sha256sum_bin[i] & 0xf]; } sha256sum_hex[sha256sum_hex_len] = '\0'; return sha256sum_hex; }
int file_move(const char *src, const char *dest) { int err; err = rename(src, dest); if (err == -1) { if (errno == EXDEV) { /* src & dest live on different file systems */ err = file_copy(src, dest); if (err == 0) unlink(src); } else { opkg_perror(ERROR, "Failed to rename %s to %s", src, dest); } } return err; }
extern char *xstrndup(const char *s, int n) { char *t; size_t len; if (s == NULL) return NULL; len = strlen (s); if (n < len) len = n; t = (char*) malloc (len + 1); if (t == NULL) { opkg_perror(ERROR, "strdup"); exit(EXIT_FAILURE); } memcpy (t, s, len); t[len] = '\0'; return t; }
char *file_sha256sum_alloc(const char *file_name) { int err; FILE *file; unsigned char sha256sum_bin[32]; file = fopen(file_name, "r"); if (file == NULL) { opkg_perror(ERROR, "Failed to open file %s", file_name); return NULL; } err = sha256_stream(file, sha256sum_bin); if (err) { opkg_msg(ERROR, "Could't compute sha256sum for %s.\n", file_name); fclose(file); return NULL; } fclose(file); return sha256_to_string(sha256sum_bin); }
char *file_md5sum_alloc(const char *file_name) { int err; FILE *file; unsigned char md5sum_bin[16]; file = fopen(file_name, "r"); if (file == NULL) { opkg_perror(ERROR, "Failed to open file %s", file_name); return NULL; } err = md5_stream(file, md5sum_bin); if (err) { opkg_msg(ERROR, "Could't compute md5sum for %s.\n", file_name); fclose(file); return NULL; } fclose(file); return md5_to_string(md5sum_bin); }
int rm_r(const char *path) { int ret = 0; DIR *dir; struct dirent *dent; int r; if (path == NULL) { opkg_perror(ERROR, "Missing directory parameter"); return -1; } dir = opendir(path); if (dir == NULL) { opkg_perror(ERROR, "Failed to open dir %s", path); return -1; } r = fchdir(dirfd(dir)); if (r == -1) { opkg_perror(ERROR, "Failed to change to dir %s", path); closedir(dir); return -1; } while (1) { errno = 0; dent = readdir(dir); if (dent == NULL) { if (errno) { opkg_perror(ERROR, "Failed to read dir %s", path); ret = -1; } break; } if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; #ifdef _BSD_SOURCE if (dent->d_type == DT_DIR) { ret = rm_r(dent->d_name); if (ret == -1) break; continue; } else if (dent->d_type == DT_UNKNOWN) #endif { struct stat st; ret = lstat(dent->d_name, &st); if (ret == -1) { opkg_perror(ERROR, "Failed to lstat %s", dent->d_name); break; } if (S_ISDIR(st.st_mode)) { ret = rm_r(dent->d_name); if (ret == -1) break; continue; } } ret = unlink(dent->d_name); if (ret == -1) { opkg_perror(ERROR, "Failed to unlink %s", dent->d_name); break; } } r = chdir(".."); if (r == -1) { ret = -1; opkg_perror(ERROR, "Failed to change to dir %s/..", path); } r = rmdir(path); if (r == -1) { ret = -1; opkg_perror(ERROR, "Failed to remove dir %s", path); } r = closedir(dir); if (r == -1) { ret = -1; opkg_perror(ERROR, "Failed to close dir %s", path); } return ret; }
int opkg_download(const char *src, const char *dest_file_name, curl_progress_func cb, void *data, const short hide_error) { int err = 0; char *src_basec = xstrdup(src); char *src_base = basename(src_basec); char *tmp_file_location; opkg_msg(NOTICE,"Downloading %s.\n", src); if (str_starts_with(src, "file:")) { const char *file_src = src + 5; opkg_msg(INFO, "Copying %s to %s...", file_src, dest_file_name); err = file_copy(file_src, dest_file_name); opkg_msg(INFO, "Done.\n"); free(src_basec); return err; } sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base); free(src_basec); err = unlink(tmp_file_location); if (err && errno != ENOENT) { opkg_perror(ERROR, "Failed to unlink %s", tmp_file_location); free(tmp_file_location); return -1; } if (conf->http_proxy) { opkg_msg(DEBUG, "Setting environment variable: http_proxy = %s.\n", conf->http_proxy); setenv("http_proxy", conf->http_proxy, 1); } if (conf->ftp_proxy) { opkg_msg(DEBUG, "Setting environment variable: ftp_proxy = %s.\n", conf->ftp_proxy); setenv("ftp_proxy", conf->ftp_proxy, 1); } if (conf->no_proxy) { opkg_msg(DEBUG,"Setting environment variable: no_proxy = %s.\n", conf->no_proxy); setenv("no_proxy", conf->no_proxy, 1); } #ifdef HAVE_CURL CURLcode res; FILE * file = fopen (tmp_file_location, "w"); curl = opkg_curl_init (cb, data); if (curl) { curl_easy_setopt (curl, CURLOPT_URL, src); curl_easy_setopt (curl, CURLOPT_WRITEDATA, file); res = curl_easy_perform (curl); fclose (file); if (res) { long error_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &error_code); opkg_msg(hide_error?DEBUG2:ERROR, "Failed to download %s: %s.\n", src, curl_easy_strerror(res)); free(tmp_file_location); return -1; } } else { free(tmp_file_location); return -1; } #else { int res; const char *argv[8]; int i = 0; argv[i++] = "wget"; argv[i++] = "-q"; if (conf->http_proxy || conf->ftp_proxy) { argv[i++] = "-Y"; argv[i++] = "on"; } argv[i++] = "-O"; argv[i++] = tmp_file_location; argv[i++] = src; argv[i++] = NULL; res = xsystem(argv); if (res) { opkg_msg(ERROR, "Failed to download %s, wget returned %d.\n", src, res); free(tmp_file_location); return -1; } } #endif err = file_move(tmp_file_location, dest_file_name); free(tmp_file_location); return err; }
int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, char **buf0, size_t buf0len) { int ret, lineno; char *buf, *nl; size_t buflen; lineno = 1; ret = 0; buflen = buf0len; buf = *buf0; buf[0] = '\0'; while (1) { if (fgets(buf, (int)buflen, fp) == NULL) { if (ferror(fp)) { opkg_perror(ERROR, "fgets"); ret = -1; } else if (strlen(*buf0) == buf0len-1) { opkg_msg(ERROR, "Missing new line character" " at end of file!\n"); parse_line(item, *buf0, mask); } break; } nl = strchr(buf, '\n'); if (nl == NULL) { if (strlen(buf) < buflen-1) { /* * Line could be exactly buflen-1 long and * missing a newline, but we won't know until * fgets fails to read more data. */ opkg_msg(ERROR, "Missing new line character" " at end of file!\n"); parse_line(item, *buf0, mask); break; } if (buf0len >= EXCESSIVE_LINE_LEN) { opkg_msg(ERROR, "Excessively long line at " "%d. Corrupt file?\n", lineno); ret = -1; break; } /* * Realloc and point buf past the data already read, * at the NULL terminator inserted by fgets. * |<--------------- buf0len ----------------->| * | |<------- buflen ---->| * |---------------------|---------------------| * buf0 buf */ buflen = buf0len +1; buf0len *= 2; *buf0 = xrealloc(*buf0, buf0len); buf = *buf0 + buflen -2; continue; } *nl = '\0'; lineno++; if (parse_line(item, *buf0, mask)) break; buf = *buf0; buflen = buf0len; buf[0] = '\0'; } return ret; }
int file_copy(const char *src, const char *dest) { struct stat src_stat; struct stat dest_stat; int dest_exists = 1; int status = 0; int r; r = stat(src, &src_stat); if (r < 0) { opkg_perror(ERROR, "%s", src); return -1; } r = stat(dest, &dest_stat); if (r < 0) { if (errno != ENOENT) { opkg_perror(ERROR, "unable to stat `%s'", dest); return -1; } dest_exists = 0; } else { int is_same_file = (src_stat.st_rdev == dest_stat.st_rdev && src_stat.st_ino == dest_stat.st_ino); if (is_same_file) { opkg_msg(ERROR, "`%s' and `%s' are the same file.\n", src, dest); return -1; } } if (S_ISREG(src_stat.st_mode)) { FILE *sfp, *dfp; struct utimbuf times; if (dest_exists) { dfp = fopen(dest, "w"); if (dfp == NULL) { r = unlink(dest); if (r < 0) { opkg_perror(ERROR, "unable to remove `%s'", dest); return -1; } } } else { int fd; fd = open(dest, O_WRONLY | O_CREAT, src_stat.st_mode); if (fd < 0) { opkg_perror(ERROR, "unable to open `%s'", dest); return -1; } dfp = fdopen(fd, "w"); if (dfp == NULL) { if (fd >= 0) close(fd); opkg_perror(ERROR, "unable to open `%s'", dest); return -1; } } sfp = fopen(src, "r"); if (sfp) { r = copy_file_data(sfp, dfp); if (r < 0) status = -1; r = fclose(sfp); if (r < 0) { opkg_perror(ERROR, "unable to close `%s'", src); status = -1; } } else { opkg_perror(ERROR, "unable to open `%s'", src); status = -1; } r = fclose(dfp); if (r < 0) { opkg_perror(ERROR, "unable to close `%s'", dest); status = -1; } times.actime = src_stat.st_atime; times.modtime = src_stat.st_mtime; r = utime(dest, ×); if (r < 0) opkg_perror(ERROR, "unable to preserve times of `%s'", dest); r = chown(dest, src_stat.st_uid, src_stat.st_gid); if (r < 0) { src_stat.st_mode &= ~(S_ISUID | S_ISGID); opkg_perror(ERROR, "unable to preserve ownership of `%s'", dest); } r = chmod(dest, src_stat.st_mode); if (r < 0) opkg_perror(ERROR, "unable to preserve permissions of `%s'", dest); return status; } else if (S_ISBLK(src_stat.st_mode) || S_ISCHR(src_stat.st_mode) || S_ISSOCK(src_stat.st_mode)) { r = mknod(dest, src_stat.st_mode, src_stat.st_rdev); if (r < 0) { opkg_perror(ERROR, "unable to create `%s'", dest); return -1; } } else if (S_ISFIFO(src_stat.st_mode)) { r = mkfifo(dest, src_stat.st_mode); if (r < 0) { opkg_perror(ERROR, "cannot create fifo `%s'", dest); return -1; } } else if (S_ISDIR(src_stat.st_mode)) { opkg_msg(ERROR, "%s: omitting directory.\n", src); return -1; } opkg_msg(ERROR, "internal error: unrecognized file type.\n"); return -1; }