1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/compiler.h> 3 #include <linux/kernel.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <errno.h> 7 #include <unistd.h> 8 #include <string.h> 9 10 #include "data.h" 11 #include "util.h" 12 #include "debug.h" 13 14 #ifndef O_CLOEXEC 15 #ifdef __sparc__ 16 #define O_CLOEXEC 0x400000 17 #elif defined(__alpha__) || defined(__hppa__) 18 #define O_CLOEXEC 010000000 19 #else 20 #define O_CLOEXEC 02000000 21 #endif 22 #endif 23 24 static bool check_pipe(struct perf_data_file *file) 25 { 26 struct stat st; 27 bool is_pipe = false; 28 int fd = perf_data_file__is_read(file) ? 29 STDIN_FILENO : STDOUT_FILENO; 30 31 if (!file->path) { 32 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) 33 is_pipe = true; 34 } else { 35 if (!strcmp(file->path, "-")) 36 is_pipe = true; 37 } 38 39 if (is_pipe) 40 file->fd = fd; 41 42 return file->is_pipe = is_pipe; 43 } 44 45 static int check_backup(struct perf_data_file *file) 46 { 47 struct stat st; 48 49 if (!stat(file->path, &st) && st.st_size) { 50 /* TODO check errors properly */ 51 char oldname[PATH_MAX]; 52 snprintf(oldname, sizeof(oldname), "%s.old", 53 file->path); 54 unlink(oldname); 55 rename(file->path, oldname); 56 } 57 58 return 0; 59 } 60 61 static int open_file_read(struct perf_data_file *file) 62 { 63 struct stat st; 64 int fd; 65 char sbuf[STRERR_BUFSIZE]; 66 67 fd = open(file->path, O_RDONLY); 68 if (fd < 0) { 69 int err = errno; 70 71 pr_err("failed to open %s: %s", file->path, 72 str_error_r(err, sbuf, sizeof(sbuf))); 73 if (err == ENOENT && !strcmp(file->path, "perf.data")) 74 pr_err(" (try 'perf record' first)"); 75 pr_err("\n"); 76 return -err; 77 } 78 79 if (fstat(fd, &st) < 0) 80 goto out_close; 81 82 if (!file->force && st.st_uid && (st.st_uid != geteuid())) { 83 pr_err("File %s not owned by current user or root (use -f to override)\n", 84 file->path); 85 goto out_close; 86 } 87 88 if (!st.st_size) { 89 pr_info("zero-sized file (%s), nothing to do!\n", 90 file->path); 91 goto out_close; 92 } 93 94 file->size = st.st_size; 95 return fd; 96 97 out_close: 98 close(fd); 99 return -1; 100 } 101 102 static int open_file_write(struct perf_data_file *file) 103 { 104 int fd; 105 char sbuf[STRERR_BUFSIZE]; 106 107 if (check_backup(file)) 108 return -1; 109 110 fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 111 S_IRUSR|S_IWUSR); 112 113 if (fd < 0) 114 pr_err("failed to open %s : %s\n", file->path, 115 str_error_r(errno, sbuf, sizeof(sbuf))); 116 117 return fd; 118 } 119 120 static int open_file(struct perf_data_file *file) 121 { 122 int fd; 123 124 fd = perf_data_file__is_read(file) ? 125 open_file_read(file) : open_file_write(file); 126 127 file->fd = fd; 128 return fd < 0 ? -1 : 0; 129 } 130 131 int perf_data_file__open(struct perf_data_file *file) 132 { 133 if (check_pipe(file)) 134 return 0; 135 136 if (!file->path) 137 file->path = "perf.data"; 138 139 return open_file(file); 140 } 141 142 void perf_data_file__close(struct perf_data_file *file) 143 { 144 close(file->fd); 145 } 146 147 ssize_t perf_data_file__write(struct perf_data_file *file, 148 void *buf, size_t size) 149 { 150 return writen(file->fd, buf, size); 151 } 152 153 int perf_data_file__switch(struct perf_data_file *file, 154 const char *postfix, 155 size_t pos, bool at_exit) 156 { 157 char *new_filepath; 158 int ret; 159 160 if (check_pipe(file)) 161 return -EINVAL; 162 if (perf_data_file__is_read(file)) 163 return -EINVAL; 164 165 if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0) 166 return -ENOMEM; 167 168 /* 169 * Only fire a warning, don't return error, continue fill 170 * original file. 171 */ 172 if (rename(file->path, new_filepath)) 173 pr_warning("Failed to rename %s to %s\n", file->path, new_filepath); 174 175 if (!at_exit) { 176 close(file->fd); 177 ret = perf_data_file__open(file); 178 if (ret < 0) 179 goto out; 180 181 if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) { 182 ret = -errno; 183 pr_debug("Failed to lseek to %zu: %s", 184 pos, strerror(errno)); 185 goto out; 186 } 187 } 188 ret = file->fd; 189 out: 190 free(new_filepath); 191 return ret; 192 } 193