/** * @brief get size of dir * * @param pathname [in] path of dir * * @return size of dir, if succ; -1, if failed. */ int get_dir_size(const char *pathname) { struct dirent *dir = NULL; struct stat st = {0}; DIR *d = NULL; int total_size = 0; char buf[512] = {0}; if (pathname == NULL) return -1; if (lstat(pathname, &st) < 0) return -1; if (!S_ISDIR(st.st_mode)) return -1; if ((d = opendir(pathname)) == NULL) return -1; while ((dir = readdir(d)) != NULL) { if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")) continue; sprintf(buf, "%s/%s", pathname, dir->d_name); if (lstat(buf, &st) >= 0) { if (S_ISDIR(st.st_mode)) { total_size += get_dir_size(dir->d_name); } else total_size += st.st_size; } } closedir(d); return total_size; }
static double get_dir_size(const char *dirname, char **worst_file, double *worst_file_size) { DIR *dp = opendir(dirname); if (!dp) return 0; /* "now" is used only if caller wants to know worst_file */ time_t now = worst_file ? time(NULL) : 0; struct dirent *dent; struct stat stats; double size = 0; while ((dent = readdir(dp)) != NULL) { if (dot_or_dotdot(dent->d_name)) continue; char *fullname = concat_path_file(dirname, dent->d_name); if (lstat(fullname, &stats) != 0) { free(fullname); continue; } if (S_ISDIR(stats.st_mode)) { double sz = get_dir_size(fullname, worst_file, worst_file_size); size += sz; } else if (S_ISREG(stats.st_mode)) { double sz = stats.st_size; size += sz; if (worst_file) { /* Calculate "weighted" size and age * w = sz_kbytes * age_mins */ sz /= 1024; long age = (now - stats.st_mtime) / 60; if (age > 0) sz *= age; if (sz > *worst_file_size) { *worst_file_size = sz; free(*worst_file); *worst_file = fullname; fullname = NULL; } } } free(fullname); } closedir(dp); return size; }
/** * @brief get size of file * * @param pathname [in] pathname of file * * @return size, if succ; -1, if failed. */ int get_file_size(const char *pathname) { struct stat st = {0}; if (pathname == NULL) return -1; if (lstat(pathname, &st) < 0) return -1; if (S_ISDIR(st.st_mode)) return get_dir_size(pathname); else return st.st_size; return -1; }
ssize_t get_dir_size(struct mic_info *mic, char *dirpath) { struct dirent *tmp; DIR *dir; char path[PATH_MAX]; struct stat data; size_t result = 0; if ((dir = opendir(dirpath)) == NULL) { mpsslog(PINFO, "%s: Could not open dir %s\n", mic->name, dirpath); return -1; } while ((tmp = readdir(dir))) { if (!strcmp(tmp->d_name, ".") || !strcmp(tmp->d_name, "..")) continue; snprintf(path, PATH_MAX - 1, "%s/%s", dirpath, tmp->d_name); if (lstat(path, &data) < 0) { mpsslog(PINFO, "%s: Couldn't lstat %s: %s\n", mic->name, path, strerror(errno)); continue; } if (S_ISDIR(data.st_mode) && !S_ISLNK(data.st_mode)) { ssize_t dirsize; strcat(path, "/"); if ((dirsize = get_dir_size(mic, path)) < 0) { mpsslog(PINFO, "%s: getting directory size failed %s %s\n", mic->name, path, strerror(errno)); return dirsize; } result += dirsize; } else if (S_ISREG(data.st_mode)) { result += data.st_size; } } closedir(dir); return result; }
/** * Check whether there is enough space on disk to create storage * * @param path Path to storage * * @return 1 if enough space exists, 0 otherwise */ int check_space(const char *path) { struct statvfs stat; off_t size; int ret; ret = get_dir_size(path, &size); if (ret < 0) { LOGE("Failed to compute storage size %s", path); return ret; } ret = statvfs(path, &stat); if (ret < 0) { LOGE("Failed to compute free space for storage %s", path); return ret; } if ((unsigned)size < stat.f_bsize * stat.f_bfree) return 1; return 0; }
static void delete_files(gpointer data, gpointer void_preserve_list) { double cap_size; const char *dir = parse_size_pfx(&cap_size, data); GList *preserve_files_list = void_preserve_list; unsigned count = 100; while (--count != 0) { GList *worst_file_list = NULL; double cur_size = get_dir_size(dir, &worst_file_list, preserve_files_list); if (cur_size <= cap_size || !worst_file_list) { list_free_with_free(worst_file_list); log_info("cur_size:%.0f cap_size:%.0f, no (more) trimming", cur_size, cap_size); break; } /* Invert the list, so that largest/oldest file is first */ worst_file_list = g_list_reverse(worst_file_list); /* And delete (some of) them */ while (worst_file_list && cur_size > cap_size) { struct name_and_size *ns = worst_file_list->data; log_notice("%s is %.0f bytes (more than %.0f MB), deleting '%s' (%llu bytes)", dir, cur_size, cap_size / (1024*1024), ns->name, (long long)ns->size); if (unlink(ns->name) != 0) perror_msg("Can't unlink '%s'", ns->name); else cur_size -= ns->size; free(ns); worst_file_list = g_list_delete_link(worst_file_list, worst_file_list); } } }
static void delete_files(gpointer data, gpointer user_data_unused) { double cap_size; const char *dir = parse_size_pfx(&cap_size, data); unsigned count = 1000; while (--count != 0) { char *worst_file = NULL; double worst_file_size = 0; double cur_size = get_dir_size(dir, &worst_file, &worst_file_size); if (cur_size <= cap_size) { VERB2 log("cur_size:%f cap_size:%f, no (more) trimming", cur_size, cap_size); free(worst_file); break; } log("%s is %.0f bytes (more than %.0f MB), deleting '%s'", dir, cur_size, cap_size / (1024*1024), worst_file); if (unlink(worst_file) != 0) perror_msg("Can't unlink '%s'", worst_file); free(worst_file); } }
u64 fs::get_dir_size(const std::string& path) { u64 result = 0; for (const auto entry : dir(path)) { if (entry.name == "." || entry.name == "..") { continue; } if (entry.is_directory == false) { result += entry.size; } if (entry.is_directory == true) { result += get_dir_size(path + '/' + entry.name); } } return result; }
/** * Copy multiple files from source to destination * * @param file_list File list * @param src_path Source * @param dst_path Destination * * @return 0 on success, negative value if an error occurs */ static int copy_files(file_info ** file_list, const char *src_path, const char *dst_path) { file_info *iter = *file_list; char path[MAX_PATH_LENGTH + 1], buff[PROPERTY_VALUE_MAX], *linkname; char property[PROPERTY_KEY_MAX], path_hash_hex[ECRYPTFS_SIG_LEN * 2 + 1]; unsigned char path_hash[ECRYPTFS_SIG_LEN]; int len = 0, ret = -1; off64_t done = 0, total = 0; if (strlen(src_path) > MAX_PATH_LENGTH || strlen(dst_path) > MAX_PATH_LENGTH) { LOGE("Invalid arguments\n"); return ret; } ret = get_dir_size(src_path, &total); if (ret < 0) { LOGE("Failed to compute storage size %s", src_path); return ret; } memset(property, 0, sizeof(property)); memcpy(property, property_prefix, strlen(property_prefix)); SHA512((unsigned char *)src_path, strlen(src_path), path_hash); convert_to_hex_format(path_hash, path_hash_hex, ECRYPTFS_SIG_LEN); memcpy(property + strlen(property_prefix), path_hash_hex, SHA_HEAD); memset(buff, 0, sizeof(buff)); snprintf(buff, sizeof(buff), "%llu", (off64_t)(done / (double)total * 100)); ret = property_set(property, buff); if (ret < 0) { LOGE("property_set"); } while (iter) { len = strlen(dst_path) + strlen(iter->path) - strlen(src_path) + 1; if (len > MAX_PATH_LENGTH) { LOGE("Invalig len\n"); return -1; } strcpy(path, dst_path); path[strlen(dst_path)] = '/'; strcpy(path + strlen(dst_path) + 1, iter->path + strlen(src_path)); if (S_ISLNK(iter->st.st_mode)) { linkname = malloc(iter->st.st_size + 1); if (linkname == NULL) { LOGE("insufficient memory\n"); exit(EXIT_FAILURE); } ret = readlink(iter->path, linkname, iter->st.st_size + 1); if (ret < 0) { free(linkname); LOGE("lstat failed\n"); return -1; } linkname[iter->st.st_size] = '\0'; ret = symlink(linkname, path); if (ret < 0) { free(linkname); LOGE("can't create symlink %s", path); return ret; } ret = lsetfilecon(path, iter->con); if (ret < 0) { LOGE("lsetfilecon %s fail\n", iter->path); free(linkname); return ret; } ret = lchown(path, iter->st.st_uid, iter->st.st_gid); if (ret < 0) { LOGE("lchown %s fail\n", iter->path); free(linkname); return ret; } free(linkname); iter = iter->next; continue; } ret = copy_file(property, iter->path, path, &iter->st, iter->con, &done, &total); if (ret < 0) { LOGE("Copying file form %s to %s failed\n", iter->path, path); return ret; } iter = iter->next; } return 0; }
/** * Get size on disk for a directory * Similar functionality with du -c * @param path Directory path * @param size Directory size * * @return 0 for success, negative value in case of an error */ int get_dir_size(const char *path, off64_t * size) { DIR *dir; struct dirent *dirent; struct stat st; int len, ret = -1; char *file_path; len = strlen(path); if (len > MAX_PATH_LENGTH) { LOGE("Invalid argument %s\n", path); return -1; } dir = opendir(path); if (!dir) { LOGE("open dir %s failed", path); return -1; } while ((dirent = readdir(dir))) { int file_len = strlen(dirent->d_name); /* This should not happen */ if (file_len > MAX_FILE_LENGTH) { LOGE("file system error\n"); closedir(dir); return -1; } /* ignore /. and /.. */ if (file_len == 1 || file_len == 2) { if (dirent->d_name[0] == '.') { if (dirent->d_name[1] == '\0') continue; if ((dirent->d_name[1] == '.') && (dirent->d_name[2] == '\0')) continue; } } file_path = (char *)malloc(MAX_PATH_LENGTH + MAX_FILE_LENGTH + 1); if (!file_path) return -1; memset(file_path, 0, MAX_PATH_LENGTH + MAX_FILE_LENGTH + 1); strcpy(file_path, path); *(file_path + len) = '/'; strcpy(file_path + len + 1, dirent->d_name); ret = lstat(file_path, &st); if (ret < 0) { LOGE("lstat failed on %s\n", file_path); closedir(dir); free(file_path); return ret; } *size += st.st_size; if (dirent->d_type == DT_DIR) { ret = get_dir_size(file_path, size); if (ret < 0) { free(file_path); return ret; } } free(file_path); } closedir(dir); return 0; }
static double get_dir_size(const char *dirname, GList **pp_worst_file_list, GList *preserve_files_list ) { DIR *dp = opendir(dirname); if (!dp) return 0; /* "now" is used only if caller wants to know worst_file */ time_t now = pp_worst_file_list ? time(NULL) : 0; struct dirent *dent; double size = 0; while ((dent = readdir(dp)) != NULL) { if (dot_or_dotdot(dent->d_name)) continue; char *fullname = concat_path_file(dirname, dent->d_name); struct stat stats; if (lstat(fullname, &stats) != 0) goto next; if (S_ISDIR(stats.st_mode)) { double sz = get_dir_size(fullname, pp_worst_file_list, preserve_files_list); size += sz; } else if (S_ISREG(stats.st_mode) || S_ISLNK(stats.st_mode)) { double sz = stats.st_size; /* Account for filename and inode storage (approximately). * This also makes even zero-length files to have nonzero cost. */ sz += strlen(dent->d_name) + sizeof(stats); size += sz; if (pp_worst_file_list) { GList *cur = preserve_files_list; while (cur) { //log_warning("'%s' ? '%s'", fullname, *pp); if (strcmp(fullname, (char*)cur->data) == 0) goto next; cur = cur->next; } /* Calculate "weighted" size and age * w = sz_kbytes * age_mins */ sz /= 1024; long age = (now - stats.st_mtime) / 60; if (age > 1) sz *= age; *pp_worst_file_list = insert_name_and_sizes(*pp_worst_file_list, fullname, sz, stats.st_size); } } next: free(fullname); } closedir(dp); return size; }
/** * Encrypt Android user data * * @param user Android user id * @param password Android user password * * @return 0 on success, negative value on error */ int android_encrypt_user_data(int user, char *password) { char data_path[MAX_PATH_LENGTH], media_path[MAX_PATH_LENGTH], buf[10]; off_t size = 0, total_size = 0; int ret = -1; LOGI("Encrypt user data for %d", user); android_stop_services(); sleep(5); memset(data_path, 0, sizeof(data_path)); sprintf(data_path, "%s%d", ANDROID_USER_DATA_PATH, user); memset(media_path, 0, sizeof(media_path)); sprintf(media_path, "%s%d", ANDROID_VIRTUAL_SDCARD_PATH, user); ret = get_dir_size(data_path, &size); if (ret < 0) { LOGE("Unable to get dir size for %s", data_path); return ret; } total_size += size; ret = get_dir_size(media_path, &size); if (ret < 0) { LOGE("Unable to get dir size for %s", media_path); return ret; } total_size += size; memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf), "%llu", total_size); property_set("efs.encrypt.size", buf); if (user == PRIMARY_USER) { property_set("crypto.primary_user", "encrypting"); } ret = EFS_create(data_path, password); if (ret < 0) { LOGE("Unable to create efs storage %s", data_path); return ret; } ret = EFS_create(media_path, password); if (ret < 0) { LOGE("Unable to create efs storage %s", media_path); return ret; } if (user == PRIMARY_USER) { android_reboot(ANDROID_RB_RESTART, 0, 0); } ret = android_unlock_user_data(user, password); if (ret < 0) { LOGE("Unable to unlock user data %d", user); return ret; } android_start_services(); return 0; }
void * save_crashdump(void *arg) { struct mic_info *mic = (struct mic_info *)arg; struct mpssd_info *mpssdi = (struct mpssd_info *)mic->data; int cdfd = -1; int procfd = -1; void *addr = NULL; ssize_t bytes; ssize_t total_bytes = 0; ssize_t dirlimit; ssize_t diractual; struct tm *tm = NULL; char pathname[PATH_MAX]; time_t t; pid_t pid1 = 0; char *state; char *save; struct stat sbuf; struct statvfs vbuf; int err; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); if ((dirlimit = atoi(CD_LIMIT) * (1024 * 1024 * 1024ULL)) == 0) { mpsslog(PWARN, "%s: [SaveCrashDump] Dump disabled\n", mic->name); goto reboot; } if (stat(CD_DIR, &sbuf) < 0) { if (mkdir(CD_DIR, 0755) < 0) { mpsslog(PWARN, "%s: [SaveCrashDump] Avborted - create directory %s failed: %s\n", mic->name, CD_DIR, strerror(errno)); goto reboot; } diractual = dirlimit; } else { /* Check size of crash directory with configured limits */ if ((diractual = get_dir_size(mic, CD_DIR)) < 0) { mpsslog(PINFO, "%s: [SaveCrashDump] Avborted - get directory %s size failed: %s\n", mic->name, CD_DIR, strerror(errno)); goto reboot; } } if (diractual > dirlimit) { mpsslog(PINFO, "%s: [SaveCrashDump] Avborted - %s current size 0x%lx configured limit 0x%lx\n", mic->name, CD_DIR, diractual, dirlimit); goto reboot; } /* Open core dump file with time details embedded in file name */ time(&t); if ((tm = localtime(&t)) == 0) { mpsslog(PERROR, "%s: [SaveCrashdump] Aborted - get system date failed\n", mic->name); goto reboot; } /* Create crash directories if not done already */ snprintf(pathname, PATH_MAX - 1, "%s/%s", CD_DIR, mic->name); if (mkdir(pathname, 0755) && errno != EEXIST) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - create directory %s failed %s\n", mic->name, pathname, strerror(errno)); goto reboot; } if (statvfs(pathname, &vbuf) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - cannot read free disk size of %s: %s\n", mic->name, pathname, strerror(errno)); goto reboot; } if (CD_MIN_DISK > (vbuf.f_bsize * vbuf.f_bfree)) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - free disk space less than required 32Gb\n", mic->name); goto reboot; } /* Open vmcore entry for crashed card */ snprintf(pathname, PATH_MAX - 1, "/proc/mic_vmcore/%s", mic->name); if ((procfd = open(pathname, O_RDONLY)) < 0) { mpsslog(PERROR, "%s: [SaveCrashdump] Aborted - open %s failed: %s\n", mic->name, pathname, strerror(errno)); goto reboot; } snprintf(pathname, PATH_MAX - 1, "%s/%s/vmcore-%d-%d-%d-%d:%d:%d", CD_DIR, mic->name, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); if ((cdfd = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted - open %s failed %s\n", mic->name, pathname, strerror(errno)); goto cleanup1; } mpsslog(PINFO, "%s: [SaveCrashDump] Capturing uOS kernel crash dump\n", mic->name); /* Read from the proc entry and write to the core dump file */ do { if (lseek(cdfd, CD_READ_CHUNK, SEEK_CUR) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted lseek failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } bytes = write(cdfd, "", 1); if (bytes != 1) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted write failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } if ((addr = mmap(NULL, CD_READ_CHUNK, PROT_READ|PROT_WRITE, MAP_SHARED, cdfd, total_bytes)) == MAP_FAILED) { mpsslog(PERROR, "%s: [SaveCrasdDump] Aborted mmap failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } if ((bytes = read(procfd, addr, CD_READ_CHUNK)) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted read failed %s\n", mic->name, strerror(errno)); remove(pathname); munmap(addr, CD_READ_CHUNK); goto cleanup2; } total_bytes += bytes; munmap(addr, CD_READ_CHUNK); if (ftruncate(cdfd, total_bytes + 1) < 0) { mpsslog(PERROR, "%s: [SaveCrashDump] Aborted ftruncate failed %s\n", mic->name, strerror(errno)); remove(pathname); goto cleanup2; } } while (bytes == CD_READ_CHUNK); mpsslog(PNORM, "%s: [SaveCrashDump] Completed raw dump size 0x%lx\n", mic->name, total_bytes); mpsslog(PNORM, "%s: [SaveCrashDump] Gzip started\n", mic->name); pid1 = gzip(pathname); /* Initiate compression of the file and reset MIC in parallel */ cleanup2: close(cdfd); cleanup1: close(procfd); reboot: if ((err = mpss_setsysfs(mic->name, "state", "reset:force")) != 0) { mpsslog(PINFO, "%s: [SaveCrashDump] Failed to set state sysfs - cannot reset: %s\n", mic->name, strerror(err)); goto done; } if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PINFO, "%s: [SaveCrashDump] Failed to read state sysfs - state of reset unknown\n", mic->name); goto done; } while (strcmp(state, "ready") && strcmp(state, "reset failed")) { if (!strcmp(state, "online") || !strcmp(state, "booting")) { mpsslog(PINFO, "%s: [SaveCrashDump] External entity has already rebooted card\n", mic->name); free(state); goto done; } mpsslog(PINFO, "%s: [SaveCrashDump] Waiting for reset\n", mic->name); sleep(2); save = state; if ((state = mpss_readsysfs(mic->name, "state")) == NULL) { mpsslog(PWARN, "%s: [SaveCrashDump] wait for ready failed to read state sysfs - try again\n", mic->name); state = save; } else { free(save); } } if (strcmp(state, "ready")) { mpsslog(PERROR, "%s: [SaveCrashDump] Failed to reset card. Aborting reboot\n", mic->name); free(state); goto done; } if (pid1 && (pid1 < 0 || ((waitpid(pid1, NULL, 0)) < 0))) remove(pathname); if (autoreboot(mic)) { while (pthread_mutex_lock(&start_lock) != 0); start_count++; while (pthread_mutex_lock(&mpssdi->pth_lock) != 0); pthread_create(&mpssdi->boot_pth, NULL, boot_mic, mic); while (pthread_mutex_unlock(&mpssdi->pth_lock) != 0); while (pthread_mutex_unlock(&start_lock) != 0); } done: pthread_exit(NULL); }