2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
27 * $TOG: IO.C /main/33 1999/01/29 14:45:00 mgreess $
29 * RESTRICTED CONFIDENTIAL INFORMATION:
31 * The information in this document is subject to special
32 * restrictions in a confidential disclosure agreement bertween
33 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
34 * document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
35 * Sun's specific written approval. This documment and all copies
36 * and derivative works thereof must be returned or destroyed at
39 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
44 #define X_INCLUDE_TIME_H
45 #define X_INCLUDE_GRP_H
46 #define X_INCLUDE_PWD_H
47 #define XOS_USE_NO_LOCKING
48 #include <X11/Xos_r.h>
58 // START Order dependent for AIX
60 #include <sys/socket.h>
62 #include <sys/socketvar.h>
63 #if defined(BIG_ENDIAN)
67 #include <netinet/in.h>
69 #include <arpa/inet.h>
71 // END Order dependent for AIX
75 # include <sys/statvfs.h>
77 #include <sys/types.h>
83 #include <sys/mntctl.h>
84 #include <sys/statfs.h>
86 #define IOVMAX MSG_MAXIOVLEN
90 statfs(const char *, struct statfs *);
91 mntctl(int, int, char *);
92 ssize_t writev(int, const struct iovec *, int);
94 #if (OSMAJORVERSION==4) && (OSMINORVERSION==2)
95 /* Temporary hack till the /usr/lpp/xlC/include/unistd.h file is fixed. */
96 extern "C" { int lockf(int, int, off_t); }
101 extern "C" { int statvfs(const char *, struct statvfs *); }
104 #include <DtMail/DtMail.hh>
105 #include <DtMail/DtMailError.hh>
106 #include <DtMail/IO.hh>
107 #include <DtMail/Threads.hh>
109 #if !defined(IOV_MAX)
111 #include <sys/stream.h>
113 #if !defined(DEF_IOV_MAX)
114 #define DEF_IOV_MAX 16
116 #define IOV_MAX DEF_IOV_MAX
119 #define IOVEC_IOVBASE_INCREMENTOR(iov, bytes) \
120 ((caddr_t)((size_t)iov->iov_base+bytes))
122 // The following I/O routines are wrappers for the normal routines,
123 // but they deal with EINTR, and partial read/write situations.
127 SafeOpen(const char * path, int oflag, mode_t mode)
132 status = open(path, oflag, mode);
133 } while (status < 0 && errno == EINTR);
144 } while (status < 0 && errno == EINTR);
150 SafeLink(const char * existingPath, const char * newPath)
154 status = link(existingPath, newPath);
155 } while (status < 0 && errno == EINTR);
161 SafeRename(const char * oldPath, const char * newPath)
165 status = rename(oldPath, newPath);
166 } while (status < 0 && errno == EINTR);
172 SafeRemove(const char *path)
176 status = remove(path);
177 } while (status < 0 && errno == EINTR);
183 SafeUnlink(const char *path)
187 status = unlink(path);
188 } while (status < 0 && errno == EINTR);
194 SafeRead(int fd, void * buf, size_t bytes)
198 status = read(fd, buf, bytes);
199 } while(status < 0 && errno == EINTR);
205 SafeWrite(int fd, const void * buf, size_t bytes)
209 status = write(fd, buf, bytes);
210 } while(status < 0 && errno == EINTR);
215 // SafeWritev -- safe multiply vectored write
217 // SafeWritev provides an interrupt safe way to call the writev() system
218 // call. In addition, it removes the IOV_MAX limitation on the size of the
219 // iovec structure, and it will not return until either all bytes specified
220 // by the iovec structure are written or writev() returns an error.
222 // int fd -- file descriptor to write to
223 // struct iovec *iov -- iovec structure describing writes to be done
224 // int iovcnt -- number of elements in passed in iov structure
226 // Will effectively destroy the contents of the passed in iovec structure.
227 // The caller must deallocate the storage associated with the structure
228 // upon regaining control.
230 // == -1 : error returned from writev() - errno set to specific error number
231 // != -1 : number of bytes actually written to the file
234 SafeWritev(int fd, struct iovec *iov, int iovcnt)
237 unsigned long bytesWritten = 0;
239 // outer loop: starting with the first write vector, as long as there is
240 // at least one vector left to feed writev(), do so
242 for(int curIov = 0; curIov < iovcnt; ) {
244 // inner loop: feed writev() allowing for interrupted system call
249 (iovcnt-curIov) > IOV_MAX ? IOV_MAX : (iovcnt-curIov));
250 } while (status < 0 && errno == EINTR);
252 if (status == (ssize_t)-1) // true error from writev??
253 return((unsigned long)-1); // yes: bail at this point to caller
254 bytesWritten += status; // bump # bytes written count
256 // must now "walk through" the io vector until we are up the to point
257 // indicated by the number of bytes written by writev() - any leftover
258 // in status indicates a partial write of a vector
260 while ((status > 0) && (curIov < iovcnt) && (iov[curIov].iov_len <= status)) {
261 status -= iov[curIov++].iov_len;
264 // Check to see if we have reached the end of the io vector array; also
265 // check to see if more bytes were written than called for; as crazy as
266 // this sounds, in at least one instance when we finish spinning through
267 // the io vectors we still had bytes left that had been written but not
268 // accounted for in the io vectors (status > 0 && curIov >= iovcnt)
270 if (curIov >= iovcnt) { // out of IO vectors?
271 if (status > 0) { // yes: all data accounted for?
272 DtMailEnv error; // NO:: log error condition
275 "SafeWritev: writev(): too many bytes written (%d/%d)\n",
276 status, bytesWritten);
278 continue; // continue and let for loop exit
281 // Check for a partial write: if the current vector contains more data
282 // than what has been written, writev() bailed in the middle of writing
283 // a vector - adjust the vector and and feed it back to writev() again
284 // OTHERWISE writev() ended with the current vector so move on to the next
286 if (iov[curIov].iov_len == status) // full write of this vector?
287 curIov++; // yes: move on to the next vector
288 else if (status != 0) { // no: adjust this vector and retry
289 iov[curIov].iov_len -= status;
290 iov[curIov].iov_base = IOVEC_IOVBASE_INCREMENTOR((&iov[curIov]), status);
293 return(bytesWritten);
296 #define SWS_BUFFERSIZE 1024
298 SafeWriteStrip(int fd, const void * buf, size_t bytes)
302 char *ptr = (char*)buf, *writebuf;
304 // bug 5856: dont write out control M
305 // make a finite size buffer for writing
306 writebuf = (char*) malloc(bytes < SWS_BUFFERSIZE ? bytes : SWS_BUFFERSIZE);
308 for (i = 0, j = 0; i < bytes; i++, ptr++) {
309 if (*ptr == '
\r' && *(ptr+1) == '\n')
311 writebuf[j++] = *ptr;
312 if (j == SWS_BUFFERSIZE || i == (bytes-1)) {
314 status = write(fd, writebuf, j);
315 } while(status < 0 && errno == EINTR);
325 SafeStat(const char * path, struct stat * buf)
329 status = stat(path, buf);
330 } while (status < 0 && errno == EINTR);
336 SafeFchown(int fd, uid_t owner, gid_t group)
340 status = fchown(fd, owner, group);
341 } while (status < 0 && errno == EINTR);
347 SafeLStat(const char * path, struct stat * buf)
351 status = lstat(path, buf);
352 } while (status < 0 && errno == EINTR);
358 SafeFStat(int fd, struct stat * buf)
362 status = fstat(fd, buf);
363 } while (status < 0 && errno == EINTR);
368 // SafeGuaranteedStat - return stat info for object given path name
369 // If NFS attribute caching is enabled (which is the default), a
370 // stat/fstat of a NFS file may not return the correct true size of the
371 // mailbox if it has been appended to since the last time it was read.
372 // To get around this problem, this function will perform a open(),
373 // read() of 1 byte, fstat(), close() which will force the attributes
374 // for the named file to be retrieved directly from the server.
377 SafeGuaranteedStat(const char * path, struct stat * buf)
382 int tempFd = SafeOpen(path, O_RDONLY|O_SYNC);
384 int tempFd = SafeOpen(path, O_RDONLY|O_RSYNC|O_SYNC);
392 if (SafeRead(tempFd, &tempBuf, 1) == -1) {
394 (void) SafeClose(tempFd);
399 if (SafeFStat(tempFd, buf) == -1) {
401 (void) SafeClose(tempFd);
406 (void) SafeClose(tempFd);
412 SafeTruncate(const char * path, off_t len)
416 status = truncate((char *)path, len); // The cast is for AIX
417 } while (status < 0 && errno == EINTR);
423 SafeFTruncate(int fd, off_t len)
427 status = ftruncate(fd, len);
428 } while (status < 0 && errno == EINTR);
434 SafeAccess(const char * path, int amode)
438 status = access(path, amode);
439 } while (status < 0 && errno == EINTR);
445 #define LOCKF_SIZE_TYPE long
447 #define LOCKF_SIZE_TYPE off_t
451 SafeLockf(int fd, int func, long size)
455 status = lockf(fd, func, (LOCKF_SIZE_TYPE) size);
456 } while (status < 0 && errno == EINTR);
462 SafeFChmod(int fd, mode_t mode)
466 status = fchmod(fd, mode);
467 } while (status < 0 && errno == EINTR);
473 SafeDup2(int fd1, int fd2)
477 status = dup2(fd1, fd2);
478 } while (status < 0 && errno == EINTR);
484 SafeExecvp(const char * file, char *const *argv)
489 status = execvp(file, (char * const *)argv);
491 } while (status < 0 && errno == EINTR);
497 SafeWaitpid(pid_t proc, int * p_stat, int options)
501 status = waitpid(proc, p_stat, options);
502 } while (status < 0 && errno == EINTR);
508 SafeWait(int * p_stat)
512 status = wait(p_stat);
513 } while (status < 0 && errno == EINTR);
519 SafeUTime(const char * path, utimbuf * ntime)
523 status = utime(path, ntime);
524 } while (status < 0 && errno == EINTR);
530 SafePathIsAccessible(DtMailEnv &error, const char *path)
534 status = SafeAccess(path, F_OK);
538 error.vSetError(DTME_PathElementPermissions, DTM_FALSE, NULL, path);
539 else if (ENOTDIR == errno)
540 error.vSetError(DTME_PathElementNotDirectory, DTM_FALSE, NULL, path);
541 else if (ENOENT == errno)
550 status = SafeAccess(t, F_OK);
553 DTME_PathElementDoesNotExist,
561 #if defined(POSIX_THREADS)
562 static void * time_mutex = NULL;
566 SafeCtime(const time_t *clock, char * buf, int buflen)
568 _Xctimeparams ctime_buf;
571 memset((void*) &ctime_buf, 0, sizeof(_Xctimeparams));
572 result = _XCtime(clock, ctime_buf);
574 strncpy(buf, result, buflen);
580 SafeLocaltime(const time_t *clock, tm & result)
583 _Xltimeparams localtime_buf;
585 memset((void*) &localtime_buf, 0, sizeof(_Xltimeparams));
586 time_ptr = _XLocaltime(clock, localtime_buf);
591 SafeMktime(tm * timeptr)
593 #if defined(POSIX_THREADS)
596 time_mutex = MutexInit();
599 MutexLock lock_scope(time_mutex);
602 return(mktime(timeptr));
606 SafeStrftime(char * buf, size_t buf_size,
607 const char * format, const tm * timeptr)
609 #if defined(POSIX_THREADS)
612 time_mutex = MutexInit();
615 MutexLock lock_scope(time_mutex);
618 return(strftime(buf, buf_size, format, timeptr));
621 #define SockINTERNAL_BUFSIZE 2048
623 void *SockOpen(char *host, int clientPort, char **errorstring)
629 unsigned long inaddr;
631 struct sockaddr_in ad;
634 char *errorfmt = NULL;
636 memset(&ad, 0, sizeof(ad));
637 ad.sin_family = AF_INET;
639 inaddr = inet_addr(host);
641 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
644 hp = gethostbyname(host);
647 if (NULL != errorstring)
649 errorfmt = DtMailEnv::getMessageText(
652 if (NULL == *errorstring) *errorstring = (char*) malloc(BUFSIZ);
653 sprintf(*errorstring, errorfmt, host);
657 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
659 ad.sin_port = htons(clientPort);
661 sockfd = socket(AF_INET, SOCK_STREAM, 0);
664 if (NULL != errorstring)
666 errorfmt = DtMailEnv::getMessageText(
668 "Error creating socket: %s");
669 if (NULL == *errorstring) *errorstring = (char*) malloc(BUFSIZ);
670 sprintf(*errorstring, errorfmt, error.errnoMessage());
674 if (connect(sockfd, (struct sockaddr *) &ad, sizeof(ad)) < 0)
676 if (NULL != errorstring)
678 errorfmt = DtMailEnv::getMessageText(
680 "Error connecting to socket: %s");
681 if (NULL == *errorstring) *errorstring = (char*) malloc(BUFSIZ);
682 sprintf(*errorstring, errorfmt, error.errnoMessage());
688 #if defined(USE_SOCKSTREAM)
689 FILE *sockfp = fdopen(sockfd, "r+");
690 setvbuf(sockfp, NULL, _IONBF, SockINTERNAL_BUFSIZE);
691 return (void*) sockfp;
693 return (void*) sockfd;
697 int SockPrintf(void *sockfp, char* format, ...)
700 char *buf = new char[8192];
703 va_start(ap, format);
704 vsprintf(buf, format, ap);
706 i = SockWrite(buf, 1, strlen(buf), sockfp);
711 char *SockGets(char *buf, int len, void *sockfp)
713 #if defined(USE_SOCKSTREAM)
714 char *in = fgets(buf, len, (FILE*) sockfp);
715 fseek((FILE*) sockfp, 0L, SEEK_CUR); /* required by POSIX */
726 read((int) sockfp, (void*) bufp, 1);
728 } while (*bufp != '\n');
734 int SockRead(char *buf, int size, int len, void *sockfp)
736 #if defined(USE_SOCKSTREAM)
737 int n = fread(buf, size, len, (FILE*) sockfp);
738 fseek((FILE*) sockfp, 0L, SEEK_CUR); /* required by POSIX */
740 int n = (int) read((int) sockfp, (void*) buf, (size_t) size * len);
745 int SockWrite(char *buf, int size, int len, void *sockfp)
749 #if defined(USE_SOCKSTREAM)
750 n = fwrite(buf, size, len, (FILE*) sockfp);
751 fseek((FILE*) sockfp, 0L, SEEK_CUR); /* required by POSIX */
753 n = write((int) sockfp, buf, size * len);
759 void SockClose(void *sockfp)
761 #if defined(USE_SOCKSTREAM)
762 fclose((FILE*) sockfp);
769 GetGroupName(char * grp_name)
772 _Xgetgrparams grp_buf;
774 memset((void*) &grp_buf, 0, sizeof(_Xgetgrparams));
775 grp = _XGetgrgid(getegid(), grp_buf);
778 strcpy(grp_name, grp->gr_name);
781 strcpy(grp_name, "UNKNOWN_GROUP");
787 GetIdForGroupName(char * grp_name)
789 assert(grp_name != NULL);
791 _Xgetgrparams grp_buf;
793 memset((void*) &grp_buf, 0, sizeof(_Xgetgrparams));
794 grp = _XGetgrnam(grp_name, grp_buf);
796 return(grp ? grp->gr_gid : (gid_t)-1);
800 GetPasswordEntry(passwd & result)
802 static struct passwd passwordEntry;
803 static int oneTimeFlag = 0;
806 _Xgetpwparams pw_buf;
807 struct passwd *tresult;
809 memset((void*) &pw_buf, 0, sizeof(_Xgetpwparams));
812 tresult = getpwuid(getuid());
815 tresult = _XGetpwuid(getuid(), pw_buf);
818 assert(tresult != NULL);
819 memcpy(&passwordEntry, tresult, sizeof(struct passwd));
820 passwordEntry.pw_name = strdup(passwordEntry.pw_name);
821 passwordEntry.pw_passwd = strdup(passwordEntry.pw_passwd);
822 #if !defined(_AIX) && !defined(linux)
824 passwordEntry.pw_age = strdup(passwordEntry.pw_age);
826 passwordEntry.pw_comment = strdup(passwordEntry.pw_comment);
828 passwordEntry.pw_gecos = strdup(passwordEntry.pw_gecos);
829 passwordEntry.pw_dir = strdup(passwordEntry.pw_dir);
830 passwordEntry.pw_shell = strdup(passwordEntry.pw_shell);
834 memcpy(&result, &passwordEntry, sizeof(struct passwd));
837 #if defined(MAILGROUP_REQUIRED)
838 int isSetMailGidNeeded(const char * mailboxPath)
843 char inbox_path[1024];
844 char mbox_path[1024];
848 _Xgetpwparams pw_buf;
850 memset((void*) &pw_buf, 0, sizeof(_Xgetpwparams));
851 pw = _XGetpwuid(getuid(), pw_buf);
853 // construct the lockfile name for the user.
854 char *lock_file = (char *)calloc(1,strlen(pw->pw_name) + 6);
855 strcpy(lock_file,pw->pw_name);
856 strcat(lock_file,".lock");
858 // parse the mailfolder name from the path
859 char *p = strrchr(mailboxPath,'/');
860 int len = (NULL!=0) ? strlen(mailboxPath)-strlen(p) : strlen(mailboxPath);
861 char *str = (char *) calloc(1, len+1);
862 strncpy(str, mailboxPath, len);
867 // Default or system mailbox dir name.
868 strcpy(inbox_path, "/var/spool/mail");
869 stat(inbox_path,&buf1);
872 if( ( (buf.st_dev == buf1.st_dev) && (buf.st_ino == buf1.st_ino) ) )
874 if( !strcmp((p+1),pw->pw_name) || !strcmp((p+1),lock_file) )
876 if( access(mailboxPath,R_OK) == -1 )
898 * gather mount status for all virtual mounts for this host.
900 * EXECUTION ENVIRONMENT: Part of user command.
903 * vmountpp pointer to a buffer in which to put mount info
906 * get_stat() was lifted and slightly modified from
907 * AIX Version 3 df.c.
910 * < 0 error in mntctl()
911 * > 0 for number of struct vmounts (mount points) in
912 * buffer which is pointed to by pointer left at
916 struct vmount **vmountpp) /* place to tell where buffer is */
919 register struct vmount *vm;
923 size = BUFSIZ; /* initial default size */
924 count = 10; /* don't try forever */
926 while (count--) { /* don't try it forever */
927 if ((vm = (struct vmount*) malloc(size)) == NULL) {
932 * perform the QUERY mntctl - if it returns > 0, that is the
933 * number of vmount structures in the buffer. If it returns
934 * -1, an error occured. If it returned 0, then look in
935 * first word of buffer for needed size.
937 if ((nmounts = mntctl(MCTL_QUERY, size, (caddr_t)vm)) > 0) {
938 *vmountpp = vm; /* OK, got it, now return */
942 size = *(int *)vm; /* the buffer wasn't big enough */
943 free((void *)vm); /* get required buffer size */
945 free((void *)vm);/* some other kind of error occurred*/
957 * Determines, via the filesystems vmount structures,
958 * the vmount id of the the filesystem id provided as
959 * an argument (enables ultimate access to the actual
960 * name of the filesystem).
962 * EXECUTION ENVIRONMENT: Part of user command.
965 * ptr to structure with vmount id of filesystem or NULL
967 struct vmount *get_vmount(fsid_t *fsid)
969 struct vmount *inu_vmount_p=NULL;
971 register struct vmount *vm;
974 /* make sure we have all the virtual mount status of this host */
975 if(inu_vmount_p == NULL)
976 inu_vmount_num = get_stat(&inu_vmount_p);
978 /* get the number of struct vmount in the vmount buffer */
979 nmount = inu_vmount_num;
981 /* go thru all the structures in the vmount buffer */
982 for (vm = inu_vmount_p; nmount; nmount--,
983 vm = (struct vmount *)((char *)vm + vm->vmt_length)) {
984 if(( vm->vmt_fsid.fsid_dev == fsid->fsid_dev ) &&
985 ( vm->vmt_fsid.fsid_type == fsid->fsid_type ))
988 return((struct vmount *)NULL);
992 int FileSystemSpace(const char *file_path, size_t bytes, char **fsname)
995 struct stat stat_buf;
996 size_t req_space = 0;
998 struct statvfs statvfs_buf;
1001 if (stat(file_path,&stat_buf) < 0) return 0;
1003 if (statvfs(file_path,&statvfs_buf) < 0) return 0;
1007 struct statfs statfs_buf;
1009 if (statfs(file_path,&statfs_buf) < 0) return 0;
1010 if (statfs_buf.f_vfstype == MNT_NFS)
1013 vm = get_vmount(&(statfs_buf.f_fsid));
1014 strcpy (statfs_buf.f_fname, vmt2dataptr (vm, VMT_STUB));
1021 // The following code became redundant as the writeMailBox method now
1022 // checks for No space from the SafeWritev call.
1025 // This check does not work (HP, IBM, Sun return -1; DEC returns 0)
1026 // Since the calling code has already created the file and is only
1027 // check that there is enough space, we don't need to check that
1028 // there are enough inodes.
1030 // special case where the filesystem is out of inodes.
1031 if(statvfs_buf.f_ffree < 10) fserror = TRUE;
1036 req_space = (size_t) ((bytes > stat_buf.st_size) ?
1037 (bytes-stat_buf.st_size) :
1040 if ( (statvfs_buf.f_bfree*statvfs_buf.f_bsize) >
1041 (req_space + statvfs_buf.f_bsize) )
1048 else fserror = TRUE;
1053 *fsname = (char*) calloc(1, strlen(statfs_buf.f_fname)+1);
1054 strcpy (*fsname, statfs_buf.f_fname);
1056 *fsname = (char*) calloc(1, strlen(file_path)+1);
1057 strcpy (*fsname, file_path);