1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/fstyp.h>
28 #include <sys/fsid.h>
29
30 #include <errno.h>
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/vnode.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #include <utime.h>
39 #include <atomic.h>
40
41 #include <sys/lx_syscall.h>
42 #include <sys/lx_types.h>
43 #include <sys/lx_debug.h>
44 #include <sys/lx_misc.h>
45 #include <sys/lx_fcntl.h>
46
47 static int
48 install_checkpath(uintptr_t p1)
49 {
50 int saved_errno = errno;
51 char path[MAXPATHLEN];
52
53 /*
54 * The "dev" RPM package wants to modify /dev/pts, but /dev/pts is a
55 * lofs mounted copy of /native/dev/pts, so that won't work.
56 *
57 * Instead, if we're trying to modify /dev/pts from install mode, just
58 * act as if it succeded.
59 */
60 if (uucopystr((void *)p1, path, MAXPATHLEN) == -1)
61 return (-errno);
62
63 if (strcmp(path, "/dev/pts") == 0)
64 return (0);
65
66 errno = saved_errno;
67 return (-errno);
68 }
69
70 /*
71 * Convert linux LX_AT_* flags to solaris AT_* flags, while verifying allowed
72 * flags have been passed. This also allows EACCESS/REMOVEDIR to be translated
73 * correctly since on linux they have the same value.
74 */
75 int
76 ltos_at_flag(int lflag, int allow)
77 {
78 int sflag = 0;
79
80 if ((lflag & LX_AT_EACCESS) && (allow & AT_EACCESS)) {
81 lflag &= ~LX_AT_EACCESS;
82 sflag |= AT_EACCESS;
83 }
84
85 if ((lflag & LX_AT_REMOVEDIR) && (allow & AT_REMOVEDIR)) {
86 lflag &= ~LX_AT_REMOVEDIR;
87 sflag |= AT_REMOVEDIR;
88 }
89
90 if ((lflag & LX_AT_SYMLINK_NOFOLLOW) && (allow & AT_SYMLINK_NOFOLLOW)) {
91 lflag &= ~LX_AT_SYMLINK_NOFOLLOW;
92 sflag |= AT_SYMLINK_NOFOLLOW;
93 }
94
95 /* right now solaris doesn't have a _FOLLOW flag, so use a fake one */
96 if ((lflag & LX_AT_SYMLINK_FOLLOW) && (allow & LX_AT_SYMLINK_FOLLOW)) {
97 lflag &= ~LX_AT_SYMLINK_FOLLOW;
98 sflag |= LX_AT_SYMLINK_FOLLOW;
99 }
100
101 /* if flag is not zero than some flags did not hit the above code */
102 if (lflag)
103 return (-EINVAL);
104
105 return (sflag);
106 }
107
108
109 /*
110 * Miscellaneous file-related system calls.
111 */
112
113 /*
114 * Linux creates half-duplex unnamed pipes and Solaris creates full-duplex
115 * pipes. Thus, to get the correct semantics, our simple pipe() system
116 * call actually needs to create a named pipe, do three opens, a close, and
117 * an unlink. This is woefully expensive. If performance becomes a real
118 * issue, we can implement a half-duplex pipe() in the brand module.
119 */
120 #define PIPENAMESZ 32 /* enough room for /tmp/.pipe.<pid>.<num> */
121
122 int
123 lx_pipe(uintptr_t p1)
124 {
125 static uint32_t pipecnt = 0;
126 int cnt;
127 char pipename[PIPENAMESZ];
128 int fds[3];
129 int r = 0;
130
131 fds[0] = -1;
132 fds[1] = -1;
133 fds[2] = -1;
134
135 /*
136 * Construct a name for the named pipe: /tmp/.pipe.<pid>.<++cnt>
137 */
138 cnt = atomic_inc_32_nv(&pipecnt);
139
140 (void) snprintf(pipename, PIPENAMESZ, "/tmp/.pipe.%d.%d",
141 getpid(), cnt);
142
143 if (mkfifo(pipename, 0600))
144 return (-errno);
145
146 /*
147 * To prevent either the read-only or write-only open from
148 * blocking, we first need to open the pipe for both reading and
149 * writing.
150 */
151 if (((fds[2] = open(pipename, O_RDWR)) < 0) ||
152 ((fds[0] = open(pipename, O_RDONLY)) < 0) ||
153 ((fds[1] = open(pipename, O_WRONLY)) < 0)) {
154 r = errno;
155 } else {
156 /*
157 * Copy the two one-way fds back to the app's address
158 * space.
159 */
160 if (uucopy(fds, (void *)p1, 2 * sizeof (int)))
161 r = errno;
162 }
163
164 if (fds[2] >= 0)
165 (void) close(fds[2]);
166 (void) unlink(pipename);
167
168 if (r != 0) {
169 if (fds[0] >= 0)
170 (void) close(fds[0]);
171 if (fds[1] >= 0)
172 (void) close(fds[1]);
173 }
174
175 return (-r);
176 }
177
178 /*
179 * On Linux, even root cannot create a link to a directory, so we have to
180 * add an explicit check.
181 */
182 int
183 lx_link(uintptr_t p1, uintptr_t p2)
184 {
185 char *from = (char *)p1;
186 char *to = (char *)p2;
187 struct stat64 statbuf;
188
189 if ((stat64(from, &statbuf) == 0) && S_ISDIR(statbuf.st_mode))
190 return (-EPERM);
191
192 return (link(from, to) ? -errno : 0);
193 }
194
195 /*
196 * On Linux, an unlink of a directory returns EISDIR, not EPERM.
197 */
198 int
199 lx_unlink(uintptr_t p)
200 {
201 char *pathname = (char *)p;
202 struct stat64 statbuf;
203
204 if ((lstat64(pathname, &statbuf) == 0) && S_ISDIR(statbuf.st_mode))
205 return (-EISDIR);
206
207 return (unlink(pathname) ? -errno : 0);
208 }
209
210 int
211 lx_unlinkat(uintptr_t ext1, uintptr_t p1, uintptr_t p2)
212 {
213 int atfd = (int)ext1;
214 char *pathname = (char *)p1;
215 int flag = (int)p2;
216 struct stat64 statbuf;
217
218 if (atfd == LX_AT_FDCWD)
219 atfd = AT_FDCWD;
220
221 flag = ltos_at_flag(flag, AT_REMOVEDIR);
222 if (flag < 0)
223 return (-EINVAL);
224
225 if (!(flag & AT_REMOVEDIR)) {
226 /* Behave like unlink() */
227 if ((fstatat64(atfd, pathname, &statbuf, AT_SYMLINK_NOFOLLOW) ==
228 0) && S_ISDIR(statbuf.st_mode))
229 return (-EISDIR);
230 }
231
232 return (unlinkat(atfd, pathname, flag) ? -errno : 0);
233 }
234
235 /*
236 * fsync() and fdatasync() - On Solaris, these calls translate into a common
237 * fsync() syscall with a different parameter, so we layer on top of the librt
238 * functions instead.
239 */
240 int
241 lx_fsync(uintptr_t fd)
242 {
243 int fildes = (int)fd;
244 struct stat64 statbuf;
245
246 if ((fstat64(fildes, &statbuf) == 0) &&
247 (S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode)))
248 return (-EINVAL);
249
250 return (fsync((int)fd) ? -errno : 0);
251 }
252
253 int
254 lx_fdatasync(uintptr_t fd)
255 {
256 int fildes = (int)fd;
257 struct stat64 statbuf;
258
259 if ((fstat64(fildes, &statbuf) == 0) &&
260 (S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode)))
261 return (-EINVAL);
262
263 return (fdatasync((int)fd) ? -errno : 0);
264 }
265
266 /*
267 * Linux, unlike Solaris, ALWAYS resets the setuid and setgid bits on a
268 * chown/fchown regardless of whether it was done by root or not. Therefore,
269 * we must do extra work after each chown/fchown call to emulate this behavior.
270 */
271 #define SETUGID (S_ISUID | S_ISGID)
272
273 /*
274 * [lf]chown16() - Translate the uid/gid and pass onto the real functions.
275 */
276 int
277 lx_chown16(uintptr_t p1, uintptr_t p2, uintptr_t p3)
278 {
279 char *filename = (char *)p1;
280 struct stat64 statbuf;
281
282 if (chown(filename, LX_UID16_TO_UID32((lx_gid16_t)p2),
283 LX_GID16_TO_GID32((lx_gid16_t)p3)))
284 return (-errno);
285
286 if (stat64(filename, &statbuf) == 0) {
287 statbuf.st_mode &= ~S_ISUID;
288 if (statbuf.st_mode & S_IXGRP)
289 statbuf.st_mode &= ~S_ISGID;
290 (void) chmod(filename, (statbuf.st_mode & MODEMASK));
291 }
292
293 return (0);
294 }
295
296 int
297 lx_fchown16(uintptr_t p1, uintptr_t p2, uintptr_t p3)
298 {
299 int fd = (int)p1;
300 struct stat64 statbuf;
301
302 if (fchown(fd, LX_UID16_TO_UID32((lx_gid16_t)p2),
303 LX_GID16_TO_GID32((lx_gid16_t)p3)))
304 return (-errno);
305
306 if (fstat64(fd, &statbuf) == 0) {
307 statbuf.st_mode &= ~S_ISUID;
308 if (statbuf.st_mode & S_IXGRP)
309 statbuf.st_mode &= ~S_ISGID;
310 (void) fchmod(fd, (statbuf.st_mode & MODEMASK));
311 }
312
313 return (0);
314 }
315
316 int
317 lx_lchown16(uintptr_t p1, uintptr_t p2, uintptr_t p3)
318 {
319 return (lchown((char *)p1, LX_UID16_TO_UID32((lx_gid16_t)p2),
320 LX_GID16_TO_GID32((lx_gid16_t)p3)) ? -errno : 0);
321 }
322
323 int
324 lx_chown(uintptr_t p1, uintptr_t p2, uintptr_t p3)
325 {
326 char *filename = (char *)p1;
327 struct stat64 statbuf;
328 int ret;
329
330 ret = chown(filename, (uid_t)p2, (gid_t)p3);
331
332 if (ret < 0) {
333 /*
334 * If chown() failed and we're in install mode, return success
335 * if the the reason we failed was because the source file
336 * didn't actually exist or if we're trying to modify /dev/pts.
337 */
338 if ((lx_install != 0) &&
339 ((errno == ENOENT) || (install_checkpath(p1) == 0)))
340 return (0);
341
342 return (-errno);
343 }
344
345 if (stat64(filename, &statbuf) == 0) {
346 statbuf.st_mode &= ~S_ISUID;
347 if (statbuf.st_mode & S_IXGRP)
348 statbuf.st_mode &= ~S_ISGID;
349 (void) chmod(filename, (statbuf.st_mode & MODEMASK));
350 }
351
352 return (0);
353 }
354
355 int
356 lx_fchown(uintptr_t p1, uintptr_t p2, uintptr_t p3)
357 {
358 int fd = (int)p1;
359 struct stat64 statbuf;
360
361 if (fchown(fd, (uid_t)p2, (gid_t)p3))
362 return (-errno);
363
364 if (fstat64(fd, &statbuf) == 0) {
365 statbuf.st_mode &= ~S_ISUID;
366 if (statbuf.st_mode & S_IXGRP)
367 statbuf.st_mode &= ~S_ISGID;
368 (void) fchmod(fd, (statbuf.st_mode & MODEMASK));
369 }
370
371 return (0);
372 }
373
374 int
375 lx_chmod(uintptr_t p1, uintptr_t p2)
376 {
377 int ret;
378
379 ret = chmod((const char *)p1, (mode_t)p2);
380
381 if (ret < 0) {
382 /*
383 * If chown() failed and we're in install mode, return success
384 * if the the reason we failed was because the source file
385 * didn't actually exist or if we're trying to modify /dev/pts.
386 */
387 if ((lx_install != 0) &&
388 ((errno == ENOENT) || (install_checkpath(p1) == 0)))
389 return (0);
390
391 return (-errno);
392 }
393
394 return (0);
395 }
396
397 int
398 lx_utime(uintptr_t p1, uintptr_t p2)
399 {
400 int ret;
401
402 ret = utime((const char *)p1, (const struct utimbuf *)p2);
403
404 if (ret < 0) {
405 /*
406 * If chown() failed and we're in install mode, return success
407 * if the the reason we failed was because the source file
408 * didn't actually exist or if we're trying to modify /dev/pts.
409 */
410 if ((lx_install != 0) &&
411 ((errno == ENOENT) || (install_checkpath(p1) == 0)))
412 return (0);
413
414 return (-errno);
415 }
416
417 return (0);
418 }
419
420 /*
421 * llseek() - The Linux implementation takes an additional parameter, which is
422 * the resulting position in the file.
423 */
424 int
425 lx_llseek(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
426 uintptr_t p5)
427 {
428 offset_t ret;
429 offset_t *res = (offset_t *)p4;
430
431 /* SEEK_DATA and SEEK_HOLE are only valid in Solaris */
432 if ((int)p5 > SEEK_END)
433 return (-EINVAL);
434
435 if ((ret = llseek((int)p1, LX_32TO64(p3, p2), p5)) < 0)
436 return (-errno);
437
438 *res = ret;
439 return (0);
440 }
441
442 /*
443 * seek() - When the resultant file offset cannot be represented in 32 bits,
444 * Linux performs the seek but Solaris doesn't, though both set EOVERFLOW. We
445 * call llseek() and then check to see if we need to return EOVERFLOW.
446 */
447 int
448 lx_lseek(uintptr_t p1, uintptr_t p2, uintptr_t p3)
449 {
450 offset_t offset = (offset_t)(off_t)(p2); /* sign extend */
451 offset_t ret;
452 off_t ret32;
453
454 /* SEEK_DATA and SEEK_HOLE are only valid in Solaris */
455 if ((int)p3 > SEEK_END)
456 return (-EINVAL);
457
458 if ((ret = llseek((int)p1, offset, p3)) < 0)
459 return (-errno);
460
461 ret32 = (off_t)ret;
462 if ((offset_t)ret32 == ret)
463 return (ret32);
464 else
465 return (-EOVERFLOW);
466 }
467
468 /*
469 * Neither Solaris nor Linux actually returns anything to the caller, but glibc
470 * expects to see SOME value returned, so placate it and return 0.
471 */
472 int
473 lx_sync(void)
474 {
475 sync();
476 return (0);
477 }
478
479 int
480 lx_rmdir(uintptr_t p1)
481 {
482 int r;
483
484 r = rmdir((char *)p1);
485 if (r < 0)
486 return ((errno == EEXIST) ? -ENOTEMPTY : -errno);
487 return (0);
488 }
489
490 /*
491 * Exactly the same as Solaris' sysfs(2), except Linux numbers their fs indices
492 * starting at 0, and Solaris starts at 1.
493 */
494 int
495 lx_sysfs(uintptr_t p1, uintptr_t p2, uintptr_t p3)
496 {
497 int option = (int)p1;
498 int res;
499
500 /*
501 * Linux actually doesn't have #defines for these; their sysfs(2)
502 * man page literally defines the "option" field as being 1, 2 or 3,
503 * corresponding to Solaris' GETFSIND, GETFSTYP and GETNFSTYP,
504 * respectively.
505 */
506 switch (option) {
507 case 1:
508 if ((res = sysfs(GETFSIND, (const char *)p2)) < 0)
509 return (-errno);
510
511 return (res - 1);
512
513 case 2:
514 if ((res = sysfs(GETFSTYP, (int)p2 + 1,
515 (char *)p3)) < 0)
516 return (-errno);
517
518 return (0);
519
520 case 3:
521 if ((res = sysfs(GETNFSTYP)) < 0)
522 return (-errno);
523
524 return (res);
525
526 default:
527 break;
528 }
529
530 return (-EINVAL);
531 }
532
533 int
534 lx_faccessat(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
535 {
536 int atfd = (int)p1;
537 char *path = (char *)p2;
538 int mode = (mode_t)p3;
539 int flag = (int)p4;
540
541 if (atfd == LX_AT_FDCWD)
542 atfd = AT_FDCWD;
543
544 flag = ltos_at_flag(flag, AT_EACCESS);
545 if (flag < 0)
546 return (-EINVAL);
547
548 return (faccessat(atfd, path, mode, flag) ? -errno : 0);
549 }
550
551 int
552 lx_futimesat(uintptr_t p1, uintptr_t p2, uintptr_t p3)
553 {
554 int atfd = (int)p1;
555 char *path = (char *)p2;
556 struct timeval *times = (struct timeval *)p3;
557
558 if (atfd == LX_AT_FDCWD)
559 atfd = AT_FDCWD;
560
561 return (futimesat(atfd, path, times) ? -errno : 0);
562 }
563
564
565 /*
566 * Constructs an absolute path string in buf from the path of fd and the
567 * relative path string pointed to by "p1". This is required for emulating
568 * *at() system calls.
569 * Example:
570 * If the path of fd is "/foo/bar" and path is "etc" the string returned is
571 * "/foo/bar/etc", if the fd is a file fd then it fails with ENOTDIR.
572 * If path is absolute then no modifcations are made to it when copied.
573 */
574 static int
575 getpathat(int fd, uintptr_t p1, char *outbuf, size_t outbuf_size)
576 {
577 char pathbuf[MAXPATHLEN];
578 char fdpathbuf[MAXPATHLEN];
579 char *fdpath;
580 struct stat64 statbuf;
581
582 if (uucopystr((void *)p1, pathbuf, MAXPATHLEN) == -1)
583 return (-errno);
584
585 /* If the path is absolute then we can early out */
586 if ((pathbuf[0] == '/') || (fd == LX_AT_FDCWD)) {
587 (void) strlcpy(outbuf, pathbuf, outbuf_size);
588 return (0);
589 }
590
591 fdpath = lx_fd_to_path(fd, fdpathbuf, sizeof (fdpathbuf));
592 if (fdpath == NULL)
593 return (-EBADF);
594
595 if ((fstat64(fd, &statbuf) < 0))
596 return (-EBADF);
597
598 if (!S_ISDIR(statbuf.st_mode))
599 return (-ENOTDIR);
600
601 if (snprintf(outbuf, outbuf_size, "%s/%s", fdpath, pathbuf) >
602 (outbuf_size-1))
603 return (-ENAMETOOLONG);
604
605 return (0);
606 }
607
608 int
609 lx_mkdirat(uintptr_t p1, uintptr_t p2, uintptr_t p3)
610 {
611 int atfd = (int)p1;
612 mode_t mode = (mode_t)p3;
613 char pathbuf[MAXPATHLEN];
614 int ret;
615
616 ret = getpathat(atfd, p2, pathbuf, sizeof (pathbuf));
617 if (ret < 0)
618 return (ret);
619
620 return (mkdir(pathbuf, mode) ? -errno : 0);
621 }
622
623 int
624 lx_mknodat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3)
625 {
626 int atfd = (int)ext1;
627 char pathbuf[MAXPATHLEN];
628 int ret;
629
630 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf));
631 if (ret < 0)
632 return (ret);
633
634 return (lx_mknod((uintptr_t)pathbuf, p2, p3));
635 }
636
637 int
638 lx_symlinkat(uintptr_t p1, uintptr_t ext1, uintptr_t p2)
639 {
640 int atfd = (int)ext1;
641 char pathbuf[MAXPATHLEN];
642 int ret;
643
644 ret = getpathat(atfd, p2, pathbuf, sizeof (pathbuf));
645 if (ret < 0)
646 return (ret);
647
648 return (symlink((char *)p1, pathbuf) ? -errno : 0);
649 }
650
651 int
652 lx_linkat(uintptr_t ext1, uintptr_t p1, uintptr_t ext2, uintptr_t p2,
653 uintptr_t p3)
654 {
655 int atfd1 = (int)ext1;
656 int atfd2 = (int)ext2;
657 char pathbuf1[MAXPATHLEN];
658 char pathbuf2[MAXPATHLEN];
659 int ret;
660
661 /*
662 * The flag specifies whether the hardlink will point to a symlink or
663 * not, on solaris the default behaviour of link() is to dereference a
664 * symlink and there is no obvious way to trigger the other behaviour.
665 * So for now we just ignore this flag and act like link().
666 */
667 /* LINTED [set but not used in function] */
668 int flag = p3;
669
670 if (flag != p3)
671 return (flag); // workaround.
672
673 ret = getpathat(atfd1, p1, pathbuf1, sizeof (pathbuf1));
674 if (ret < 0)
675 return (ret);
676
677 ret = getpathat(atfd2, p2, pathbuf2, sizeof (pathbuf2));
678 if (ret < 0)
679 return (ret);
680
681 return (lx_link((uintptr_t)pathbuf1, (uintptr_t)pathbuf2));
682 }
683
684 int
685 lx_readlinkat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3)
686 {
687 int atfd = (int)ext1;
688 char pathbuf[MAXPATHLEN];
689 int ret;
690
691 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf));
692 if (ret < 0)
693 return (ret);
694
695 ret = readlink(pathbuf, (char *)p2, (size_t)p3);
696 if (ret < 0)
697 return (-errno);
698
699 return (ret);
700 }
701
702 int
703 lx_fchownat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3,
704 uintptr_t p4)
705 {
706 int flag;
707 int atfd = (int)ext1;
708 char pathbuf[MAXPATHLEN];
709 int ret;
710
711 flag = ltos_at_flag(p4, AT_SYMLINK_NOFOLLOW);
712 if (flag < 0)
713 return (-EINVAL);
714
715 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf));
716 if (ret < 0)
717 return (ret);
718
719 if (flag & AT_SYMLINK_NOFOLLOW)
720 return (lchown(pathbuf, (uid_t)p2, (gid_t)p3) ? -errno : 0);
721 else
722 return (lx_chown((uintptr_t)pathbuf, p2, p3));
723 }
724
725 int
726 lx_fchmodat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3)
727 {
728 int atfd = (int)ext1;
729 char pathbuf[MAXPATHLEN];
730 int ret;
731
732 /*
733 * It seems that at least some versions of glibc do not set or clear
734 * the flags arg, so checking them will result in random behaviour.
735 */
736 /* LINTED [set but not used in function] */
737 int flag = p3;
738
739 if (flag != p3)
740 return (flag); // workaround.
741
742 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf));
743 if (ret < 0)
744 return (ret);
745
746 return (lx_chmod((uintptr_t)pathbuf, p2));
747 }