libsfakeroot.c (7043B)
1 /* sfakeroot 2 * 3 * Copyright © 2020 Richard Ipsum 4 * 5 * This file is part of sfakeroot. 6 * 7 * sfakeroot is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, version 3 of the License. 10 * 11 * sfakeroot is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with sfakeroot. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <stdbool.h> 23 #include <fcntl.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include <errno.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <sys/wait.h> 31 #include <sys/un.h> 32 33 #include "sfakeroot.h" 34 35 int sfakeroot_readwriten(int fd, char bytes[], size_t len, bool is_write) 36 { 37 ssize_t n; 38 size_t remaining = len; 39 40 while (remaining > 0) { 41 n = is_write ? write(fd, bytes, remaining) : read(fd, bytes, remaining); 42 switch (n) { 43 case 0: 44 if (is_write) { 45 /* not necessarily an error if we're writing... */ 46 continue; 47 } 48 fprintf(stderr, "sfakeroot: %s: data truncated, remaining: %zu\n", 49 is_write ? "write" : "read", remaining); 50 return -1; 51 case -1: 52 if (errno == EINTR) { 53 continue; 54 } 55 fprintf(stderr, "sfakeroot: %s: %s\n", 56 is_write ? "write" : "read", strerror(errno)); 57 return -1; 58 default: 59 remaining -= n; 60 bytes += n; 61 } 62 } 63 64 return len - remaining; 65 } 66 67 int sfakeroot_recvmsg(int fd, struct sfakeroot_msg *m) 68 { 69 if (sfakeroot_readwriten(fd, (char *) m, sizeof (*m), false) != sizeof (*m)) { 70 fprintf(stderr, "sfakeroot_recvmsg: error reading message\n"); 71 return -1; 72 } 73 74 return 0; 75 } 76 77 int sfakeroot_sendmsg(int fd, struct sfakeroot_msg *m) 78 { 79 if (sfakeroot_readwriten(fd, (char *) m, sizeof (*m), true) != sizeof (*m)) { 80 fprintf(stderr, "sfakeroot_sendmsg: error writing message\n"); 81 return -1; 82 } 83 84 return 0; 85 } 86 87 static int sfakeroot__session_open_internal(bool session_expected) 88 { 89 struct sockaddr_un sa = {.sun_family = AF_UNIX}; 90 int sockfd; 91 socklen_t socklen; 92 char *sockpath = getenv("SFAKEROOT_SOCKET_PATH"); 93 94 if (sockpath == NULL) { 95 fprintf(stderr, "environment variable SFAKEROOT_SOCKET_PATH not set!\n"); 96 return -1; 97 } 98 99 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 100 if (sockfd == -1) { 101 fprintf(stderr, "socket: %s\n", strerror(errno)); 102 return -1; 103 } 104 105 strlcpy(sa.sun_path, sockpath, sizeof (sa.sun_path)); 106 socklen = strlen(sa.sun_path) + 1 + sizeof (sa.sun_family); 107 108 if (connect(sockfd, (struct sockaddr *) &sa, socklen) == -1) { 109 if (session_expected) { 110 fprintf(stderr, "connect: %s\n", strerror(errno)); 111 } 112 return -1; 113 } 114 115 return sockfd; 116 } 117 118 int sfakeroot_session_open(void) 119 { 120 return sfakeroot__session_open_internal(true); 121 } 122 123 bool sfakeroot_daemon_running(void) 124 { 125 int sockfd = sfakeroot__session_open_internal(false); 126 close(sockfd); 127 return sockfd != -1; 128 } 129 130 static int sfakeroot__call(struct sfakeroot_msg *m) 131 { 132 int sockfd; 133 char *wd; 134 135 sockfd = sfakeroot_session_open(); 136 if (sockfd == -1) { 137 return -1; 138 } 139 140 if ((wd = getcwd(NULL, 0)) == NULL) { 141 return -1; 142 } 143 144 strlcpy(m->working_dir, wd, sizeof (m->working_dir)); 145 free(wd); 146 147 if (sfakeroot_sendmsg(sockfd, m) == -1) { 148 return -1; 149 } 150 if (sfakeroot_recvmsg(sockfd, m) == -1) { 151 return -1; 152 } 153 154 close(sockfd); 155 errno = m->reterrno; 156 return m->retcode; 157 } 158 159 int chmod(const char *path, mode_t mode) 160 { 161 struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_CHMOD, .mode = mode}; 162 debug("chmod %s %o\n", path, mode); 163 strlcpy(m.path, path, sizeof (m.path)); 164 return sfakeroot__call(&m); 165 } 166 167 int chown(const char *path, uid_t uid, gid_t gid) 168 { 169 struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_CHOWN, .uid = uid, .gid = gid}; 170 strlcpy(m.path, path, sizeof (m.path)); 171 debug("chown: path: %s, uid: %d, gid: %d\n", path, (int) uid, (int) gid); 172 return sfakeroot__call(&m); 173 } 174 175 int lchown(const char *path, uid_t uid, gid_t gid) 176 { 177 struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_LCHOWN, .uid = uid, .gid = gid}; 178 strlcpy(m.path, path, sizeof (m.path)); 179 debug("lchown: path: %s, uid: %d, gid: %d\n", path, (int) uid, (int) gid); 180 return sfakeroot__call(&m); 181 } 182 183 int fchown(int fd, uid_t uid, gid_t gid) 184 { 185 struct sfakeroot_msg m = { 186 .type = SFAKEROOT_MSG_FCHOWN, 187 .fd = fd, 188 .uid = uid, 189 .gid = gid 190 }; 191 return sfakeroot__call(&m); 192 } 193 194 int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag) 195 { 196 struct sfakeroot_msg m = { 197 .type = SFAKEROOT_MSG_FCHOWNAT, 198 .fd = fd, 199 .flag = flag, 200 .uid = uid, 201 .gid = gid 202 }; 203 debug("fchownat %d %s %u %u %u\n", fd, path, uid, gid, flag); 204 strlcpy(m.path, path, sizeof (m.path)); 205 return sfakeroot__call(&m); 206 } 207 208 static int sfakeroot__stat(struct sfakeroot_msg *m, struct stat *s) 209 { 210 int ret; 211 if ((ret = sfakeroot__call(m)) == -1) { 212 return -1; 213 } 214 *s = m->st; 215 return ret; 216 } 217 218 int stat(const char *path, struct stat *s) 219 { 220 struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_STAT}; 221 debug("stat\n"); 222 strlcpy(m.path, path, sizeof (m.path)); 223 return sfakeroot__stat(&m, s); 224 } 225 226 int __xstat(int ver, const char *path, struct stat *s) 227 { 228 (void) ver; 229 return stat(path, s); 230 } 231 232 int lstat(const char *path, struct stat *s) 233 { 234 struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_LSTAT}; 235 debug("lstat\n"); 236 strlcpy(m.path, path, sizeof (m.path)); 237 return sfakeroot__stat(&m, s); 238 } 239 240 int __lxstat(int ver, const char *path, struct stat *s) 241 { 242 (void) ver; 243 return lstat(path, s); 244 } 245 246 int fstat(int fd, struct stat *s) 247 { 248 struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_FSTAT, .fd = fd}; 249 return sfakeroot__stat(&m, s); 250 } 251 252 int __fxstat(int ver, int fd, struct stat *sb) 253 { 254 (void) ver; 255 return fstat(fd, sb); 256 } 257 258 int fstatat(int fd, const char *path, struct stat *s, int flag) 259 { 260 struct sfakeroot_msg m = { 261 .type = SFAKEROOT_MSG_FSTATAT, 262 .fd = fd, 263 .flag = flag, 264 }; 265 strlcpy(m.path, path, sizeof (m.path)); 266 return sfakeroot__stat(&m, s); 267 } 268 269 #undef __xstat 270 #undef __fxstat 271 #undef __lxstat 272 #undef __xstat64 273 #undef __fxstat64 274 #undef __lxstat64 275 #undef _FILE_OFFSET_BITS 276 277 // TODO: 278 // int 279 // utimes(const char *path, const struct timeval *times); 280 // 281 // int 282 // futimes(int fd, const struct timeval *times);