| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <dirent.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <pagemap/pagemap.h> |
| |
| int pm_kernel_create(pm_kernel_t **ker_out) { |
| pm_kernel_t *ker; |
| int error; |
| |
| if (!ker_out) |
| return 1; |
| |
| ker = calloc(1, sizeof(*ker)); |
| if (!ker) |
| return errno; |
| |
| ker->kpagecount_fd = open("/proc/kpagecount", O_RDONLY); |
| if (ker->kpagecount_fd < 0) { |
| error = errno; |
| free(ker); |
| return error; |
| } |
| |
| ker->kpageflags_fd = open("/proc/kpageflags", O_RDONLY); |
| if (ker->kpageflags_fd < 0) { |
| error = errno; |
| close(ker->kpagecount_fd); |
| free(ker); |
| return error; |
| } |
| |
| ker->pagesize = getpagesize(); |
| |
| *ker_out = ker; |
| |
| return 0; |
| } |
| |
| #define INIT_PIDS 20 |
| int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len) { |
| DIR *proc; |
| struct dirent *dir; |
| pid_t pid, *pids, *new_pids; |
| size_t pids_count, pids_size; |
| int error; |
| |
| proc = opendir("/proc"); |
| if (!proc) |
| return errno; |
| |
| pids = malloc(INIT_PIDS * sizeof(pid_t)); |
| if (!pids) { |
| closedir(proc); |
| return errno; |
| } |
| pids_count = 0; pids_size = INIT_PIDS; |
| |
| while ((dir = readdir(proc))) { |
| if (sscanf(dir->d_name, "%d", &pid) < 1) |
| continue; |
| |
| if (pids_count >= pids_size) { |
| new_pids = realloc(pids, 2 * pids_size * sizeof(pid_t)); |
| if (!new_pids) { |
| error = errno; |
| free(pids); |
| closedir(proc); |
| return error; |
| } |
| pids = new_pids; |
| pids_size = 2 * pids_size; |
| } |
| |
| pids[pids_count] = pid; |
| |
| pids_count++; |
| } |
| |
| closedir(proc); |
| |
| new_pids = realloc(pids, pids_count * sizeof(pid_t)); |
| if (!new_pids) { |
| error = errno; |
| free(pids); |
| return error; |
| } |
| |
| *pids_out = new_pids; |
| *len = pids_count; |
| |
| return 0; |
| } |
| |
| int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out) { |
| off_t off; |
| |
| if (!ker || !count_out) |
| return -1; |
| |
| off = lseek(ker->kpagecount_fd, pfn * sizeof(uint64_t), SEEK_SET); |
| if (off == (off_t)-1) |
| return errno; |
| if (read(ker->kpagecount_fd, count_out, sizeof(uint64_t)) < |
| (ssize_t)sizeof(uint64_t)) |
| return errno; |
| |
| return 0; |
| } |
| |
| int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out) { |
| off_t off; |
| |
| if (!ker || !flags_out) |
| return -1; |
| |
| off = lseek(ker->kpageflags_fd, pfn * sizeof(uint64_t), SEEK_SET); |
| if (off == (off_t)-1) |
| return errno; |
| if (read(ker->kpageflags_fd, flags_out, sizeof(uint64_t)) < |
| (ssize_t)sizeof(uint64_t)) |
| return errno; |
| |
| return 0; |
| } |
| |
| int pm_kernel_destroy(pm_kernel_t *ker) { |
| if (!ker) |
| return -1; |
| |
| close(ker->kpagecount_fd); |
| close(ker->kpageflags_fd); |
| |
| free(ker); |
| |
| return 0; |
| } |