Forward compatibility: flex
[foam-extend-3.2.git] / src / OSspecific / POSIX / POSIX.C
blobabc3eea8b891db0f7d7bf003cf3d9e2b4c02e87b
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 Description
25     POSIX versions of the functions declared in OSspecific.H
27 \*---------------------------------------------------------------------------*/
29 #ifdef solarisGcc
30 # define _SYS_VNODE_H
31 #endif
33 #include "OSspecific.H"
34 #include "POSIX.H"
35 #include "foamVersion.H"
36 #include "fileName.H"
37 #include "fileStat.H"
38 #include "timer.H"
40 #include <fstream>
41 #include <cstdlib>
42 #include <cctype>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <dirent.h>
47 #include <pwd.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/socket.h>
52 #include <netdb.h>
54 #include <netinet/in.h>
56 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
58 defineTypeNameAndDebug(Foam::POSIX, 0);
60 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
62 pid_t Foam::pid()
64     return getpid();
67 pid_t Foam::ppid()
69     return getppid();
72 pid_t Foam::pgid()
74     return getpgrp();
77 bool Foam::env(const word& envName)
79     return getenv(envName.c_str()) != NULL;
83 Foam::string Foam::getEnv(const word& envName)
85     char* env = getenv(envName.c_str());
87     if (env)
88     {
89         return string(env);
90     }
91     else
92     {
93         // Return null-constructed string rather than string::null
94         // to avoid cyclic dependencies in the construction of globals
95         return string();
96     }
100 bool Foam::setEnv
102     const word& envName,
103     const string& value,
104     const bool overwrite
107     return setenv(envName.c_str(), value.c_str(), overwrite) == 0;
111 Foam::word Foam::hostName()
113     char buffer[256];
114     gethostname(buffer, 256);
116     return buffer;
120 Foam::word Foam::userName()
122     struct passwd* pw = getpwuid(getuid());
124     if (pw != NULL)
125     {
126         return pw->pw_name;
127     }
128     else
129     {
130         return word::null;
131     }
135 // use $HOME environment variable or passwd info
136 Foam::fileName Foam::home()
138     char* env = getenv("HOME");
140     if (env != NULL)
141     {
142         return fileName(env);
143     }
144     else
145     {
146         struct passwd* pw = getpwuid(getuid());
148         if (pw != NULL)
149         {
150             return pw->pw_dir;
151         }
152         else
153         {
154             return fileName::null;
155         }
156     }
160 Foam::fileName Foam::home(const word& userName)
162     struct passwd* pw;
164     if (userName.size())
165     {
166         pw = getpwnam(userName.c_str());
167     }
168     else
169     {
170         char* env = getenv("HOME");
172         if (env != NULL)
173         {
174             return fileName(env);
175         }
177         pw = getpwuid(getuid());
178     }
180     if (pw != NULL)
181     {
182         return pw->pw_dir;
183     }
184     else
185     {
186         return fileName::null;
187     }
191 Foam::fileName Foam::cwd()
193     char buf[255];
194     if (getcwd(buf, 255))
195     {
196         return buf;
197     }
198     else
199     {
200         FatalErrorIn("Foam::cwd()")
201             << "Couldn't get the current working directory"
202             << exit(FatalError);
204         return fileName::null;
205     }
209 bool Foam::chDir(const fileName& dir)
211     return chdir(dir.c_str()) != 0;
215 Foam::fileName Foam::findEtcFile(const fileName& name, bool mandatory)
217     // Search user files: deprecated.  HJ, 11/Dec/2013
219     // Search site files:
220     fileName searchDir = getEnv("WM_PROJECT_INST_DIR");
221     if (isDir(searchDir))
222     {
223         // Check for site file in $WM_PROJECT_INST_DIR/site/VERSION
224         fileName fullName = searchDir/"site"/FOAMversion/name;
225         if (isFile(fullName))
226         {
227             return fullName;
228         }
230         // Check for version-independent site file in $WM_PROJECT_INST_DIR/site
231         fullName = searchDir/"site"/name;
232         if (isFile(fullName))
233         {
234             return fullName;
235         }
236     }
238     // Search installation files:
239     searchDir = getEnv("WM_PROJECT_DIR");
240     if (isDir(searchDir))
241     {
242         // Check for shipped FOAM file in $WM_PROJECT_DIR/etc
243         fileName fullName = searchDir/"etc"/name;
244         if (isFile(fullName))
245         {
246             return fullName;
247         }
248     }
250     // Not found
251     // abort if the file is mandatory, otherwise return null
252     if (mandatory)
253     {
254         cerr<< "--> FOAM FATAL ERROR in Foam::findEtcFile() :"
255                " could not find mandatory file\n    '"
256             << name.c_str() << "'\n\n" << std::endl;
257         ::exit(1);
258     }
260     // Return null-constructed fileName rather than fileName::null
261     // to avoid cyclic dependencies in the construction of globals
262     return fileName();
266 bool Foam::mkDir(const fileName& pathName, mode_t mode)
268     // empty names are meaningless
269     if (pathName.empty())
270     {
271         return false;
272     }
274     // Construct instance path directory if does not exist
275     if (::mkdir(pathName.c_str(), mode) == 0)
276     {
277         // Directory made OK so return true
278         return true;
279     }
280     else
281     {
282         switch (errno)
283         {
284             case EPERM:
285             {
286                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
287                     << "The filesystem containing " << pathName
288                     << " does not support the creation of directories."
289                     << exit(FatalError);
291                 return false;
292             }
294             case EEXIST:
295             {
296                 // Directory already exists so simply return true
297                 return true;
298             }
300             case EFAULT:
301             {
302                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
303                     << "" << pathName
304                     << " points outside your accessible address space."
305                     << exit(FatalError);
307                 return false;
308             }
310             case EACCES:
311             {
312                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
313                     << "The parent directory does not allow write "
314                        "permission to the process,"<< nl
315                     << "or one of the directories in " << pathName
316                     << " did not allow search (execute) permission."
317                     << exit(FatalError);
319                 return false;
320             }
322             case ENAMETOOLONG:
323             {
324                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
325                     << "" << pathName << " is too long."
326                     << exit(FatalError);
328                 return false;
329             }
331             case ENOENT:
332             {
333                 // Part of the path does not exist so try to create it
334                 if (pathName.path().size() && mkDir(pathName.path(), mode))
335                 {
336                     return mkDir(pathName, mode);
337                 }
338                 else
339                 {
340                     FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
341                         << "Couldn't create directory " << pathName
342                         << exit(FatalError);
344                     return false;
345                 }
346             }
348             case ENOTDIR:
349             {
350                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
351                     << "A component used as a directory in " << pathName
352                     << " is not, in fact, a directory."
353                     << exit(FatalError);
355                 return false;
356             }
358             case ENOMEM:
359             {
360                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
361                     << "Insufficient kernel memory was available to make "
362                        "directory " << pathName << '.'
363                     << exit(FatalError);
365                 return false;
366             }
368             case EROFS:
369             {
370                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
371                     << "" << pathName
372                     << " refers to a file on a read-only filesystem."
373                     << exit(FatalError);
375                 return false;
376             }
378             case ELOOP:
379             {
380                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
381                     << "Too many symbolic links were encountered in resolving "
382                     << pathName << '.'
383                     << exit(FatalError);
385                 return false;
386             }
388             case ENOSPC:
389             {
390                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
391                     << "The device containing " << pathName
392                     << " has no room for the new directory or "
393                     << "the user's disk quota is exhausted."
394                     << exit(FatalError);
396                 return false;
397             }
399             default:
400             {
401                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
402                     << "Couldn't create directory " << pathName
403                     << exit(FatalError);
405                 return false;
406             }
407         }
408     }
412 // Set the file mode
413 bool Foam::chMod(const fileName& name, const mode_t m)
415     return ::chmod(name.c_str(), m) == 0;
419 // Return the file mode
420 mode_t Foam::mode(const fileName& name)
422     fileStat fileStatus(name);
423     if (fileStatus.isValid())
424     {
425         return fileStatus.status().st_mode;
426     }
427     else
428     {
429         return 0;
430     }
434 // Return the file type: FILE or DIRECTORY
435 Foam::fileName::Type Foam::type(const fileName& name)
437     mode_t m = mode(name);
439     if (S_ISREG(m))
440     {
441         return fileName::FILE;
442     }
443     else if (S_ISDIR(m))
444     {
445         return fileName::DIRECTORY;
446     }
447     else
448     {
449         return fileName::UNDEFINED;
450     }
454 // Does the name exist in the filing system?
455 bool Foam::exists(const fileName& name, const bool checkGzip)
457     return mode(name) || isFile(name, checkGzip);
461 // Does the directory exist?
462 bool Foam::isDir(const fileName& name)
464     return S_ISDIR(mode(name));
468 // Does the file exist?
469 bool Foam::isFile(const fileName& name, const bool checkGzip)
471     return S_ISREG(mode(name)) || (checkGzip && S_ISREG(mode(name + ".gz")));
475 // Return size of file
476 off_t Foam::fileSize(const fileName& name)
478     fileStat fileStatus(name);
479     if (fileStatus.isValid())
480     {
481         return fileStatus.status().st_size;
482     }
483     else
484     {
485         return -1;
486     }
490 // Return time of last file modification
491 time_t Foam::lastModified(const fileName& name)
493     fileStat fileStatus(name);
494     if (fileStatus.isValid())
495     {
496         return fileStatus.status().st_mtime;
497     }
498     else
499     {
500         return 0;
501     }
505 // Read a directory and return the entries as a string list
506 Foam::fileNameList Foam::readDir
508     const fileName& directory,
509     const fileName::Type type,
510     const bool filtergz
513     // Initial filename list size
514     // also used as increment if initial size found to be insufficient
515     static const int maxNnames = 100;
517     if (POSIX::debug)
518     {
519         Info<< "readDir(const fileName&, const fileType, const bool filtergz)"
520             << " : reading directory " << directory << endl;
521     }
523     // Setup empty string list MAXTVALUES long
524     fileNameList dirEntries(maxNnames);
526     // Pointers to the directory entries
527     DIR *source;
528     struct dirent *list;
530     // Temporary variables and counters
531     label nEntries = 0;
533     // Attempt to open directory and set the structure pointer
534     if ((source = opendir(directory.c_str())) == NULL)
535     {
536         dirEntries.setSize(0);
538         if (POSIX::debug)
539         {
540             Info<< "readDir(const fileName&, const fileType, "
541                    "const bool filtergz) : cannot open directory "
542                 << directory << endl;
543         }
544     }
545     else
546     {
547         // Read and parse all the entries in the directory
548         while ((list = readdir(source)) != NULL)
549         {
550             fileName fName(list->d_name);
552             // Ignore files begining with ., i.e. '.', '..' and '.*'
553             if (fName.size() && fName[0] != '.')
554             {
555                 word fExt = fName.ext();
557                 if
558                 (
559                     (type == fileName::DIRECTORY)
560                  ||
561                     (
562                         type == fileName::FILE
563                      && fName[fName.size() - 1] != '~'
564                      && fExt != "vtk"
565                      && fExt != "bak"
566                      && fExt != "BAK"
567                      && fExt != "old"
568                      && fExt != "save"
569                     )
570                 )
571                 {
572                     if ((directory/fName).type() == type)
573                     {
574                         if (nEntries >= dirEntries.size())
575                         {
576                             dirEntries.setSize(dirEntries.size() + maxNnames);
577                         }
579                         if (filtergz && fExt == "gz")
580                         {
581                             dirEntries[nEntries++] = fName.lessExt();
582                         }
583                         else
584                         {
585                             dirEntries[nEntries++] = fName;
586                         }
587                     }
588                 }
589             }
590         }
592         // Reset the length of the entries list
593         dirEntries.setSize(nEntries);
595         closedir(source);
596     }
598     return dirEntries;
602 // Copy, recursively if necessary, the source to the destination
603 bool Foam::cp(const fileName& src, const fileName& dest)
605     // Make sure source exists.
606     if (!exists(src))
607     {
608         return false;
609     }
611     fileName destFile(dest);
613     // Check type of source file.
614     if (src.type() == fileName::FILE)
615     {
616         // If dest is a directory, create the destination file name.
617         if (destFile.type() == fileName::DIRECTORY)
618         {
619             destFile = destFile/src.name();
620         }
622         // Make sure the destination directory exists.
623         if (!isDir(destFile.path()) && !mkDir(destFile.path()))
624         {
625             return false;
626         }
628         // Open and check streams.
629         std::ifstream srcStream(src.c_str());
630         if (!srcStream)
631         {
632             return false;
633         }
635         std::ofstream destStream(destFile.c_str());
636         if (!destStream)
637         {
638             return false;
639         }
641         // Copy character data.
642         char ch;
643         while (srcStream.get(ch))
644         {
645             destStream.put(ch);
646         }
648         // Final check.
649         if (!srcStream.eof() || !destStream)
650         {
651             return false;
652         }
653     }
654     else if (src.type() == fileName::DIRECTORY)
655     {
656         // If dest is a directory, create the destination file name.
657         if (destFile.type() == fileName::DIRECTORY)
658         {
659             destFile = destFile/src.component(src.components().size() -1);
660         }
662         // Make sure the destination directory exists.
663         if (!isDir(destFile) && !mkDir(destFile))
664         {
665             return false;
666         }
668         // Copy files
669         fileNameList contents = readDir(src, fileName::FILE, false);
670         forAll(contents, i)
671         {
672             if (POSIX::debug)
673             {
674                 Info<< "Copying : " << src/contents[i]
675                     << " to " << destFile/contents[i] << endl;
676             }
678             // File to file.
679             cp(src/contents[i], destFile/contents[i]);
680         }
682         // Copy sub directories.
683         fileNameList subdirs = readDir(src, fileName::DIRECTORY);
684         forAll(subdirs, i)
685         {
686             if (POSIX::debug)
687             {
688                 Info<< "Copying : " << src/subdirs[i]
689                     << " to " << destFile << endl;
690             }
692             // Dir to Dir.
693             cp(src/subdirs[i], destFile);
694         }
695     }
697     return true;
701 // Create a softlink. dst should not exist. Returns true if successful.
702 bool Foam::ln(const fileName& src, const fileName& dst)
704     if (POSIX::debug)
705     {
706         Info<< "Create softlink from : " << src << " to " << dst
707             << endl;
708     }
710     if (exists(dst))
711     {
712         WarningIn("ln(const fileName&, const fileName&)")
713             << "destination " << dst << " already exists. Not linking."
714             << endl;
715         return false;
716     }
718     if (!exists(src))
719     {
720         WarningIn("ln(const fileName&, const fileName&)")
721             << "source " << src << " does not exist." << endl;
722         return false;
723     }
725     if (symlink(src.c_str(), dst.c_str()) == 0)
726     {
727         return true;
728     }
729     else
730     {
731         WarningIn("ln(const fileName&, const fileName&)")
732             << "symlink from " << src << " to " << dst << " failed." << endl;
733         return false;
734     }
738 // Rename srcFile dstFile
739 bool Foam::mv(const fileName& src, const fileName& dst)
741     if (POSIX::debug)
742     {
743         Info<< "Move : " << src << " to " << dst << endl;
744     }
746     if
747     (
748         dst.type() == fileName::DIRECTORY
749      && src.type() != fileName::DIRECTORY
750     )
751     {
752         const fileName dstName(dst/src.name());
754         return rename(src.c_str(), dstName.c_str()) == 0;
755     }
756     else
757     {
758         return rename(src.c_str(), dst.c_str()) == 0;
759     }
763 //- Rename to a corresponding backup file
764 //  If the backup file already exists, attempt with "01" .. "99" index
765 bool Foam::mvBak(const fileName& src, const std::string& ext)
767     if (POSIX::debug)
768     {
769         Info<< "mvBak : " << src << " to extension " << ext << endl;
770     }
772     if (exists(src, false))
773     {
774         const int maxIndex = 99;
775         char index[3];
777         for (int n = 0; n <= maxIndex; n++)
778         {
779             fileName dstName(src + "." + ext);
780             if (n)
781             {
782                 sprintf(index, "%02d", n);
783                 dstName += index;
784             }
786             // avoid overwriting existing files, except for the last
787             // possible index where we have no choice
788             if (!exists(dstName, false) || n == maxIndex)
789             {
790                 return rename(src.c_str(), dstName.c_str()) == 0;
791             }
793         }
794     }
796     // fall-through: nothing to do
797     return false;
802 // Remove a file, returning true if successful otherwise false
803 bool Foam::rm(const fileName& file)
805     if (POSIX::debug)
806     {
807         Info<< "Removing : " << file << endl;
808     }
810     // Try returning plain file name; if not there, try with .gz
811     if (remove(file.c_str()) == 0)
812     {
813         return true;
814     }
815     else
816     {
817         return remove(string(file + ".gz").c_str()) == 0;
818     }
822 // Remove a dirctory and its contents
823 bool Foam::rmDir(const fileName& directory)
825     if (POSIX::debug)
826     {
827         Info<< "rmDir(const fileName&) : "
828             << "removing directory " << directory << endl;
829     }
831     // Pointers to the directory entries
832     DIR *source;
833     struct dirent *list;
835     // Attempt to open directory and set the structure pointer
836     if ((source = opendir(directory.c_str())) == NULL)
837     {
838         WarningIn("rmDir(const fileName&)")
839             << "cannot open directory " << directory << endl;
841         return false;
842     }
843     else
844     {
845         // Read and parse all the entries in the directory
846         while ((list = readdir(source)) != NULL)
847         {
848             fileName fName(list->d_name);
850             if (fName != "." && fName != "..")
851             {
852                 fileName path = directory/fName;
854                 if (path.type() == fileName::DIRECTORY)
855                 {
856                     if (!rmDir(path))
857                     {
858                         WarningIn("rmDir(const fileName&)")
859                             << "failed to remove directory " << fName
860                             << " while removing directory " << directory
861                             << endl;
863                         closedir(source);
865                         return false;
866                     }
867                 }
868                 else
869                 {
870                     if (!rm(path))
871                     {
872                         WarningIn("rmDir(const fileName&)")
873                             << "failed to remove file " << fName
874                             << " while removing directory " << directory
875                             << endl;
877                         closedir(source);
879                         return false;
880                     }
881                 }
882             }
884         }
886         if (!rm(directory))
887         {
888             WarningIn("rmDir(const fileName&)")
889                 << "failed to remove directory " << directory << endl;
891             closedir(source);
893             return false;
894         }
896         closedir(source);
898         return true;
899     }
903 unsigned int Foam::sleep(const unsigned int s)
905     return ::sleep(s);
909 void Foam::fdClose(const int fd)
911     if (close(fd) != 0)
912     {
913         FatalErrorIn
914         (
915             "fdClose(const int fd)"
916         )   << "close error on " << fd << endl
917             << abort(FatalError);
918     }
922 bool Foam::ping
924     const word& destName,
925     const label destPort,
926     const label timeOut
929     char *serverAddress;
930     struct in_addr *ptr;
931     struct hostent *hostPtr;
932     volatile int sockfd;
933     struct sockaddr_in destAddr;      // will hold the destination addr
934     u_int addr;
936     if ((hostPtr = gethostbyname(destName.c_str())) == NULL)
937     {
938         FatalErrorIn
939         (
940             "Foam::ping(const word&, const label)"
941         )   << "gethostbyname error " << h_errno << " for host " << destName
942             << abort(FatalError);
943     }
945     // Get first of the SLL of addresses
946     serverAddress = *(hostPtr->h_addr_list);
947     ptr = reinterpret_cast<struct in_addr*>(serverAddress);
948     addr = ptr->s_addr;
950     // Allocate socket
951     sockfd = socket(AF_INET, SOCK_STREAM, 0);
952     if (sockfd < 0)
953     {
954         FatalErrorIn
955         (
956             "Foam::ping(const word&, const label)"
957         )   << "socket error"
958             << abort(FatalError);
959     }
961     // Fill sockaddr_in structure with dest address and port
962     memset (reinterpret_cast<char *>(&destAddr), '\0', sizeof(destAddr));
963     destAddr.sin_family = AF_INET;
964     destAddr.sin_port = htons(ushort(destPort));
965     destAddr.sin_addr.s_addr = addr;
968     timer myTimer(timeOut);
970     if (timedOut(myTimer))
971     {
972         // Setjmp from timer jumps back to here
973         fdClose(sockfd);
974         return false;
975     }
977     if
978     (
979         connect
980         (
981             sockfd,
982             reinterpret_cast<struct sockaddr*>(&destAddr),
983             sizeof(struct sockaddr)
984         ) != 0
985     )
986     {
987         // Connection refused. Check if network was actually used or not.
989         int connectErr = errno;
991         fdClose(sockfd);
993         if (connectErr == ECONNREFUSED)
994         {
995             return true;
996         }
997         //perror("connect");
999         return false;
1000     }
1002     fdClose(sockfd);
1004     return true;
1008 bool Foam::ping(const word& hostname, const label timeOut)
1010     return ping(hostname, 222, timeOut) || ping(hostname, 22, timeOut);
1014 int Foam::system(const string& command)
1016     return ::system(command.c_str());
1020 void Foam::osRandomSeed(const label seed)
1022 #ifdef USE_RANDOM
1023     srandom((unsigned int)seed);
1024 #else
1025     srand48(seed);
1026 #endif
1030 Foam::label Foam::osRandomInteger()
1032 #ifdef USE_RANDOM
1033     return random();
1034 #else
1035     return lrand48();
1036 #endif
1040 Foam::scalar Foam::osRandomDouble()
1042 #ifdef USE_RANDOM
1043     return (scalar)random()/INT_MAX;
1044 #else
1045     return drand48();
1046 #endif
1050 // ************************************************************************* //