1 /* syscalls.cc: syscalls
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #define fstat __FOOfstat__
13 #define lstat __FOOlstat__
14 #define stat __FOOstat__
15 #define _close __FOO_close__
16 #define _lseek __FOO_lseek__
17 #define _open __FOO_open__
18 #define _read __FOO_read__
19 #define _write __FOO_write__
20 #define _open64 __FOO_open64__
21 #define _lseek64 __FOO_lseek64__
22 #define _fstat64 __FOO_fstat64__
23 #define pread __FOO_pread
24 #define pwrite __FOO_pwrite
28 #include <sys/vfs.h> /* needed for statfs */
29 #include <sys/statvfs.h> /* needed for statvfs */
47 #include <lmcons.h> /* for UNLEN */
59 #include <cygwin/version.h>
60 #include <sys/cygwin.h>
62 #include "perprocess.h"
69 #include "shared_info.h"
85 suffix_info stat_suffixes[] =
88 suffix_info (".exe", 1),
92 bool transparent_exe = false;
94 SYSTEM_INFO system_info;
96 static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
99 static int __stdcall stat_worker (const char *name, struct __stat64 *buf,
100 int nofollow) __attribute__ ((regparm (3)));
102 /* Close all files and process any queued deletions.
103 Lots of unix style applications will open a tmp file, unlink it,
104 but never call close. This function is called by _exit to
105 ensure we don't leave any such files lying around. */
108 close_all_files (bool norelease)
110 cygheap->fdtab.lock ();
113 for (int i = 0; i < (int) cygheap->fdtab.size; i++)
114 if ((fh = cygheap->fdtab[i]) != NULL)
117 debug_printf ("closing fd %d", i);
121 cygheap->fdtab.release (i);
124 if (!hExeced && cygheap->ctty)
125 cygheap->close_ctty ();
127 cygheap->fdtab.unlock ();
128 user_shared->delqueue.process_queue ();
134 return cygheap->fdtab.dup2 (fd, cygheap_fdnew ());
138 dup2 (int oldfd, int newfd)
140 return cygheap->fdtab.dup2 (oldfd, newfd);
144 try_to_bin (path_conv &win32_path, HANDLE h)
148 char recycler[CYG_MAX_PATH + 20];
150 char *c = recycler + win32_path.rootdir (recycler);
151 if (wincap.has_recycle_dot_bin ())
153 strcpy (c, "$Recycle.Bin"); /* NTFS and FAT since Vista */
156 else if (win32_path.fs_is_ntfs ())
158 strcpy (c, "RECYCLER"); /* NTFS up to 2K3 */
161 else if (win32_path.fs_is_fat ())
163 strcpy (c, "Recycled"); /* FAT up to 2K3 */
169 /* Yes, we can really do that. Typically the recycle bin is created
170 by the first user actually using the bin. The permissions are the
171 default permissions propagated from the root directory. */
172 if (GetFileAttributes (recycler) == INVALID_FILE_ATTRIBUTES)
174 if (!CreateDirectory (recycler, NULL))
176 debug_printf ("Can't create folder %s, %E", recycler);
179 SetFileAttributes (recycler,
180 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
183 /* Up to Windows 2003 Server, the default settings for the top level recycle
184 bin are so that everybody has the right to create files in it. Starting
185 with Vista, users are by default not allowed to create files in that
186 directory, only subdirectories. Too bad, but that requires to move
187 files to the user's own recycler subdir. Instead of adding yet another
188 special case, we just move the stuff to the user's recycler, especially
189 since only shared files are moved at all. */
190 if (win32_path.fs_is_ntfs ())
193 cygheap->user.get_windows_id (c);
196 if (GetFileAttributes (recycler) == INVALID_FILE_ATTRIBUTES)
198 if (!CreateDirectory (recycler,
199 sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
200 cygheap->user.sid ())))
202 debug_printf ("Can't create folder %s, %E", recycler);
205 SetFileAttributes (recycler,
206 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
210 /* Create hopefully unique filename. */
211 __small_sprintf (c, "\\cyg%016X", hash_path_name (myself->uid,
212 win32_path.get_win32 ()));
215 /* Length of the WCHAR path in bytes. */
216 ULONG len = 2 * (c - recycler);
217 /* Choose size big enough to fit a local native NT path into it. */
218 ULONG size = sizeof (FILE_RENAME_INFORMATION) + len + 10;
219 PFILE_RENAME_INFORMATION pfri = (PFILE_RENAME_INFORMATION) alloca (size);
221 pfri->ReplaceIfExists = TRUE;
222 pfri->RootDirectory = NULL;
223 UNICODE_STRING uname = { 0, len + 10, pfri->FileName };
224 get_nt_native_path (recycler, uname);
225 pfri->FileNameLength = uname.Length;
226 status = NtSetInformationFile (h, &io, pfri, size, FileRenameInformation);
227 if (!NT_SUCCESS (status))
228 debug_printf ("Move %s to %s failed, status = %p", win32_path.get_win32 (),
233 unlink_9x (path_conv &win32_name)
235 BOOL ret = DeleteFile (win32_name);
236 syscall_printf ("DeleteFile %s", ret ? "succeeded" : "failed");
237 return GetLastError ();
241 unlink_nt (path_conv &win32_name, bool setattrs)
243 WCHAR wpath[CYG_MAX_PATH + 10];
244 UNICODE_STRING upath = {0, sizeof (wpath), wpath};
245 OBJECT_ATTRIBUTES attr;
250 ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
251 /* Don't open directories with "delete on close", because the NT internal
252 semantic is apparently different from the file semantic. If a directory
253 is opened "delete on close", the rename operation in try_to_bin fails
254 with STATUS_ACCESS_DENIED. So directories must be deleted using
255 NtSetInformationFile, class FileDispositionInformation, which works fine.
257 Correction, moving a directory opened with delete-on-close fails ONLY
258 on XP. Note to myself: Never take anything for granted on Windows!
260 Don't try "delete on close" if the file is on a remote share. If two
261 processes have open handles on a file and one of them calls unlink, then
262 it happens that the file is removed from the remote share even though the
263 other process still has an open handle. This other process than gets
264 Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the file. That
265 does not happen when using NtSetInformationFile, class
266 FileDispositionInformation, which nicely succeeds but still, the file is
267 available for the other process. Microsoft KB 837665 describes this
268 problem as a bug in 2K3, but I have reproduced it on shares on Samba
269 2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and 2K3 and in all cases, DeleteFile
270 works, "delete on close" does not. */
271 if (!win32_name.isdir () && !win32_name.isremote ())
272 flags |= FILE_DELETE_ON_CLOSE;
273 /* Add the reparse point flag to native symlinks, otherwise we remove the
274 target, not the symlink. */
275 if (win32_name.is_rep_symlink ())
276 flags |= FILE_OPEN_REPARSE_POINT;
278 win32_name.get_nt_native_path (upath);
279 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
280 NULL, sec_none_nih.lpSecurityDescriptor);
281 /* First try to open the file with sharing not allowed. If the file
282 has an open handle on it, this will fail. That indicates that the
283 file has to be moved to the recycle bin so that it actually disappears
284 from its directory even though its in use. Otherwise, if opening
285 doesn't fail, the file is not in use and by simply closing the handle
286 the file will disappear. */
287 bool move_to_bin = false;
288 status = NtOpenFile (&h, DELETE, &attr, &io, 0, flags);
289 if (status == STATUS_SHARING_VIOLATION)
292 status = NtOpenFile (&h, DELETE, &attr, &io, wincap.shared (), flags);
294 if (!NT_SUCCESS (status))
296 if (status == STATUS_DELETE_PENDING)
298 syscall_printf ("Delete already pending, status = %p", status);
301 syscall_printf ("Opening file for delete failed, status = %p", status);
302 return RtlNtStatusToDosError (status);
306 SetFileAttributes (win32_name, (DWORD) win32_name);
308 if (move_to_bin && !win32_name.isremote ())
309 try_to_bin (win32_name, h);
313 if (win32_name.isdir () || win32_name.isremote ())
315 FILE_DISPOSITION_INFORMATION disp = { TRUE };
316 status = NtSetInformationFile (h, &io, &disp, sizeof disp,
317 FileDispositionInformation);
318 if (!NT_SUCCESS (status))
320 syscall_printf ("Setting delete disposition failed, status = %p",
322 lasterr = RtlNtStatusToDosError (status);
326 status = NtClose (h);
327 if (!NT_SUCCESS (status))
329 /* Maybe that's really paranoid, but not being able to close the file
330 also means that deleting fails. */
331 syscall_printf ("%p = NtClose (%p)", status, h);
333 lasterr = RtlNtStatusToDosError (status);
336 syscall_printf ("Deleting succeeded");
341 unlink (const char *ourname)
346 path_conv win32_name (ourname, PC_SYM_NOFOLLOW,
347 transparent_exe ? stat_suffixes : NULL);
349 if (win32_name.error)
351 set_errno (win32_name.error);
355 devn = win32_name.get_devn ();
356 if (isproc_dev (devn))
362 syscall_printf ("_unlink (%s)", win32_name.get_win32 ());
364 if (!win32_name.exists ())
366 syscall_printf ("unlinking a nonexistent file");
370 else if (win32_name.isdir ())
372 syscall_printf ("unlinking a directory");
378 if (!((DWORD) win32_name & (FILE_ATTRIBUTE_READONLY
379 | FILE_ATTRIBUTE_SYSTEM
380 | FILE_ATTRIBUTE_HIDDEN)))
384 /* Allow us to delete even if read-only */
385 setattrs = SetFileAttributes (win32_name,
387 & ~(FILE_ATTRIBUTE_READONLY
388 | FILE_ATTRIBUTE_SYSTEM
389 | FILE_ATTRIBUTE_HIDDEN));
393 lasterr = wincap.is_winnt () ? unlink_nt (win32_name, setattrs)
394 : unlink_9x (win32_name);
399 SetFileAttributes (win32_name, (DWORD) win32_name);
401 /* Windows 9x seems to report ERROR_ACCESS_DENIED rather than sharing
403 if ((wincap.access_denied_on_delete () && lasterr == ERROR_ACCESS_DENIED
404 && !win32_name.isremote ())
405 || lasterr == ERROR_SHARING_VIOLATION)
407 /* Add file to the "to be deleted" queue. */
408 syscall_printf ("Sharing violation, couldn't delete file");
409 user_shared->delqueue.queue_file (win32_name);
413 __seterrno_from_win_error (lasterr);
417 syscall_printf ("%d = unlink (%s)", res, ourname);
422 _remove_r (struct _reent *, const char *ourname)
424 path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
426 if (win32_name.error)
428 set_errno (win32_name.error);
429 syscall_printf ("-1 = remove (%s)", ourname);
433 return win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
437 remove (const char *ourname)
439 path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
441 if (win32_name.error)
443 set_errno (win32_name.error);
444 syscall_printf ("-1 = remove (%s)", ourname);
448 return win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
458 _getpid_r (struct _reent *)
463 /* getppid: POSIX 4.1.1.1 */
470 /* setsid: POSIX 4.3.2.1 */
475 vfork_save *vf = vfork_storage.val ();
476 /* This is a horrible, horrible kludge */
477 if (vf && vf->pid < 0)
482 syscall_printf ("longjmping due to vfork");
483 vf->restore_pid (pid);
485 /* assuming that fork was successful */
489 if (myself->pgid == myself->pid)
490 syscall_printf ("hmm. pgid %d pid %d", myself->pgid, myself->pid);
494 cygheap->manage_console_count ("setsid", 0);
495 myself->sid = getpid ();
496 myself->pgid = getpid ();
498 cygheap->close_ctty ();
499 syscall_printf ("sid %d, pgid %d, %s", myself->sid, myself->pgid, myctty ());
528 read (int fd, void *ptr, size_t len)
536 return readv (fd, &iov, 1);
540 pread (int fd, void *ptr, size_t len, _off64_t off)
543 cygheap_fdget cfd (fd);
547 res = cfd->pread (ptr, len, off);
549 syscall_printf ("%d = pread (%d, %p, %d, %d), errno %d",
550 res, fd, ptr, len, off, get_errno ());
555 pwrite (int fd, void *ptr, size_t len, _off64_t off)
558 cygheap_fdget cfd (fd);
562 res = cfd->pwrite (ptr, len, off);
564 syscall_printf ("%d = pwrite (%d, %p, %d, %d), errno %d",
565 res, fd, ptr, len, off, get_errno ());
569 EXPORT_ALIAS (read, _read)
572 write (int fd, const void *ptr, size_t len)
574 const struct iovec iov =
576 iov_base: (void *) ptr, // const_cast
580 return writev (fd, &iov, 1);
583 EXPORT_ALIAS (write, _write)
586 readv (int fd, const struct iovec *const iov, const int iovcnt)
588 extern int sigcatchers;
589 const int e = get_errno ();
593 const ssize_t tot = check_iovec_for_read (iov, iovcnt);
603 sig_dispatch_pending ();
605 cygheap_fdget cfd (fd);
609 if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
615 DWORD wait = cfd->is_nonblocking () ? 0 : INFINITE;
617 /* Could block, so let user know we at least got here. */
618 syscall_printf ("readv (%d, %p, %d) %sblocking, sigcatchers %d",
619 fd, iov, iovcnt, wait ? "" : "non", sigcatchers);
621 if (wait && (!cfd->is_slow () || cfd->uninterruptible_io ()))
622 debug_printf ("no need to call ready_for_read");
623 else if (!cfd->ready_for_read (fd, wait))
629 /* FIXME: This is not thread safe. We need some method to
630 ensure that an fd, closed in another thread, aborts I/O
635 /* Check to see if this is a background read from a "tty",
636 sending a SIGTTIN, if appropriate */
637 res = cfd->bg_check (SIGTTIN);
647 myself->process_state |= PID_TTYIN;
653 res = cfd->readv (iov, iovcnt, tot);
654 myself->process_state &= ~PID_TTYIN;
658 if (res >= 0 || get_errno () != EINTR || !_my_tls.call_signal_handler ())
664 syscall_printf ("%d = readv (%d, %p, %d), errno %d", res, fd, iov, iovcnt,
671 writev (const int fd, const struct iovec *const iov, const int iovcnt)
674 sig_dispatch_pending ();
675 const ssize_t tot = check_iovec_for_write (iov, iovcnt);
677 cygheap_fdget cfd (fd);
687 if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
693 /* Could block, so let user know we at least got here. */
694 if (fd == 1 || fd == 2)
695 paranoid_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
697 syscall_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
699 res = cfd->bg_check (SIGTTOU);
701 if (res > (int) bg_eof)
703 myself->process_state |= PID_TTYOU;
704 res = cfd->writev (iov, iovcnt, tot);
705 myself->process_state &= ~PID_TTYOU;
709 if (fd == 1 || fd == 2)
710 paranoid_printf ("%d = write (%d, %p, %d), errno %d",
711 res, fd, iov, iovcnt, get_errno ());
713 syscall_printf ("%d = write (%d, %p, %d), errno %d",
714 res, fd, iov, iovcnt, get_errno ());
721 /* newlib's fcntl.h defines _open as taking variable args so we must
722 correspond. The third arg if it exists is: mode_t mode. */
724 open (const char *unix_path, int flags, ...)
729 sig_dispatch_pending ();
731 syscall_printf ("open (%s, %p)", unix_path, flags);
733 if (efault.faulted (EFAULT))
734 /* errno already set */;
735 else if (!*unix_path)
739 /* check for optional mode argument */
740 va_start (ap, flags);
741 mode = va_arg (ap, mode_t);
749 if (!(fh = build_fh_name (unix_path, NULL, (flags & O_NOFOLLOW) ?
750 PC_SYM_NOFOLLOW : PC_SYM_FOLLOW,
751 transparent_exe ? stat_suffixes : NULL)))
752 res = -1; // errno already set
753 else if ((flags & O_NOFOLLOW) && fh->issymlink ())
759 else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) && fh->exists ())
765 else if (fh->is_fs_special () && fh->device_access_denied (flags))
770 else if (!fh->open (flags, (mode & 07777) & ~cygheap->umask))
777 cygheap->fdtab[fd] = fh;
779 set_std_handle (res);
784 syscall_printf ("%d = open (%s, %p)", res, unix_path, flags);
788 EXPORT_ALIAS (open, _open )
789 EXPORT_ALIAS (open, _open64 )
792 lseek64 (int fd, _off64_t pos, int dir)
796 if (dir != SEEK_SET && dir != SEEK_CUR && dir != SEEK_END)
803 cygheap_fdget cfd (fd);
805 res = cfd->lseek (pos, dir);
809 syscall_printf ("%D = lseek (%d, %D, %d)", res, fd, pos, dir);
814 EXPORT_ALIAS (lseek64, _lseek64)
817 lseek (int fd, _off_t pos, int dir)
819 return lseek64 (fd, (_off64_t) pos, dir);
822 EXPORT_ALIAS (lseek, _lseek)
829 syscall_printf ("close (%d)", fd);
832 cygheap_fdget cfd (fd, true);
841 syscall_printf ("%d = close (%d)", res, fd);
846 EXPORT_ALIAS (close, _close)
853 cygheap_fdget cfd (fd);
857 res = cfd->is_tty ();
858 syscall_printf ("%d = isatty (%d)", res, fd);
862 /* Under NT, try to make a hard link using backup API. If that
863 fails or we are Win 95, just copy the file.
864 FIXME: We should actually be checking partition type, not OS.
865 Under NTFS, we should support hard links. On FAT partitions,
866 we should just copy the file.
870 link (const char *oldpath, const char *newpath)
875 if (!(fh = build_fh_name (oldpath, NULL, PC_SYM_NOFOLLOW,
876 transparent_exe ? stat_suffixes : NULL)))
881 debug_printf ("got %d error from build_fh_name", fh->error ());
882 set_errno (fh->error ());
885 res = fh->link (newpath);
889 syscall_printf ("%d = link (%s, %s)", res, oldpath, newpath);
893 /* chown: POSIX 5.6.5.1 */
895 * chown () is only implemented for Windows NT. Under other operating
896 * systems, it is only a stub that always returns zero.
899 chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid)
901 if (!wincap.has_security ()) // real chown only works on NT
902 return 0; // return zero (and do nothing) under Windows 9x
907 if (!(fh = build_fh_name (name, NULL, fmode, stat_suffixes)))
912 debug_printf ("got %d error from build_fh_name", fh->error ());
913 set_errno (fh->error ());
916 res = fh->fchown (uid, gid);
920 syscall_printf ("%d = %schown (%s,...)",
921 res, (fmode & PC_SYM_NOFOLLOW) ? "l" : "", name);
926 chown32 (const char * name, __uid32_t uid, __gid32_t gid)
928 return chown_worker (name, PC_SYM_FOLLOW, uid, gid);
932 chown (const char * name, __uid16_t uid, __gid16_t gid)
934 return chown_worker (name, PC_SYM_FOLLOW,
935 uid16touid32 (uid), gid16togid32 (gid));
939 lchown32 (const char * name, __uid32_t uid, __gid32_t gid)
941 return chown_worker (name, PC_SYM_NOFOLLOW, uid, gid);
945 lchown (const char * name, __uid16_t uid, __gid16_t gid)
947 return chown_worker (name, PC_SYM_NOFOLLOW,
948 uid16touid32 (uid), gid16togid32 (gid));
952 fchown32 (int fd, __uid32_t uid, __gid32_t gid)
954 if (!wincap.has_security ()) // real chown only works on NT
955 return 0; // return zero (and do nothing) under Windows 9x
957 cygheap_fdget cfd (fd);
960 syscall_printf ("-1 = fchown (%d,...)", fd);
964 int res = cfd->fchown (uid, gid);
966 syscall_printf ("%d = fchown (%s,...)", res, cfd->get_name ());
971 fchown (int fd, __uid16_t uid, __gid16_t gid)
973 return fchown32 (fd, uid16touid32 (uid), gid16togid32 (gid));
976 /* umask: POSIX 5.3.3.1 */
982 oldmask = cygheap->umask;
983 cygheap->umask = mask & 0777;
988 chmod_device (path_conv& pc, mode_t mode)
990 return mknod_worker (pc, pc.dev.mode & S_IFMT, mode, pc.dev.major, pc.dev.minor);
993 /* chmod: POSIX 5.6.4.1 */
995 chmod (const char *path, mode_t mode)
999 if (!(fh = build_fh_name (path, NULL, PC_SYM_FOLLOW, stat_suffixes)))
1004 debug_printf ("got %d error from build_fh_name", fh->error ());
1005 set_errno (fh->error ());
1008 res = fh->fchmod (mode);
1012 syscall_printf ("%d = chmod (%s, %p)", res, path, mode);
1016 /* fchmod: P96 5.6.4.1 */
1019 fchmod (int fd, mode_t mode)
1021 cygheap_fdget cfd (fd);
1024 syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode);
1028 return cfd->fchmod (mode);
1032 stat64_to_stat32 (struct __stat64 *src, struct __stat32 *dst)
1034 dst->st_dev = ((src->st_dev >> 8) & 0xff00) | (src->st_dev & 0xff);
1035 dst->st_ino = ((unsigned) (src->st_ino >> 32)) | (unsigned) src->st_ino;
1036 dst->st_mode = src->st_mode;
1037 dst->st_nlink = src->st_nlink;
1038 dst->st_uid = src->st_uid;
1039 dst->st_gid = src->st_gid;
1040 dst->st_rdev = ((src->st_rdev >> 8) & 0xff00) | (src->st_rdev & 0xff);
1041 dst->st_size = src->st_size;
1042 dst->st_atim = src->st_atim;
1043 dst->st_mtim = src->st_mtim;
1044 dst->st_ctim = src->st_ctim;
1045 dst->st_blksize = src->st_blksize;
1046 dst->st_blocks = src->st_blocks;
1050 fstat64 (int fd, struct __stat64 *buf)
1054 cygheap_fdget cfd (fd);
1059 memset (buf, 0, sizeof (struct __stat64));
1060 res = cfd->fstat (buf);
1064 buf->st_ino = cfd->get_namehash ();
1066 buf->st_dev = cfd->get_device ();
1068 buf->st_rdev = buf->st_dev;
1072 syscall_printf ("%d = fstat (%d, %p)", res, fd, buf);
1077 _fstat64_r (struct _reent *ptr, int fd, struct __stat64 *buf)
1081 if ((ret = fstat64 (fd, buf)) == -1)
1082 ptr->_errno = get_errno ();
1087 fstat (int fd, struct __stat32 *buf)
1089 struct __stat64 buf64;
1090 int ret = fstat64 (fd, &buf64);
1092 stat64_to_stat32 (&buf64, buf);
1097 _fstat_r (struct _reent *ptr, int fd, struct __stat32 *buf)
1101 if ((ret = fstat (fd, buf)) == -1)
1102 ptr->_errno = get_errno ();
1106 /* fsync: P96 6.6.1.1 */
1110 cygheap_fdget cfd (fd);
1113 syscall_printf ("-1 = fsync (%d)", fd);
1116 return cfd->fsync ();
1119 EXPORT_ALIAS (fsync, fdatasync)
1122 sync_worker (const char *vol)
1124 HANDLE fh = CreateFileA (vol, GENERIC_WRITE, wincap.shared (),
1125 &sec_none_nih, OPEN_EXISTING, 0, NULL);
1126 if (fh != INVALID_HANDLE_VALUE)
1128 FlushFileBuffers (fh);
1132 debug_printf ("Open failed with %E");
1139 char vol[CYG_MAX_PATH];
1141 if (wincap.has_guid_volumes ()) /* Win2k and newer */
1143 char a_drive[CYG_MAX_PATH] = {0};
1144 char b_drive[CYG_MAX_PATH] = {0};
1146 if (is_floppy ("A:"))
1147 GetVolumeNameForVolumeMountPointA ("A:\\", a_drive, CYG_MAX_PATH);
1148 if (is_floppy ("B:"))
1149 GetVolumeNameForVolumeMountPointA ("B:\\", b_drive, CYG_MAX_PATH);
1151 HANDLE sh = FindFirstVolumeA (vol, CYG_MAX_PATH);
1152 if (sh != INVALID_HANDLE_VALUE)
1156 debug_printf ("Try volume %s", vol);
1158 /* Check vol for being a floppy on A: or B:. Skip them. */
1159 if (strcasematch (vol, a_drive) || strcasematch (vol, b_drive))
1161 debug_printf ("Is floppy, don't sync");
1165 /* Eliminate trailing backslash. */
1166 vol[strlen (vol) - 1] = '\0';
1169 while (FindNextVolumeA (sh, vol, CYG_MAX_PATH));
1170 FindVolumeClose (sh);
1173 else if (wincap.is_winnt ()) /* 9x has no concept for opening volumes */
1175 DWORD drives = GetLogicalDrives ();
1177 /* Skip floppies on A: and B: as in setmntent. */
1178 if ((drives & 1) && is_floppy ("A:"))
1180 if ((drives & 2) && is_floppy ("B:"))
1182 strcpy (vol, "\\\\.\\A:");
1185 /* Geeh. Try to sync only non-floppy drives. */
1188 debug_printf ("Try volume %s", vol);
1193 while ((mask <<= 1) <= 1 << 25);
1197 /* Cygwin internal */
1198 static int __stdcall
1199 stat_worker (const char *name, struct __stat64 *buf, int nofollow)
1202 fhandler_base *fh = NULL;
1205 if (efault.faulted (EFAULT))
1208 if (!(fh = build_fh_name (name, NULL, nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW,
1214 debug_printf ("got %d error from build_fh_name", fh->error ());
1215 set_errno (fh->error ());
1217 else if (fh->exists ())
1219 debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow,
1221 memset (buf, 0, sizeof (*buf));
1222 res = fh->fstat (buf);
1226 buf->st_ino = fh->get_namehash ();
1228 buf->st_dev = fh->get_device ();
1230 buf->st_rdev = buf->st_dev;
1239 syscall_printf ("%d = (%s, %p)", res, name, buf);
1244 stat64 (const char *name, struct __stat64 *buf)
1246 syscall_printf ("entering");
1247 return stat_worker (name, buf, 0);
1251 _stat64_r (struct _reent *ptr, const char *name, struct __stat64 *buf)
1255 if ((ret = stat64 (name, buf)) == -1)
1256 ptr->_errno = get_errno ();
1261 stat (const char *name, struct __stat32 *buf)
1263 struct __stat64 buf64;
1264 int ret = stat64 (name, &buf64);
1266 stat64_to_stat32 (&buf64, buf);
1271 _stat_r (struct _reent *ptr, const char *name, struct __stat32 *buf)
1275 if ((ret = stat (name, buf)) == -1)
1276 ptr->_errno = get_errno ();
1280 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1282 lstat64 (const char *name, struct __stat64 *buf)
1284 syscall_printf ("entering");
1285 return stat_worker (name, buf, 1);
1288 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1290 lstat (const char *name, struct __stat32 *buf)
1292 struct __stat64 buf64;
1293 int ret = lstat64 (name, &buf64);
1295 stat64_to_stat32 (&buf64, buf);
1300 access (const char *fn, int flags)
1302 // flags were incorrectly specified
1304 if (flags & ~(F_OK|R_OK|W_OK|X_OK))
1308 fhandler_base *fh = build_fh_name (fn, NULL, PC_SYM_FOLLOW, stat_suffixes);
1311 res = fh->fhaccess (flags);
1315 debug_printf ("returning %d", res);
1320 rename (const char *oldpath, const char *newpath)
1323 char *lnk_suffix = NULL;
1324 bool no_lnk_file_exists = false;
1326 path_conv real_old (oldpath, PC_SYM_NOFOLLOW,
1327 transparent_exe ? stat_suffixes : NULL);
1331 syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath);
1332 set_errno (real_old.error);
1336 if (!real_old.exists ()) /* file to move doesn't exist */
1338 syscall_printf ("file to move doesn't exist");
1343 path_conv real_new (newpath, PC_SYM_NOFOLLOW,
1344 transparent_exe ? stat_suffixes : NULL);
1346 char new_buf[CYG_MAX_PATH + 5];
1347 if (!real_new.error && !real_new.case_clash)
1352 if (real_old.is_lnk_special ())
1354 if (real_new.exists ())
1356 /* This early directory test is necessary because the below test
1357 tests against the name with attached .lnk suffix. To avoid
1358 name collisions, we shouldn't rename a file to "foo.lnk"
1359 if a "foo" directory exists. */
1360 if (real_new.isdir ())
1362 syscall_printf ("newpath is directory, but oldpath is not");
1366 /* Shortcut hack, No. 3, part 1 */
1367 no_lnk_file_exists = true;
1369 /* Shortcut hack. */
1370 strcpy (new_buf, newpath);
1371 strcat (new_buf, ".lnk");
1373 real_new.check (newpath, PC_SYM_NOFOLLOW);
1375 else if (transparent_exe
1376 && !real_old.isdir ()
1377 && GetBinaryType (real_old, &bintype)
1378 && (len = strlen (real_new)) > 4
1379 && !strcasematch ((const char *) real_new + len - 4, ".exe"))
1381 /* Executable hack. */
1382 strcpy (new_buf, newpath);
1383 strcat (new_buf, ".exe");
1385 real_new.check (newpath, PC_SYM_NOFOLLOW);
1389 if (real_new.error || real_new.case_clash)
1391 syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath);
1392 set_errno (real_new.case_clash ? ECASECLASH : real_new.error);
1396 if (real_new.isdir () && !real_old.isdir ())
1398 syscall_printf ("newpath is directory, but oldpath is not");
1403 /* Destination file exists and is read only, change that or else
1404 the rename won't work. */
1405 if (real_new.has_attribute (FILE_ATTRIBUTE_READONLY))
1406 SetFileAttributes (real_new, (DWORD) real_new & ~FILE_ATTRIBUTE_READONLY);
1408 /* Shortcut hack No. 2, part 1 */
1409 if (!real_old.issymlink () && !real_new.error && real_new.is_lnk_special ()
1410 && (lnk_suffix = strrchr (real_new.get_win32 (), '.')))
1413 if (MoveFile (real_old, real_new))
1418 /* Test for an attempt to make a directory a subdirectory of itself first.
1419 This test has to be made before any attempt to remove the potentially
1420 existing file or directory real_new. Otherwise we end up with a
1421 non-moved directory *and* a deleted read_new path. Also this case
1422 has to generate an EINVAL in all circumstances,
1424 NB: We could test this also before calling MoveFile but the idea is
1425 that this is a somewhat seldom case and we like to avoid expensive
1426 string comparison. So we allow MoveFile to fail and test the error
1429 The order in the condition is (hopefully) trimmed for doing the least
1430 expensive stuff first. Nevertheless it would be nice if 9x could
1431 generate the same error codes as NT.
1432 NT generates ERROR_SHARING_VIOLATION in all cases, while 9x generates
1433 ERROR_ACCESS_DENIED if the target path doesn't exist,
1434 ERROR_ALREADY_EXISTS otherwise */
1437 lasterr = GetLastError ();
1438 if (real_old.isdir ()
1439 && ((lasterr == ERROR_SHARING_VIOLATION && wincap.has_move_file_ex ())
1440 || (lasterr == ERROR_ACCESS_DENIED && !real_new.exists ()
1441 && !wincap.has_move_file_ex ())
1442 || (lasterr == ERROR_ALREADY_EXISTS && real_new.exists ()
1443 && !wincap.has_move_file_ex ()))
1444 && (len = strlen (real_old), strncasematch (real_old, real_new, len))
1445 && real_new[len] == '\\')
1446 SetLastError (ERROR_INVALID_PARAMETER);
1447 else if (real_new.isdir ())
1449 /* Since neither MoveFileEx(MOVEFILE_REPLACE_EXISTING) nor DeleteFile
1450 allow to remove directories, this case is handled separately. */
1451 if (!RemoveDirectoryA (real_new))
1453 syscall_printf ("Can't remove target directory");
1454 /* On 9X ERROR_ACCESS_DENIED is returned if you try to remove
1455 a non-empty directory. */
1456 if (GetLastError () == ERROR_ACCESS_DENIED
1457 && wincap.access_denied_on_delete ())
1458 SetLastError (ERROR_DIR_NOT_EMPTY);
1460 else if (MoveFile (real_old, real_new))
1463 else if (wincap.has_move_file_ex ())
1465 if (MoveFileEx (real_old.get_win32 (), real_new.get_win32 (),
1466 MOVEFILE_REPLACE_EXISTING))
1469 else if (lasterr == ERROR_ALREADY_EXISTS || lasterr == ERROR_FILE_EXISTS)
1471 syscall_printf ("try win95 hack");
1472 for (int i = 0; i < 2; i++)
1474 if (!DeleteFileA (real_new) &&
1475 GetLastError () != ERROR_FILE_NOT_FOUND)
1477 syscall_printf ("deleting %s to be paranoid",
1478 real_new.get_win32 ());
1481 else if (MoveFile (real_old, real_new))
1493 /* Reset R/O attributes if neccessary. */
1494 if (real_new.has_attribute (FILE_ATTRIBUTE_READONLY))
1495 SetFileAttributes (real_new, real_new);
1499 /* make the new file have the permissions of the old one */
1500 DWORD attr = real_old;
1501 #ifdef HIDDEN_DOT_FILES
1502 char *c = strrchr (real_old.get_win32 (), '\\');
1503 if ((c && c[1] == '.') || *real_old.get_win32 () == '.')
1504 attr &= ~FILE_ATTRIBUTE_HIDDEN;
1505 c = strrchr (real_new.get_win32 (), '\\');
1506 if ((c && c[1] == '.') || *real_new.get_win32 () == '.')
1507 attr |= FILE_ATTRIBUTE_HIDDEN;
1509 SetFileAttributes (real_new, attr);
1511 /* Shortcut hack, No. 2, part 2 */
1512 /* if the new filename was an existing shortcut, remove it now if the
1513 new filename is equal to the shortcut name without .lnk suffix. */
1517 DeleteFile (real_new);
1519 /* Shortcut hack, No. 3, part 2 */
1520 /* If a file with the given name exists, it must be deleted after the
1521 symlink has been renamed. Otherwise we end up with two files of
1522 the same name in the directory, one file "newpath", which already
1523 exited before rename has been called, and one file "newpath.lnk",
1524 which is the result of the rename operation. */
1525 else if (no_lnk_file_exists)
1527 lnk_suffix = strrchr (real_new.get_win32 (), '.');
1529 DeleteFile (real_new);
1533 syscall_printf ("%d = rename (%s, %s)", res, (char *) real_old,
1540 system (const char *cmdstring)
1542 pthread_testcancel ();
1545 if (efault.faulted (EFAULT))
1549 const char* command[4];
1551 if (cmdstring == NULL)
1556 command[2] = cmdstring;
1557 command[3] = (const char *) NULL;
1559 if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1)
1561 // when exec fails, return value should be as if shell
1562 // executed exit (127)
1570 setdtablesize (int size)
1572 if (size <= (int)cygheap->fdtab.size || cygheap->fdtab.extend (size - cygheap->fdtab.size))
1581 return cygheap->fdtab.size > OPEN_MAX ? cygheap->fdtab.size : OPEN_MAX;
1587 if (!system_info.dwAllocationGranularity)
1588 GetSystemInfo (&system_info);
1589 return (size_t) system_info.dwAllocationGranularity;
1593 getsystempagesize ()
1595 if (!system_info.dwPageSize)
1596 GetSystemInfo (&system_info);
1597 return (size_t) system_info.dwPageSize;
1600 /* FIXME: not all values are correct... */
1602 fpathconf (int fd, int v)
1604 cygheap_fdget cfd (fd);
1607 return cfd->fpathconf (v);
1611 pathconf (const char *file, int v)
1616 if (efault.faulted (EFAULT))
1623 if (!(fh = build_fh_name (file, NULL, PC_SYM_FOLLOW,
1624 transparent_exe ? stat_suffixes : NULL)))
1631 return fh->fpathconf (v);
1635 ttyname_r (int fd, char *buf, size_t buflen)
1639 if (efault.faulted ())
1643 cygheap_fdget cfd (fd, true);
1646 else if (!cfd->is_tty ())
1648 else if (buflen < strlen (cfd->ttyname ()) + 1)
1651 strcpy (buf, cfd->ttyname ());
1653 debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf);
1660 static char name[TTY_NAME_MAX + 1];
1661 int ret = ttyname_r (fd, name, TTY_NAME_MAX + 1);
1673 static NO_COPY char buf[16];
1676 if (!real_tty_attached (myself))
1677 strcpy (str, "/dev/conin");
1679 __small_sprintf (str, "/dev/tty%d", myself->ctty);
1683 /* Tells stdio if it should do the cr/lf conversion for this file */
1685 _cygwin_istext_for_stdio (int fd)
1687 if (CYGWIN_VERSION_OLD_STDIO_CRLF_HANDLING)
1689 syscall_printf ("fd %d: old API", fd);
1690 return 0; /* we do it for old apps, due to getc/putc macros */
1693 cygheap_fdget cfd (fd, false, false);
1696 syscall_printf ("fd %d: not open", fd);
1701 if (cfd->get_device () != FH_FS)
1703 syscall_printf ("fd not disk file. Defaulting to binary.");
1708 if (cfd->wbinary () || cfd->rbinary ())
1710 syscall_printf ("fd %d: opened as binary", fd);
1714 syscall_printf ("fd %d: defaulting to text", fd);
1718 /* internal newlib function */
1719 extern "C" int _fwalk (struct _reent *ptr, int (*function) (FILE *));
1722 setmode_helper (FILE *f)
1724 if (fileno (f) != _my_tls.locals.setmode_file)
1726 syscall_printf ("improbable, but %d != %d", fileno (f), _my_tls.locals.setmode_file);
1729 syscall_printf ("file was %s now %s", f->_flags & __SCLE ? "text" : "binary",
1730 _my_tls.locals.setmode_mode & O_TEXT ? "text" : "binary");
1731 if (_my_tls.locals.setmode_mode & O_TEXT)
1732 f->_flags |= __SCLE;
1734 f->_flags &= ~__SCLE;
1741 cygheap_fdget cfd (fd);
1745 return cfd->get_flags () & (O_BINARY | O_TEXT);
1748 /* Set a file descriptor into text or binary mode, returning the
1752 setmode (int fd, int mode)
1754 cygheap_fdget cfd (fd);
1757 if (mode != O_BINARY && mode != O_TEXT && mode != 0)
1763 /* Note that we have no way to indicate the case that writes are
1764 binary but not reads, or vice-versa. These cases can arise when
1765 using the tty or console interface. People using those
1766 interfaces should not use setmode. */
1769 if (cfd->wbinary () && cfd->rbinary ())
1771 else if (cfd->wbinset () && cfd->rbinset ())
1772 res = O_TEXT; /* Specifically set O_TEXT */
1777 cfd->reset_to_open_binmode ();
1779 cfd->set_flags ((cfd->get_flags () & ~(O_TEXT | O_BINARY)) | mode);
1781 syscall_printf ("(%d<%s>, %p) returning %s", fd, cfd->get_name (),
1782 mode, res & O_TEXT ? "text" : "binary");
1787 cygwin_setmode (int fd, int mode)
1789 int res = setmode (fd, mode);
1792 _my_tls.locals.setmode_file = fd;
1793 if (_cygwin_istext_for_stdio (fd))
1794 _my_tls.locals.setmode_mode = O_TEXT;
1796 _my_tls.locals.setmode_mode = O_BINARY;
1797 _fwalk (_GLOBAL_REENT, setmode_helper);
1803 posix_fadvise (int fd, _off64_t offset, _off64_t len, int advice)
1806 cygheap_fdget cfd (fd);
1808 res = cfd->fadvise (offset, len, advice);
1811 syscall_printf ("%d = posix_fadvice (%d, %D, %D, %d)",
1812 res, fd, offset, len, advice);
1817 posix_fallocate (int fd, _off64_t offset, _off64_t len)
1820 if (offset < 0 || len == 0)
1824 cygheap_fdget cfd (fd);
1826 res = cfd->ftruncate (offset + len, false);
1830 syscall_printf ("%d = posix_fallocate (%d, %D, %D)", res, fd, offset, len);
1835 ftruncate64 (int fd, _off64_t length)
1838 cygheap_fdget cfd (fd);
1840 res = cfd->ftruncate (length, true);
1843 syscall_printf ("%d = ftruncate (%d, %D)", res, fd, length);
1847 /* ftruncate: P96 5.6.7.1 */
1849 ftruncate (int fd, _off_t length)
1851 return ftruncate64 (fd, (_off64_t)length);
1854 /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
1856 truncate64 (const char *pathname, _off64_t length)
1861 fd = open (pathname, O_RDWR);
1865 res = ftruncate64 (fd, length);
1868 syscall_printf ("%d = truncate (%s, %D)", res, pathname, length);
1873 /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
1875 truncate (const char *pathname, _off_t length)
1877 return truncate64 (pathname, (_off64_t)length);
1881 get_osfhandle (int fd)
1885 cygheap_fdget cfd (fd);
1887 res = (long) cfd->get_handle ();
1891 syscall_printf ("%d = get_osfhandle (%d)", res, fd);
1896 statvfs (const char *fname, struct statvfs *sfs)
1899 char root[CYG_MAX_PATH];
1902 if (efault.faulted (EFAULT))
1910 syscall_printf ("statfs %s", fname);
1918 path_conv full_path (fname, PC_SYM_FOLLOW);
1919 if (!full_path.rootdir (root))
1921 set_errno (ENOTDIR);
1925 ULARGE_INTEGER availb, freeb, totalb;
1926 DWORD spc, bps, availc, freec, totalc, vsn, maxlen, flags;
1927 BOOL status, statusex;
1929 /* GetDiskFreeSpaceEx must be called before GetDiskFreeSpace on
1930 WinME, to avoid the MS KB 314417 bug */
1931 statusex = GetDiskFreeSpaceEx (root, &availb, &totalb, &freeb);
1932 status = GetDiskFreeSpace (root, &spc, &bps, &freec, &totalc);
1933 if (!status && statusex)
1935 /* Grrr, this can happen on 9x when a share isn't attached to
1936 a drive letter. Fake, fake, hoorah. */
1940 while ((totalb.QuadPart % (spc*bps)) && spc > 1)
1947 availc = availb.QuadPart / (spc*bps);
1948 totalc = totalb.QuadPart / (spc*bps);
1949 freec = freeb.QuadPart / (spc*bps);
1952 /* Quotas active. We can't trust totalc. */
1953 HANDLE hdl = CreateFile (full_path, READ_CONTROL,
1954 wincap.shared (), &sec_none_nih,
1956 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1957 if (hdl == INVALID_HANDLE_VALUE)
1958 debug_printf ("CreateFile (%s) failed, %E", (char *) full_path);
1961 NTFS_VOLUME_DATA_BUFFER nvdb;
1963 if (!DeviceIoControl (hdl, FSCTL_GET_NTFS_VOLUME_DATA, NULL,
1964 0, &nvdb, sizeof nvdb, &bytes, NULL))
1965 debug_printf ("DeviceIoControl (%s) failed, %E", (char *) full_path);
1967 totalc = nvdb.TotalClusters.QuadPart;
1974 if (GetVolumeInformation (root, NULL, 0, &vsn, &maxlen, &flags, NULL, 0))
1976 sfs->f_bsize = spc*bps;
1977 sfs->f_frsize = spc*bps;
1978 sfs->f_blocks = totalc;
1979 sfs->f_bfree = freec;
1980 sfs->f_bavail = availc;
1981 sfs->f_files = ULONG_MAX;
1982 sfs->f_ffree = ULONG_MAX;
1983 sfs->f_favail = ULONG_MAX;
1985 sfs->f_flag = flags;
1986 sfs->f_namemax = maxlen;
1997 fstatvfs (int fd, struct statvfs *sfs)
1999 cygheap_fdget cfd (fd);
2002 return statvfs (cfd->get_name (), sfs);
2006 statfs (const char *fname, struct statfs *sfs)
2009 if (efault.faulted (EFAULT))
2012 int ret = statvfs (fname, &vfs);
2015 sfs->f_type = vfs.f_flag;
2016 sfs->f_bsize = vfs.f_bsize;
2017 sfs->f_blocks = vfs.f_blocks;
2018 sfs->f_bavail = vfs.f_bavail;
2019 sfs->f_bfree = vfs.f_bfree;
2022 sfs->f_fsid = vfs.f_fsid;
2023 sfs->f_namelen = vfs.f_namemax;
2029 fstatfs (int fd, struct statfs *sfs)
2031 cygheap_fdget cfd (fd);
2034 return statfs (cfd->get_name (), sfs);
2037 /* setpgid: POSIX 4.3.3.1 */
2039 setpgid (pid_t pid, pid_t pgid)
2051 pinfo p (pid, PID_MAP_RW);
2054 else if (p->pgid == pgid)
2056 /* A process may only change the process group of itself and its children */
2057 else if (p != myself && p->ppid != myself->pid)
2062 if (p->pid != p->pgid)
2063 p->set_has_pgid_children (0);
2068 syscall_printf ("pid %d, pgid %d, res %d", pid, pgid, res);
2090 return setpgid (0, 0);
2102 cygheap_fdget cfd (fd);
2105 return (char *) (cfd->ptsname ());
2108 /* FIXME: what is this? */
2109 extern "C" int __declspec(dllexport)
2115 static int __stdcall
2116 mknod_worker (const char *path, mode_t type, mode_t mode, _major_t major,
2119 char buf[sizeof (":\\00000000:00000000:00000000") + CYG_MAX_PATH];
2120 sprintf (buf, ":\\%x:%x:%x", major, minor,
2121 type | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)));
2122 return symlink_worker (buf, path, true, true);
2126 mknod32 (const char *path, mode_t mode, __dev32_t dev)
2129 if (efault.faulted (EFAULT))
2137 if (strlen (path) >= CYG_MAX_PATH)
2140 path_conv w32path (path, PC_SYM_NOFOLLOW);
2141 if (w32path.exists ())
2147 mode_t type = mode & S_IFMT;
2148 _major_t major = _major (dev);
2149 _minor_t minor = _minor (dev);
2157 major = _major (FH_FIFO);
2158 minor = _minor (FH_FIFO);
2164 int fd = open (path, O_CREAT, mode);
2176 return mknod_worker (w32path, type, mode, major, minor);
2180 mknod (const char *_path, mode_t mode, __dev16_t dev)
2182 return mknod32 (_path, mode, (__dev32_t) dev);
2186 mkfifo (const char *path, mode_t mode)
2188 return mknod32 (path, (mode & ~S_IFMT) | S_IFIFO, 0);
2191 /* seteuid: standards? */
2193 seteuid32 (__uid32_t uid)
2195 debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
2196 uid, myself->uid, myself->gid);
2198 if (uid == myself->uid && !cygheap->user.groups.ischanged)
2200 debug_printf ("Nothing happens");
2205 user_groups &groups = cygheap->user.groups;
2206 HANDLE new_token = INVALID_HANDLE_VALUE;
2207 struct passwd * pw_new;
2208 bool token_is_internal, issamesid = false;
2210 pw_new = internal_getpwuid (uid);
2211 if (!wincap.has_security () && pw_new)
2213 load_registry_hive (pw_new->pw_name);
2216 if (!usersid.getfrompw (pw_new))
2222 cygheap->user.deimpersonate ();
2224 /* Verify if the process token is suitable. */
2225 if (verify_token (hProcToken, usersid, groups))
2226 new_token = hProcToken;
2227 /* Verify if the external token is suitable */
2228 else if (cygheap->user.external_token != NO_IMPERSONATION
2229 && verify_token (cygheap->user.external_token, usersid, groups))
2230 new_token = cygheap->user.external_token;
2231 /* Verify if the current token (internal or former external) is suitable */
2232 else if (cygheap->user.curr_primary_token != NO_IMPERSONATION
2233 && cygheap->user.curr_primary_token != cygheap->user.external_token
2234 && verify_token (cygheap->user.curr_primary_token, usersid, groups,
2235 &token_is_internal))
2236 new_token = cygheap->user.curr_primary_token;
2237 /* Verify if the internal token is suitable */
2238 else if (cygheap->user.internal_token != NO_IMPERSONATION
2239 && cygheap->user.internal_token != cygheap->user.curr_primary_token
2240 && verify_token (cygheap->user.internal_token, usersid, groups,
2241 &token_is_internal))
2242 new_token = cygheap->user.internal_token;
2244 debug_printf ("Found token %d", new_token);
2246 /* If no impersonation token is available, try to
2247 authenticate using NtCreateToken () or LSA authentication. */
2248 if (new_token == INVALID_HANDLE_VALUE)
2250 if (!(new_token = lsaauth (usersid, groups, pw_new)))
2252 debug_printf ("lsaauth failed, try create_token.");
2253 new_token = create_token (usersid, groups, pw_new);
2254 if (new_token == INVALID_HANDLE_VALUE)
2256 debug_printf ("create_token failed, bail out of here");
2257 cygheap->user.reimpersonate ();
2262 /* Keep at most one internal token */
2263 if (cygheap->user.internal_token != NO_IMPERSONATION)
2264 CloseHandle (cygheap->user.internal_token);
2265 cygheap->user.internal_token = new_token;
2268 if (new_token != hProcToken)
2270 /* Avoid having HKCU use default user */
2272 load_registry_hive (usersid.string (name));
2274 /* Try setting owner to same value as user. */
2275 if (!SetTokenInformation (new_token, TokenOwner,
2276 &usersid, sizeof usersid))
2277 debug_printf ("SetTokenInformation(user.token, TokenOwner), %E");
2278 /* Try setting primary group in token to current group */
2279 if (!SetTokenInformation (new_token, TokenPrimaryGroup,
2280 &groups.pgsid, sizeof (cygsid)))
2281 debug_printf ("SetTokenInformation(user.token, TokenPrimaryGroup), %E");
2282 /* Try setting default DACL */
2283 PACL dacl_buf = (PACL) alloca (MAX_DACL_LEN (5));
2284 if (sec_acl (dacl_buf, true, true, usersid))
2286 TOKEN_DEFAULT_DACL tdacl = { dacl_buf };
2287 if (!SetTokenInformation (new_token, TokenDefaultDacl,
2288 &tdacl, sizeof (tdacl)))
2289 debug_printf ("SetTokenInformation (TokenDefaultDacl), %E");
2293 issamesid = (usersid == cygheap->user.sid ());
2294 cygheap->user.set_sid (usersid);
2295 cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
2297 if (cygheap->user.current_token != NO_IMPERSONATION)
2299 CloseHandle (cygheap->user.current_token);
2300 cygheap->user.current_token = NO_IMPERSONATION;
2302 if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
2304 if (!DuplicateTokenEx (cygheap->user.curr_primary_token, MAXIMUM_ALLOWED,
2305 &sec_none, SecurityImpersonation,
2306 TokenImpersonation, &cygheap->user.current_token))
2309 cygheap->user.curr_primary_token = NO_IMPERSONATION;
2312 set_cygwin_privileges (cygheap->user.current_token);
2314 if (!cygheap->user.reimpersonate ())
2321 cygheap->user.set_name (pw_new->pw_name);
2323 groups.ischanged = FALSE;
2325 user_shared_initialize (true);
2330 seteuid (__uid16_t uid)
2332 return seteuid32 (uid16touid32 (uid));
2335 /* setuid: POSIX 4.2.2.1 */
2337 setuid32 (__uid32_t uid)
2339 int ret = seteuid32 (uid);
2341 cygheap->user.real_uid = myself->uid;
2342 debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
2347 setuid (__uid16_t uid)
2349 return setuid32 (uid16touid32 (uid));
2353 setreuid32 (__uid32_t ruid, __uid32_t euid)
2357 __uid32_t old_euid = myself->uid;
2359 if (ruid != ILLEGAL_UID && cygheap->user.real_uid != ruid && euid != ruid)
2360 tried = !(ret = seteuid32 (ruid));
2361 if (!ret && euid != ILLEGAL_UID)
2362 ret = seteuid32 (euid);
2363 if (tried && (ret || euid == ILLEGAL_UID) && seteuid32 (old_euid))
2364 system_printf ("Cannot restore original euid %u", old_euid);
2365 if (!ret && ruid != ILLEGAL_UID)
2366 cygheap->user.real_uid = ruid;
2367 debug_printf ("real: %u, effective: %u", cygheap->user.real_uid, myself->uid);
2372 setreuid (__uid16_t ruid, __uid16_t euid)
2374 return setreuid32 (uid16touid32 (ruid), uid16touid32 (euid));
2377 /* setegid: from System V. */
2379 setegid32 (__gid32_t gid)
2381 debug_printf ("new egid: %u current: %u", gid, myself->gid);
2383 if (gid == myself->gid || !wincap.has_security ())
2389 user_groups * groups = &cygheap->user.groups;
2391 struct __group32 * gr = internal_getgrgid (gid);
2393 if (!gsid.getfromgr (gr))
2400 groups->update_pgrp (gsid);
2401 if (cygheap->user.issetuid ())
2403 /* If impersonated, update impersonation token... */
2404 if (!SetTokenInformation (cygheap->user.primary_token (),
2405 TokenPrimaryGroup, &gsid, sizeof gsid))
2406 debug_printf ("SetTokenInformation(primary_token, "
2407 "TokenPrimaryGroup), %E");
2408 if (!SetTokenInformation (cygheap->user.token (), TokenPrimaryGroup,
2409 &gsid, sizeof gsid))
2410 debug_printf ("SetTokenInformation(token, TokenPrimaryGroup), %E");
2412 cygheap->user.deimpersonate ();
2413 if (!SetTokenInformation (hProcToken, TokenPrimaryGroup, &gsid, sizeof gsid))
2414 debug_printf ("SetTokenInformation(hProcToken, TokenPrimaryGroup), %E");
2415 clear_procimptoken ();
2416 cygheap->user.reimpersonate ();
2421 setegid (__gid16_t gid)
2423 return setegid32 (gid16togid32 (gid));
2426 /* setgid: POSIX 4.2.2.1 */
2428 setgid32 (__gid32_t gid)
2430 int ret = setegid32 (gid);
2432 cygheap->user.real_gid = myself->gid;
2437 setgid (__gid16_t gid)
2439 int ret = setegid32 (gid16togid32 (gid));
2441 cygheap->user.real_gid = myself->gid;
2446 setregid32 (__gid32_t rgid, __gid32_t egid)
2450 __gid32_t old_egid = myself->gid;
2452 if (rgid != ILLEGAL_GID && cygheap->user.real_gid != rgid && egid != rgid)
2453 tried = !(ret = setegid32 (rgid));
2454 if (!ret && egid != ILLEGAL_GID)
2455 ret = setegid32 (egid);
2456 if (tried && (ret || egid == ILLEGAL_GID) && setegid32 (old_egid))
2457 system_printf ("Cannot restore original egid %u", old_egid);
2458 if (!ret && rgid != ILLEGAL_GID)
2459 cygheap->user.real_gid = rgid;
2460 debug_printf ("real: %u, effective: %u", cygheap->user.real_gid, myself->gid);
2465 setregid (__gid16_t rgid, __gid16_t egid)
2467 return setregid32 (gid16togid32 (rgid), gid16togid32 (egid));
2470 /* chroot: privileged Unix system call. */
2471 /* FIXME: Not privileged here. How should this be done? */
2473 chroot (const char *newroot)
2475 path_conv path (newroot, PC_SYM_FOLLOW | PC_POSIX);
2479 set_errno (path.error);
2480 else if (!path.exists ())
2482 else if (!path.isdir ())
2483 set_errno (ENOTDIR);
2484 else if (path.isspecial ())
2488 getwinenv("PATH="); /* Save the native PATH */
2489 cygheap->root.set (path.normalized_path, path);
2493 syscall_printf ("%d = chroot (%s)", ret ? get_errno () : 0,
2494 newroot ? newroot : "NULL");
2499 creat (const char *path, mode_t mode)
2501 return open (path, O_WRONLY | O_CREAT | O_TRUNC, mode);
2514 ret = fread (&w, sizeof (int), 1, fp);
2515 return ret != 1 ? EOF : w;
2519 putw (int w, FILE *fp)
2522 ret = fwrite (&w, sizeof (int), 1, fp);
2523 if (feof (fp) || ferror (fp))
2529 wcscmp (const wchar_t *s1, const wchar_t *s2)
2531 while (*s1 && *s1 == *s2)
2537 return (* (unsigned short *) s1) - (* (unsigned short *) s2);
2541 wcslen (const wchar_t *s1)
2549 /* FIXME: to do this right, maybe work out the usoft va_list machine
2550 and use wsvprintfW instead?
2553 wprintf (const char *fmt, ...)
2559 ret = vprintf (fmt, ap);
2572 memccpy (_PTR out, const _PTR in, int c, size_t len)
2574 const char *inc = (char *) in;
2575 char *outc = (char *) out;
2589 setpriority (int which, id_t who, int value)
2591 DWORD prio = nice_to_winprio (value);
2599 if ((pid_t) who == myself->pid)
2601 if (!SetPriorityClass (hMainProc, prio))
2606 myself->nice = value;
2607 debug_printf ("Set nice to %d", myself->nice);
2623 winpids pids ((DWORD) PID_MAP_RW);
2624 for (DWORD i = 0; i < pids.npids; ++i)
2626 _pinfo *p = pids[i];
2632 if ((pid_t) who != p->pid)
2636 if ((pid_t) who != p->pgid)
2640 if ((__uid32_t) who != p->uid)
2644 HANDLE proc_h = OpenProcess (PROCESS_SET_INFORMATION, FALSE,
2650 if (!SetPriorityClass (proc_h, prio))
2654 CloseHandle (proc_h);
2668 getpriority (int which, id_t who)
2670 int nice = NZERO * 2; /* Illegal value */
2677 if ((pid_t) who == myself->pid)
2678 return myself->nice;
2692 winpids pids ((DWORD) 0);
2693 for (DWORD i = 0; i < pids.npids; ++i)
2695 _pinfo *p = pids[i];
2700 if ((pid_t) who == p->pid)
2707 if ((pid_t) who == p->pgid && p->nice < nice)
2711 if ((__uid32_t) who == p->uid && p->nice < nice)
2718 if (nice == NZERO * 2)
2729 return setpriority (PRIO_PROCESS, myself->pid, myself->nice + incr);
2733 * Find the first bit set in I.
2739 static const unsigned char table[] =
2741 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
2742 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
2743 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
2744 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
2745 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2746 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2747 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2748 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
2750 unsigned long int a;
2751 unsigned long int x = i & -i;
2753 a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24);
2755 return table[x >> a] + a;
2759 locked_append (int fd, const void * buf, size_t size)
2761 struct __flock64 lock_buffer = {F_WRLCK, SEEK_SET, 0, 0, 0};
2765 if ((lock_buffer.l_start = lseek64 (fd, 0, SEEK_END)) != (_off64_t) -1
2766 && fcntl_worker (fd, F_SETLKW, &lock_buffer) != -1)
2768 if (lseek64 (fd, 0, SEEK_END) != (_off64_t) -1)
2769 write (fd, buf, size);
2770 lock_buffer.l_type = F_UNLCK;
2771 fcntl_worker (fd, F_SETLK, &lock_buffer);
2774 while (count++ < 1000
2775 && (errno == EACCES || errno == EAGAIN)
2780 updwtmp (const char *wtmp_file, const struct utmp *ut)
2784 if ((fd = open (wtmp_file, O_WRONLY | O_BINARY, 0)) >= 0)
2786 locked_append (fd, ut, sizeof *ut);
2791 static int utmp_fd = -1;
2792 static bool utmp_readonly = false;
2793 static char *utmp_file = (char *) _PATH_UTMP;
2796 internal_setutent (bool force_readwrite)
2798 if (force_readwrite && utmp_readonly)
2802 utmp_fd = open (utmp_file, O_RDWR | O_BINARY);
2803 /* If open fails, we assume an unprivileged process (who?). In this
2804 case we try again for reading only unless the process calls
2805 pututline() (==force_readwrite) in which case opening just fails. */
2806 if (utmp_fd < 0 && !force_readwrite)
2808 utmp_fd = open (utmp_file, O_RDONLY | O_BINARY);
2810 utmp_readonly = true;
2814 lseek (utmp_fd, 0, SEEK_SET);
2820 internal_setutent (false);
2830 utmp_readonly = false;
2835 utmpname (const char *file)
2838 if (efault.faulted () || !*file)
2840 debug_printf ("Invalid file");
2844 utmp_file = strdup (file);
2845 debug_printf ("New UTMP file: %s", utmp_file);
2847 EXPORT_ALIAS (utmpname, utmpxname)
2849 /* Note: do not make NO_COPY */
2850 static struct utmp utmp_data_buf[16];
2851 static unsigned utix = 0;
2852 #define nutdbuf (sizeof (utmp_data_buf) / sizeof (utmp_data_buf[0]))
2853 #define utmp_data ({ \
2854 if (utix > nutdbuf) \
2856 utmp_data_buf + utix++; \
2859 static struct utmpx *
2860 copy_ut_to_utx (struct utmp *ut, struct utmpx *utx)
2864 memcpy (utx, ut, sizeof *ut);
2865 utx->ut_tv.tv_sec = ut->ut_time;
2866 utx->ut_tv.tv_usec = 0;
2870 extern "C" struct utmp *
2875 internal_setutent (false);
2880 utmp *ut = utmp_data;
2881 if (read (utmp_fd, ut, sizeof *ut) != sizeof *ut)
2886 extern "C" struct utmp *
2887 getutid (struct utmp *id)
2890 if (efault.faulted (EFAULT))
2894 internal_setutent (false);
2899 utmp *ut = utmp_data;
2900 while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
2902 switch (id->ut_type)
2908 if (id->ut_type == ut->ut_type)
2915 if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0)
2925 extern "C" struct utmp *
2926 getutline (struct utmp *line)
2929 if (efault.faulted (EFAULT))
2933 internal_setutent (false);
2938 utmp *ut = utmp_data;
2939 while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
2940 if ((ut->ut_type == LOGIN_PROCESS ||
2941 ut->ut_type == USER_PROCESS) &&
2942 !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line)))
2948 extern "C" struct utmp *
2949 pututline (struct utmp *ut)
2952 if (efault.faulted (EFAULT))
2954 internal_setutent (true);
2957 debug_printf ("error: utmp_fd %d", utmp_fd);
2960 debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n",
2961 ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id);
2962 debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n",
2963 ut->ut_user, ut->ut_host);
2966 if ((u = getutid (ut)))
2968 lseek (utmp_fd, -sizeof *ut, SEEK_CUR);
2969 write (utmp_fd, ut, sizeof *ut);
2972 locked_append (utmp_fd, ut, sizeof *ut);
2979 internal_setutent (false);
2988 extern "C" struct utmpx *
2991 static struct utmpx utx;
2992 return copy_ut_to_utx (getutent (), &utx);
2995 extern "C" struct utmpx *
2996 getutxid (const struct utmpx *id)
2998 static struct utmpx utx;
3001 if (efault.faulted (EFAULT))
3003 ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec;
3004 return copy_ut_to_utx (getutid ((struct utmp *) id), &utx);
3007 extern "C" struct utmpx *
3008 getutxline (const struct utmpx *line)
3010 static struct utmpx utx;
3013 if (efault.faulted (EFAULT))
3015 ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec;
3016 return copy_ut_to_utx (getutline ((struct utmp *) line), &utx);
3019 extern "C" struct utmpx *
3020 pututxline (const struct utmpx *utmpx)
3022 static struct utmpx utx;
3025 if (efault.faulted (EFAULT))
3027 ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3028 return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx);
3032 updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
3034 ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3035 updwtmp (wtmpx_file, (const struct utmp *) utmpx);
3039 long gethostid (void)
3041 unsigned data[13] = {0x92895012,
3055 bool has_cpuid = false;
3057 DWORD opmask = SetThreadAffinityMask (GetCurrentThread (), 1);
3059 debug_printf ("SetThreadAffinityMask to 1 failed, %E");
3061 if (!can_set_flag (0x00040000))
3062 debug_printf ("386 processor - no cpuid");
3065 debug_printf ("486 processor");
3066 if (can_set_flag (0x00200000))
3068 debug_printf ("processor supports CPUID instruction");
3072 debug_printf ("processor does not support CPUID instruction");
3076 unsigned maxf, unused[3];
3077 cpuid (&maxf, &unused[0], &unused[1], &unused[2], 0);
3082 cpuid (&data[0], &unused[0], &unused[1], &features, 1);
3083 if (features & (1 << 18))
3085 debug_printf ("processor has psn");
3088 cpuid (&unused[0], &unused[1], &data[1], &data[2], 3);
3089 debug_printf ("Processor PSN: %04x-%04x-%04x-%04x-%04x-%04x",
3090 data[0] >> 16, data[0] & 0xffff, data[2] >> 16, data[2] & 0xffff, data[1] >> 16, data[1] & 0xffff);
3094 debug_printf ("processor does not have psn");
3099 RPC_STATUS status = UuidCreateSequential (&Uuid);
3100 if (GetLastError () == ERROR_PROC_NOT_FOUND)
3101 status = UuidCreate (&Uuid);
3102 if (status == RPC_S_OK)
3104 data[4] = *(unsigned *)&Uuid.Data4[2];
3105 data[5] = *(unsigned short *)&Uuid.Data4[6];
3106 // Unfortunately Windows will sometimes pick a virtual Ethernet card
3107 // e.g. VMWare Virtual Ethernet Adaptor
3108 debug_printf ("MAC address of first Ethernet card: %02x:%02x:%02x:%02x:%02x:%02x",
3109 Uuid.Data4[2], Uuid.Data4[3], Uuid.Data4[4],
3110 Uuid.Data4[5], Uuid.Data4[6], Uuid.Data4[7]);
3114 debug_printf ("no Ethernet card installed");
3117 reg_key key (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE", "Microsoft", "Windows", "CurrentVersion", NULL);
3118 key.get_string ("ProductId", (char *)&data[6], 24, "00000-000-0000000-00000");
3119 debug_printf ("Windows Product ID: %s", (char *)&data[6]);
3121 /* Contrary to MSDN, NT4 requires the second argument
3122 or a STATUS_ACCESS_VIOLATION is generated */
3123 ULARGE_INTEGER availb;
3124 GetDiskFreeSpaceEx ("C:\\", &availb, (PULARGE_INTEGER) &data[11], NULL);
3125 if (GetLastError () == ERROR_PROC_NOT_FOUND)
3126 GetDiskFreeSpace ("C:\\", NULL, NULL, NULL, (DWORD *)&data[11]);
3128 debug_printf ("hostid entropy: %08x %08x %08x %08x "
3129 "%08x %08x %08x %08x "
3130 "%08x %08x %08x %08x "
3140 long hostid = 0x40291372;
3141 // a random hashing algorithm
3142 // dependancy on md5 is probably too costly
3143 for (int i=0;i<13;i++)
3144 hostid ^= ((data[i] << (i << 2)) | (data[i] >> (32 - (i << 2))));
3146 if (opmask && !SetThreadAffinityMask (GetCurrentThread (), opmask))
3147 debug_printf ("SetThreadAffinityMask to %p failed, %E", opmask);
3149 debug_printf ("hostid: %08x", hostid);
3154 #define ETC_SHELLS "/etc/shells"
3155 static int shell_index;
3156 static struct __sFILE64 *shell_fp;
3161 /* List of default shells if no /etc/shells exists, defined as on Linux.
3162 FIXME: SunOS has a far longer list, containing all shells which
3163 might be shipped with the OS. Should we do the same for the Cygwin
3164 distro, adding bash, tcsh, ksh, pdksh and zsh? */
3165 static NO_COPY const char *def_shells[] = {
3172 static char buf[CYG_MAX_PATH];
3175 if (!shell_fp && !(shell_fp = fopen64 (ETC_SHELLS, "rt")))
3177 if (def_shells[shell_index])
3178 return strcpy (buf, def_shells[shell_index++]);
3181 /* Skip white space characters. */
3182 while ((ch = getc (shell_fp)) != EOF && isspace (ch))
3184 /* Get each non-whitespace character as part of the shell path as long as
3187 ch != EOF && !isspace (ch) && buf_idx < CYG_MAX_PATH;
3188 buf_idx++, ch = getc (shell_fp))
3190 /* Skip any trailing non-whitespace character not fitting in buf. If the
3191 path is longer than CYG_MAX_PATH, it's invalid anyway. */
3192 while (ch != EOF && !isspace (ch))
3193 ch = getc (shell_fp);
3196 buf[buf_idx] = '\0';
3206 fseek (shell_fp, 0L, SEEK_SET);
3222 flockfile (FILE *file)
3228 ftrylockfile (FILE *file)
3230 return _ftrylockfile (file);
3234 funlockfile (FILE *file)
3236 _funlockfile (file);
3240 popen (const char *command, const char *in_type)
3242 const char *type = in_type;
3245 if (*type == 'b' || *type == 't')
3247 if ((rw != 'r' && rw != 'w') || (*type != '\0'))
3253 int fd, other_fd, __stdin, __stdout, stdwhat;
3264 other_fd = __stdout = fds[1];
3270 other_fd = __stdin = fds[0];
3274 return NULL; /* avoid a compiler warning */
3277 FILE *fp = fdopen (fd, in_type);
3278 fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
3284 const char *argv[4];
3286 argv[0] = "/bin/sh";
3293 int state = fcntl (stdwhat, F_GETFD, 0);
3294 fcntl (stdwhat, F_SETFD, state | FD_CLOEXEC);
3295 pid = spawn_guts ("/bin/sh", argv, cur_environ (), _P_NOWAIT,
3297 fcntl (stdwhat, F_SETFD, state);
3304 fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[fd];
3305 fh->set_popen_pid (pid);
3310 int save_errno = get_errno ();
3313 set_errno (save_errno);
3320 fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[fileno(fp)];
3322 if (fh->get_device () != FH_PIPEW && fh->get_device () != FH_PIPER)
3328 int pid = fh->get_popen_pid ();
3340 if (waitpid (pid, &status, 0) == pid)
3342 else if (get_errno () == EINTR)