initial commit for version 1.6.x patch release
[OpenFOAM-1.6.x.git] / src / OSspecific / POSIX / POSIX.C
blob3f64d413c3e2f95e36e72044c58f20e5a5cfcccf
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
11     OpenFOAM 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 2 of the License, or (at your
14     option) any later version.
16     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 Description
26     POSIX versions of the functions declared in OSspecific.H
28 \*---------------------------------------------------------------------------*/
30 #ifdef solarisGcc
31 # define _SYS_VNODE_H
32 #endif
34 #include "OSspecific.H"
35 #include "POSIX.H"
36 #include "foamVersion.H"
37 #include "fileName.H"
38 #include "fileStat.H"
39 #include "timer.H"
41 #include <fstream>
42 #include <cstdlib>
43 #include <cctype>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <dirent.h>
48 #include <pwd.h>
49 #include <errno.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/socket.h>
53 #include <netdb.h>
55 #include <netinet/in.h>
57 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
59 defineTypeNameAndDebug(Foam::POSIX, 0);
61 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
63 pid_t Foam::pid()
65     return getpid();
68 pid_t Foam::ppid()
70     return getppid();
73 pid_t Foam::pgid()
75     return getpgrp();
78 bool Foam::env(const word& envName)
80     return getenv(envName.c_str()) != NULL;
84 Foam::string Foam::getEnv(const word& envName)
86     char* env = getenv(envName.c_str());
88     if (env)
89     {
90         return string(env);
91     }
92     else
93     {
94         // Return null-constructed string rather than string::null
95         // to avoid cyclic dependencies in the construction of globals
96         return string();
97     }
101 bool Foam::setEnv
103     const word& envName,
104     const string& value,
105     const bool overwrite
108     return setenv(envName.c_str(), value.c_str(), overwrite) == 0;
112 Foam::word Foam::hostName()
114     char buffer[256];
115     gethostname(buffer, 256);
117     return buffer;
121 Foam::word Foam::userName()
123     struct passwd* pw = getpwuid(getuid());
125     if (pw != NULL)
126     {
127         return pw->pw_name;
128     }
129     else
130     {
131         return word::null;
132     }
136 // use $HOME environment variable or passwd info
137 Foam::fileName Foam::home()
139     char* env = getenv("HOME");
141     if (env != NULL)
142     {
143         return fileName(env);
144     }
145     else
146     {
147         struct passwd* pw = getpwuid(getuid());
149         if (pw != NULL)
150         {
151             return pw->pw_dir;
152         }
153         else
154         {
155             return fileName::null;
156         }
157     }
161 Foam::fileName Foam::home(const word& userName)
163     struct passwd* pw;
165     if (userName.size())
166     {
167         pw = getpwnam(userName.c_str());
168     }
169     else
170     {
171         char* env = getenv("HOME");
173         if (env != NULL)
174         {
175             return fileName(env);
176         }
178         pw = getpwuid(getuid());
179     }
181     if (pw != NULL)
182     {
183         return pw->pw_dir;
184     }
185     else
186     {
187         return fileName::null;
188     }
192 Foam::fileName Foam::cwd()
194     char buf[255];
195     if (getcwd(buf, 255))
196     {
197         return buf;
198     }
199     else
200     {
201         FatalErrorIn("Foam::cwd()")
202             << "Couldn't get the current working directory"
203             << exit(FatalError);
205         return fileName::null;
206     }
210 bool Foam::chDir(const fileName& dir)
212     return chdir(dir.c_str()) != 0;
216 Foam::fileName Foam::findEtcFile(const fileName& name, bool mandatory)
218     // Search user files:
219     // ~~~~~~~~~~~~~~~~~~
220     fileName searchDir = home()/".OpenFOAM";
221     if (isDir(searchDir))
222     {
223         // Check for user file in ~/.OpenFOAM/VERSION
224         fileName fullName = searchDir/FOAMversion/name;
225         if (isFile(fullName))
226         {
227             return fullName;
228         }
230         // Check for version-independent user file in ~/.OpenFOAM
231         fullName = searchDir/name;
232         if (isFile(fullName))
233         {
234             return fullName;
235         }
236     }
239     // Search site files:
240     // ~~~~~~~~~~~~~~~~~~
241     searchDir = getEnv("WM_PROJECT_INST_DIR");
242     if (isDir(searchDir))
243     {
244         // Check for site file in $WM_PROJECT_INST_DIR/site/VERSION
245         fileName fullName = searchDir/"site"/FOAMversion/name;
246         if (isFile(fullName))
247         {
248             return fullName;
249         }
251         // Check for version-independent site file in $WM_PROJECT_INST_DIR/site
252         fullName = searchDir/"site"/name;
253         if (isFile(fullName))
254         {
255             return fullName;
256         }
257     }
259     // Search installation files:
260     // ~~~~~~~~~~~~~~~~~~~~~~~~~~
261     searchDir = getEnv("WM_PROJECT_DIR");
262     if (isDir(searchDir))
263     {
264         // Check for shipped OpenFOAM file in $WM_PROJECT_DIR/etc
265         fileName fullName = searchDir/"etc"/name;
266         if (isFile(fullName))
267         {
268             return fullName;
269         }
270     }
272     // Not found
273     // abort if the file is mandatory, otherwise return null
274     if (mandatory)
275     {
276         cerr<< "--> FOAM FATAL ERROR in Foam::findEtcFile() :"
277                " could not find mandatory file\n    '"
278             << name.c_str() << "'\n\n" << std::endl;
279         ::exit(1);
280     }
282     // Return null-constructed fileName rather than fileName::null
283     // to avoid cyclic dependencies in the construction of globals
284     return fileName();
288 bool Foam::mkDir(const fileName& pathName, mode_t mode)
290     // empty names are meaningless
291     if (pathName.empty())
292     {
293         return false;
294     }
296     // Construct instance path directory if does not exist
297     if (::mkdir(pathName.c_str(), mode) == 0)
298     {
299         // Directory made OK so return true
300         return true;
301     }
302     else
303     {
304         switch (errno)
305         {
306             case EPERM:
307             {
308                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
309                     << "The filesystem containing " << pathName
310                     << " does not support the creation of directories."
311                     << exit(FatalError);
313                 return false;
314             }
316             case EEXIST:
317             {
318                 // Directory already exists so simply return true
319                 return true;
320             }
322             case EFAULT:
323             {
324                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
325                     << "" << pathName
326                     << " points outside your accessible address space."
327                     << exit(FatalError);
329                 return false;
330             }
332             case EACCES:
333             {
334                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
335                     << "The parent directory does not allow write "
336                        "permission to the process,"<< nl
337                     << "or one of the directories in " << pathName
338                     << " did not allow search (execute) permission."
339                     << exit(FatalError);
341                 return false;
342             }
344             case ENAMETOOLONG:
345             {
346                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
347                     << "" << pathName << " is too long."
348                     << exit(FatalError);
350                 return false;
351             }
353             case ENOENT:
354             {
355                 // Part of the path does not exist so try to create it
356                 if (pathName.path().size() && mkDir(pathName.path(), mode))
357                 {
358                     return mkDir(pathName, mode);
359                 }
360                 else
361                 {
362                     FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
363                         << "Couldn't create directory " << pathName
364                         << exit(FatalError);
366                     return false;
367                 }
368             }
370             case ENOTDIR:
371             {
372                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
373                     << "A component used as a directory in " << pathName
374                     << " is not, in fact, a directory."
375                     << exit(FatalError);
377                 return false;
378             }
380             case ENOMEM:
381             {
382                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
383                     << "Insufficient kernel memory was available to make "
384                        "directory " << pathName << '.'
385                     << exit(FatalError);
387                 return false;
388             }
390             case EROFS:
391             {
392                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
393                     << "" << pathName
394                     << " refers to a file on a read-only filesystem."
395                     << exit(FatalError);
397                 return false;
398             }
400             case ELOOP:
401             {
402                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
403                     << "Too many symbolic links were encountered in resolving "
404                     << pathName << '.'
405                     << exit(FatalError);
407                 return false;
408             }
410             case ENOSPC:
411             {
412                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
413                     << "The device containing " << pathName
414                     << " has no room for the new directory or "
415                     << "the user's disk quota is exhausted."
416                     << exit(FatalError);
418                 return false;
419             }
421             default:
422             {
423                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
424                     << "Couldn't create directory " << pathName
425                     << exit(FatalError);
427                 return false;
428             }
429         }
430     }
434 // Set the file mode
435 bool Foam::chMod(const fileName& name, const mode_t m)
437     return ::chmod(name.c_str(), m) == 0;
441 // Return the file mode
442 mode_t Foam::mode(const fileName& name)
444     fileStat fileStatus(name);
445     if (fileStatus.isValid())
446     {
447         return fileStatus.status().st_mode;
448     }
449     else
450     {
451         return 0;
452     }
456 // Return the file type: FILE or DIRECTORY
457 Foam::fileName::Type Foam::type(const fileName& name)
459     mode_t m = mode(name);
461     if (S_ISREG(m))
462     {
463         return fileName::FILE;
464     }
465     else if (S_ISDIR(m))
466     {
467         return fileName::DIRECTORY;
468     }
469     else
470     {
471         return fileName::UNDEFINED;
472     }
476 // Does the name exist in the filing system?
477 bool Foam::exists(const fileName& name, const bool checkGzip)
479     return mode(name) || isFile(name, checkGzip);
483 // Does the directory exist?
484 bool Foam::isDir(const fileName& name)
486     return S_ISDIR(mode(name));
490 // Does the file exist?
491 bool Foam::isFile(const fileName& name, const bool checkGzip)
493     return S_ISREG(mode(name)) || (checkGzip && S_ISREG(mode(name + ".gz")));
497 // Return size of file
498 off_t Foam::fileSize(const fileName& name)
500     fileStat fileStatus(name);
501     if (fileStatus.isValid())
502     {
503         return fileStatus.status().st_size;
504     }
505     else
506     {
507         return -1;
508     }
512 // Return time of last file modification
513 time_t Foam::lastModified(const fileName& name)
515     fileStat fileStatus(name);
516     if (fileStatus.isValid())
517     {
518         return fileStatus.status().st_mtime;
519     }
520     else
521     {
522         return 0;
523     }
527 // Read a directory and return the entries as a string list
528 Foam::fileNameList Foam::readDir
530     const fileName& directory,
531     const fileName::Type type,
532     const bool filtergz
535     // Initial filename list size
536     // also used as increment if initial size found to be insufficient
537     static const int maxNnames = 100;
539     if (POSIX::debug)
540     {
541         Info<< "readDir(const fileName&, const fileType, const bool filtergz)"
542             << " : reading directory " << directory << endl;
543     }
545     // Setup empty string list MAXTVALUES long
546     fileNameList dirEntries(maxNnames);
548     // Pointers to the directory entries
549     DIR *source;
550     struct dirent *list;
552     // Temporary variables and counters
553     label nEntries = 0;
555     // Attempt to open directory and set the structure pointer
556     if ((source = opendir(directory.c_str())) == NULL)
557     {
558         dirEntries.setSize(0);
560         if (POSIX::debug)
561         {
562             Info<< "readDir(const fileName&, const fileType, "
563                    "const bool filtergz) : cannot open directory "
564                 << directory << endl;
565         }
566     }
567     else
568     {
569         // Read and parse all the entries in the directory
570         while ((list = readdir(source)) != NULL)
571         {
572             fileName fName(list->d_name);
574             // ignore files begining with ., i.e. '.', '..' and '.*'
575             if (fName.size() && fName[0] != '.')
576             {
577                 word fExt = fName.ext();
579                 if
580                 (
581                     (type == fileName::DIRECTORY)
582                  ||
583                     (
584                         type == fileName::FILE
585                      && fName[fName.size()-1] != '~'
586                      && fExt != "bak"
587                      && fExt != "BAK"
588                      && fExt != "old"
589                      && fExt != "save"
590                     )
591                 )
592                 {
593                     if ((directory/fName).type() == type)
594                     {
595                         if (nEntries >= dirEntries.size())
596                         {
597                             dirEntries.setSize(dirEntries.size() + maxNnames);
598                         }
600                         if (filtergz && fExt == "gz")
601                         {
602                             dirEntries[nEntries++] = fName.lessExt();
603                         }
604                         else
605                         {
606                             dirEntries[nEntries++] = fName;
607                         }
608                     }
609                 }
610             }
611         }
613         // Reset the length of the entries list
614         dirEntries.setSize(nEntries);
616         closedir(source);
617     }
619     return dirEntries;
623 // Copy, recursively if necessary, the source to the destination
624 bool Foam::cp(const fileName& src, const fileName& dest)
626     // Make sure source exists.
627     if (!exists(src))
628     {
629         return false;
630     }
632     fileName destFile(dest);
634     // Check type of source file.
635     if (src.type() == fileName::FILE)
636     {
637         // If dest is a directory, create the destination file name.
638         if (destFile.type() == fileName::DIRECTORY)
639         {
640             destFile = destFile/src.name();
641         }
643         // Make sure the destination directory exists.
644         if (!isDir(destFile.path()) && !mkDir(destFile.path()))
645         {
646             return false;
647         }
649         // Open and check streams.
650         std::ifstream srcStream(src.c_str());
651         if (!srcStream)
652         {
653             return false;
654         }
656         std::ofstream destStream(destFile.c_str());
657         if (!destStream)
658         {
659             return false;
660         }
662         // Copy character data.
663         char ch;
664         while (srcStream.get(ch))
665         {
666             destStream.put(ch);
667         }
669         // Final check.
670         if (!srcStream.eof() || !destStream)
671         {
672             return false;
673         }
674     }
675     else if (src.type() == fileName::DIRECTORY)
676     {
677         // If dest is a directory, create the destination file name.
678         if (destFile.type() == fileName::DIRECTORY)
679         {
680             destFile = destFile/src.component(src.components().size() -1);
681         }
683         // Make sure the destination directory exists.
684         if (!isDir(destFile) && !mkDir(destFile))
685         {
686             return false;
687         }
689         // Copy files
690         fileNameList contents = readDir(src, fileName::FILE, false);
691         forAll(contents, i)
692         {
693             if (POSIX::debug)
694             {
695                 Info<< "Copying : " << src/contents[i]
696                     << " to " << destFile/contents[i] << endl;
697             }
699             // File to file.
700             cp(src/contents[i], destFile/contents[i]);
701         }
703         // Copy sub directories.
704         fileNameList subdirs = readDir(src, fileName::DIRECTORY);
705         forAll(subdirs, i)
706         {
707             if (POSIX::debug)
708             {
709                 Info<< "Copying : " << src/subdirs[i]
710                     << " to " << destFile << endl;
711             }
713             // Dir to Dir.
714             cp(src/subdirs[i], destFile);
715         }
716     }
718     return true;
722 // Create a softlink. dst should not exist. Returns true if successful.
723 bool Foam::ln(const fileName& src, const fileName& dst)
725     if (POSIX::debug)
726     {
727         Info<< "Create softlink from : " << src << " to " << dst
728             << endl;
729     }
731     if (exists(dst))
732     {
733         WarningIn("ln(const fileName&, const fileName&)")
734             << "destination " << dst << " already exists. Not linking."
735             << endl;
736         return false;
737     }
739     if (!exists(src))
740     {
741         WarningIn("ln(const fileName&, const fileName&)")
742             << "source " << src << " does not exist." << endl;
743         return false;
744     }
746     if (symlink(src.c_str(), dst.c_str()) == 0)
747     {
748         return true;
749     }
750     else
751     {
752         WarningIn("ln(const fileName&, const fileName&)")
753             << "symlink from " << src << " to " << dst << " failed." << endl;
754         return false;
755     }
759 // Rename srcFile dstFile
760 bool Foam::mv(const fileName& src, const fileName& dst)
762     if (POSIX::debug)
763     {
764         Info<< "Move : " << src << " to " << dst << endl;
765     }
767     if
768     (
769         dst.type() == fileName::DIRECTORY
770      && src.type() != fileName::DIRECTORY
771     )
772     {
773         const fileName dstName(dst/src.name());
775         return rename(src.c_str(), dstName.c_str()) == 0;
776     }
777     else
778     {
779         return rename(src.c_str(), dst.c_str()) == 0;
780     }
784 //- Rename to a corresponding backup file
785 //  If the backup file already exists, attempt with "01" .. "99" index
786 bool Foam::mvBak(const fileName& src, const std::string& ext)
788     if (POSIX::debug)
789     {
790         Info<< "mvBak : " << src << " to extension " << ext << endl;
791     }
793     if (exists(src, false))
794     {
795         const int maxIndex = 99;
796         char index[3];
798         for (int n = 0; n <= maxIndex; n++)
799         {
800             fileName dstName(src + "." + ext);
801             if (n)
802             {
803                 sprintf(index, "%02d", n);
804                 dstName += index;
805             }
807             // avoid overwriting existing files, except for the last
808             // possible index where we have no choice
809             if (!exists(dstName, false) || n == maxIndex)
810             {
811                 return rename(src.c_str(), dstName.c_str()) == 0;
812             }
814         }
815     }
817     // fall-through: nothing to do
818     return false;
823 // Remove a file, returning true if successful otherwise false
824 bool Foam::rm(const fileName& file)
826     if (POSIX::debug)
827     {
828         Info<< "Removing : " << file << endl;
829     }
831     // Try returning plain file name; if not there, try with .gz
832     if (remove(file.c_str()) == 0)
833     {
834         return true;
835     }
836     else
837     {
838         return remove(string(file + ".gz").c_str()) == 0;
839     }
843 // Remove a dirctory and its contents
844 bool Foam::rmDir(const fileName& directory)
846     if (POSIX::debug)
847     {
848         Info<< "rmDir(const fileName&) : "
849             << "removing directory " << directory << endl;
850     }
852     // Pointers to the directory entries
853     DIR *source;
854     struct dirent *list;
856     // Attempt to open directory and set the structure pointer
857     if ((source = opendir(directory.c_str())) == NULL)
858     {
859         WarningIn("rmDir(const fileName&)")
860             << "cannot open directory " << directory << endl;
862         return false;
863     }
864     else
865     {
866         // Read and parse all the entries in the directory
867         while ((list = readdir(source)) != NULL)
868         {
869             fileName fName(list->d_name);
871             if (fName != "." && fName != "..")
872             {
873                 fileName path = directory/fName;
875                 if (path.type() == fileName::DIRECTORY)
876                 {
877                     if (!rmDir(path))
878                     {
879                         WarningIn("rmDir(const fileName&)")
880                             << "failed to remove directory " << fName
881                             << " while removing directory " << directory
882                             << endl;
884                         closedir(source);
886                         return false;
887                     }
888                 }
889                 else
890                 {
891                     if (!rm(path))
892                     {
893                         WarningIn("rmDir(const fileName&)")
894                             << "failed to remove file " << fName
895                             << " while removing directory " << directory
896                             << endl;
898                         closedir(source);
900                         return false;
901                     }
902                 }
903             }
905         }
907         if (!rm(directory))
908         {
909             WarningIn("rmDir(const fileName&)")
910                 << "failed to remove directory " << directory << endl;
912             closedir(source);
914             return false;
915         }
917         closedir(source);
919         return true;
920     }
924 unsigned int Foam::sleep(const unsigned int s)
926     return ::sleep(s);
930 void Foam::fdClose(const int fd)
932     if (close(fd) != 0)
933     {
934         FatalErrorIn
935         (
936             "fdClose(const int fd)"
937         )   << "close error on " << fd << endl
938             << abort(FatalError);
939     }
943 bool Foam::ping
945     const word& destName,
946     const label destPort,
947     const label timeOut
950     char *serverAddress;
951     struct in_addr *ptr;
952     struct hostent *hostPtr;
953     volatile int sockfd;
954     struct sockaddr_in destAddr;      // will hold the destination addr
955     u_int addr;
957     if ((hostPtr = gethostbyname(destName.c_str())) == NULL)
958     {
959         FatalErrorIn
960         (
961             "Foam::ping(const word&, const label)"
962         )   << "gethostbyname error " << h_errno << " for host " << destName
963             << abort(FatalError);
964     }
966     // Get first of the SLL of addresses
967     serverAddress = *(hostPtr->h_addr_list);
968     ptr = reinterpret_cast<struct in_addr*>(serverAddress);
969     addr = ptr->s_addr;
971     // Allocate socket
972     sockfd = socket(AF_INET, SOCK_STREAM, 0);
973     if (sockfd < 0)
974     {
975         FatalErrorIn
976         (
977             "Foam::ping(const word&, const label)"
978         )   << "socket error"
979             << abort(FatalError);
980     }
982     // Fill sockaddr_in structure with dest address and port
983     memset (reinterpret_cast<char *>(&destAddr), '\0', sizeof(destAddr));
984     destAddr.sin_family = AF_INET;
985     destAddr.sin_port = htons(ushort(destPort));
986     destAddr.sin_addr.s_addr = addr;
989     timer myTimer(timeOut);
991     if (timedOut(myTimer))
992     {
993         // Setjmp from timer jumps back to here
994         fdClose(sockfd);
995         return false;
996     }
998     if
999     (
1000         connect
1001         (
1002             sockfd,
1003             reinterpret_cast<struct sockaddr*>(&destAddr),
1004             sizeof(struct sockaddr)
1005         ) != 0
1006     )
1007     {
1008         // Connection refused. Check if network was actually used or not.
1010         int connectErr = errno;
1012         fdClose(sockfd);
1014         if (connectErr == ECONNREFUSED)
1015         {
1016             return true;
1017         }
1018         //perror("connect");
1020         return false;
1021     }
1023     fdClose(sockfd);
1025     return true;
1029 bool Foam::ping(const word& hostname, const label timeOut)
1031     return ping(hostname, 222, timeOut) || ping(hostname, 22, timeOut);
1035 int Foam::system(const string& command)
1037     return ::system(command.c_str());
1041 // ************************************************************************* //