correction to d4edb38234db8268907f04836d49bb93461b8a88
[OpenFOAM-1.5.x.git] / src / OSspecific / Unix / Unix.C
blob8f4ddafdb827b6b63e7524764478a2fd0c93ff7e
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2008 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     UNIX versions of the functions declated in OSspecific.H.
28 \*---------------------------------------------------------------------------*/
30 #ifdef solarisGcc
31 # define _SYS_VNODE_H
32 #endif
34 #include "OSspecific.H"
35 #include "Unix.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::Unix, 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 string::null;
95     }
99 bool Foam::setEnv
101     const word& envName,
102     const string& value,
103     const bool overwrite
106     return setenv(envName.c_str(), value.c_str(), overwrite) == 0;
110 Foam::word Foam::hostName()
112     char buffer[256];
113     gethostname(buffer, 256);
115     return buffer;
119 Foam::word Foam::userName()
121     struct passwd* pw = getpwuid(getuid());
123     if (pw != NULL)
124     {
125         return pw->pw_name;
126     }
127     else
128     {
129         return word::null;
130     }
134 // use $HOME environment variable or passwd info
135 Foam::fileName Foam::home()
137     char* env = getenv("HOME");
139     if (env != NULL)
140     {
141         return fileName(env);
142     }
143     else
144     {
145         struct passwd* pw = getpwuid(getuid());
147         if (pw != NULL)
148         {
149             return pw->pw_dir;
150         }
151         else
152         {
153             return fileName::null;
154         }
155     }
159 Foam::fileName Foam::home(const word& userName)
161     struct passwd* pw;
163     if (userName.size())
164     {
165         pw = getpwnam(userName.c_str());
166     }
167     else
168     {
169         char* env = getenv("HOME");
171         if (env != NULL)
172         {
173             return fileName(env);
174         }
176         pw = getpwuid(getuid());
177     }
179     if (pw != NULL)
180     {
181         return pw->pw_dir;
182     }
183     else
184     {
185         return fileName::null;
186     }
190 Foam::fileName Foam::cwd()
192     char buf[255];
193     if (getcwd(buf, 255))
194     {
195         return buf;
196     }
197     else
198     {
199         FatalErrorIn("Foam::cwd()")
200             << "Couldn't get the current working directory"
201             << exit(FatalError);
203         return fileName::null;
204     }
208 bool Foam::chDir(const fileName& dir)
210     return chdir(dir.c_str()) != 0;
214 Foam::fileName Foam::dotFoam(const fileName& name)
216     // Search user files:
217     // ~~~~~~~~~~~~~~~~~~
218     fileName searchDir = home()/".OpenFOAM";
219     if (dir(searchDir))
220     {
221         // Check for user file in ~/.OpenFOAM/VERSION
222         fileName fullName = searchDir/FOAMversion/name;
223         if (exists(fullName))
224         {
225             return fullName;
226         }
228         // Check for version-independent user file in ~/.OpenFOAM
229         fullName = searchDir/name;
230         if (exists(fullName))
231         {
232             return fullName;
233         }
234     }
237     // Search site files:
238     // ~~~~~~~~~~~~~~~~~~
239     searchDir = getEnv("WM_PROJECT_INST_DIR");
240     if (dir(searchDir))
241     {
242         // Check for site file in $WM_PROJECT_INST_DIR/site/VERSION
243         fileName fullName = searchDir/"site"/FOAMversion/name;
244         if (exists(fullName))
245         {
246             return fullName;
247         }
249         // Check for version-independent site file in $WM_PROJECT_INST_DIR/site
250         fullName = searchDir/"site"/name;
251         if (exists(fullName))
252         {
253             return fullName;
254         }
255     }
257     // Search installation files:
258     // ~~~~~~~~~~~~~~~~~~~~~~~~~~
259     searchDir = getEnv("WM_PROJECT_DIR");
260     if (dir(searchDir))
261     {
262         // Check for shipped OpenFOAM file in $WM_PROJECT_DIR/etc
263         fileName fullName = searchDir/"etc"/name;
264         if (exists(fullName))
265         {
266             return fullName;
267         }
268     }
270     // Not found
271     return fileName::null;
275 bool Foam::mkDir(const fileName& pathName, mode_t mode)
277     // empty names are meaningless
278     if (!pathName.size())
279     {
280         return false;
281     }
283     // Construct instance path directory if does not exist
284     if (::mkdir(pathName.c_str(), mode) == 0)
285     {
286         // Directory made OK so return true
287         return true;
288     }
289     else
290     {
291         switch (errno)
292         {
293             case EPERM:
294             {
295                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
296                     << "The filesystem containing " << pathName
297                     << " does not support the creation of directories."
298                     << exit(FatalError);
300                 return false;
301             }
303             case EEXIST:
304             {
305                 // Directory already exists so simply return true
306                 return true;
307             }
309             case EFAULT:
310             {
311                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
312                     << "" << pathName
313                     << " points outside your accessible address space."
314                     << exit(FatalError);
316                 return false;
317             }
319             case EACCES:
320             {
321                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
322                     << "The parent directory does not allow write "
323                        "permission to the process,"<< nl
324                     << "or one of the directories in " << pathName
325                     << " did not allow search (execute) permission."
326                     << exit(FatalError);
328                 return false;
329             }
331             case ENAMETOOLONG:
332             {
333                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
334                     << "" << pathName << " is too long."
335                     << exit(FatalError);
337                 return false;
338             }
340             case ENOENT:
341             {
342                 // Part of the path does not exist so try to create it
343                 if (pathName.path().size() && mkDir(pathName.path(), mode))
344                 {
345                     return mkDir(pathName, mode);
346                 }
347                 else
348                 {
349                     FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
350                         << "Couldn't create directory " << pathName
351                         << exit(FatalError);
353                     return false;
354                 }
355             }
357             case ENOTDIR:
358             {
359                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
360                     << "A component used as a directory in " << pathName
361                     << " is not, in fact, a directory."
362                     << exit(FatalError);
364                 return false;
365             }
367             case ENOMEM:
368             {
369                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
370                     << "Insufficient kernel memory was available to make "
371                        "directory " << pathName << '.'
372                     << exit(FatalError);
374                 return false;
375             }
377             case EROFS:
378             {
379                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
380                     << "" << pathName
381                     << " refers to a file on a read-only filesystem."
382                     << exit(FatalError);
384                 return false;
385             }
387             case ELOOP:
388             {
389                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
390                     << "Too many symbolic links were encountered in resolving "
391                     << pathName << '.'
392                     << exit(FatalError);
394                 return false;
395             }
397             case ENOSPC:
398             {
399                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
400                     << "The device containing " << pathName
401                     << " has no room for the new directory or "
402                     << "the user's disk quota is exhausted."
403                     << exit(FatalError);
405                 return false;
406             }
408             default:
409             {
410                 FatalErrorIn("Foam::mkDir(const fileName&, mode_t)")
411                     << "Couldn't create directory " << pathName
412                     << exit(FatalError);
414                 return false;
415             }
416         }
417     }
421 // Set the file mode
422 bool Foam::chmod(const fileName& name, const mode_t m)
424     return ::chmod(name.c_str(), m) == 0;
428 // Return the file mode
429 mode_t Foam::mode(const fileName& name)
431     fileStat fileStatus(name);
432     if (fileStatus.isValid())
433     {
434         return fileStatus.status().st_mode;
435     }
436     else
437     {
438         return 0;
439     }
443 // Return the file type: FILE or DIRECTORY
444 Foam::fileName::Type Foam::type(const fileName& name)
446     mode_t m = mode(name);
448     if (S_ISREG(m))
449     {
450         return fileName::FILE;
451     }
452     else if (S_ISDIR(m))
453     {
454         return fileName::DIRECTORY;
455     }
456     else
457     {
458         return fileName::UNDEFINED;
459     }
463 // Does the name exist in the filing system?
464 bool Foam::exists(const fileName& name)
466     return mode(name) || file(name);
470 // Does the file exist
471 bool Foam::file(const fileName& name)
473     return S_ISREG(mode(name)) || S_ISREG(mode(name + ".gz"));
477 // Does the directory exist
478 bool Foam::dir(const fileName& name)
480     return S_ISDIR(mode(name));
484 // Return size of file
485 off_t Foam::size(const fileName& name)
487     fileStat fileStatus(name);
488     if (fileStatus.isValid())
489     {
490         return fileStatus.status().st_size;
491     }
492     else
493     {
494         return -1;
495     }
499 // Return time of last file modification
500 time_t Foam::lastModified(const fileName& name)
502     fileStat fileStatus(name);
503     if (fileStatus.isValid())
504     {
505         return fileStatus.status().st_mtime;
506     }
507     else
508     {
509         return 0;
510     }
514 // Read a directory and return the entries as a string list
515 Foam::fileNameList Foam::readDir
517     const fileName& directory,
518     const fileName::Type type,
519     const bool filtergz
522     // Initial filename list size
523     // also used as increment if initial size found to be insufficient
524     static const int maxNnames = 100;
526     if (Unix::debug)
527     {
528         Info<< "readDir(const fileName&, const fileType, const bool filtergz)"
529             << " : reading directory " << directory << endl;
530     }
532     // Setup empty string list MAXTVALUES long
533     fileNameList dirEntries(maxNnames);
535     // Pointers to the Unix director system
536     DIR *source;
537     struct dirent *list;
539     // Temporary variables and counters
540     label nEntries = 0;
542     // Attempt to open directory and set the structure pointer
543     if ((source = opendir(directory.c_str())) == NULL)
544     {
545         dirEntries.setSize(0);
547         if (Unix::debug)
548         {
549             Info<< "readDir(const fileName&, const fileType, "
550                    "const bool filtergz) : cannot open directory "
551                 << directory << endl;
552         }
553     }
554     else
555     {
556         // Read and parse all the entries in the directory
557         while ((list = readdir(source)) != NULL)
558         {
559             fileName fName(list->d_name);
561             // ignore files begining with ., i.e. ., .. and .??*
562             if (fName.size() > 0 && fName[size_t(0)] != '.')
563             {
564                 word fileNameExt = fName.ext();
566                 if
567                 (
568                     (type == fileName::DIRECTORY)
569                  ||
570                     (
571                         type == fileName::FILE
572                         && fName[fName.size()-1] != '~'
573                         && fileNameExt != "bak"
574                         && fileNameExt != "BAK"
575                         && fileNameExt != "old"
576                         && fileNameExt != "save"
577                     )
578                 )
579                 {
580                     if ((directory/fName).type() == type)
581                     {
582                         if (nEntries >= dirEntries.size())
583                         {
584                             dirEntries.setSize(dirEntries.size() + maxNnames);
585                         }
587                         if (filtergz && fileNameExt == "gz")
588                         {
589                             dirEntries[nEntries++] = fName.lessExt();
590                         }
591                         else
592                         {
593                             dirEntries[nEntries++] = fName;
594                         }
595                     }
596                 }
597             }
598         }
600         // Reset the length of the entries list
601         dirEntries.setSize(nEntries);
603         closedir(source);
604     }
606     return dirEntries;
610 // Copy, recursively if necessary, the source top the destination
611 bool Foam::cp(const fileName& src, const fileName& dest)
613     fileName destFile(dest);
615     // Make sure source exists.
616     if (!exists(src))
617     {
618         return false;
619     }
621     // Check type of source file.
622     if (src.type() == fileName::FILE)
623     {
624         // If dest is a directory, create the destination file name.
625         if (destFile.type() == fileName::DIRECTORY)
626         {
627             destFile = destFile/src.name();
628         }
630         // Make sure the destination directory exists.
631         if (!dir(destFile.path()) && !mkDir(destFile.path()))
632         {
633             return false;
634         }
636         // Open and check streams.
637         std::ifstream srcStream(src.c_str());
638         if (!srcStream)
639         {
640             return false;
641         }
643         std::ofstream destStream(destFile.c_str());
644         if (!destStream)
645         {
646             return false;
647         }
649         // Copy character data.
650         char ch;
651         while (srcStream.get(ch))
652         {
653             destStream.put(ch);
654         }
656         // Final check.
657         if (!srcStream.eof() || !destStream)
658         {
659             return false;
660         }
661     }
662     else if (src.type() == fileName::DIRECTORY)
663     {
664         // If dest is a directory, create the destination file name.
665         if (destFile.type() == fileName::DIRECTORY)
666         {
667             destFile = destFile/src.component(src.components().size() -1);
668         }
670         // Make sure the destination directory extists.
671         if (!dir(destFile) && !mkDir(destFile))
672         {
673             return false;
674         }
676         // Copy files
677         fileNameList contents = readDir(src, fileName::FILE, false);
678         forAll(contents, i)
679         {
680             if (Unix::debug)
681             {
682                 Info<< "Copying : " << src/contents[i]
683                     << " to " << destFile/contents[i] << endl;
684             }
686             // File to file.
687             cp(src/contents[i], destFile/contents[i]);
688         }
690         // Copy sub directories.
691         fileNameList subdirs = readDir(src, fileName::DIRECTORY);
692         forAll(subdirs, i)
693         {
694             if (Unix::debug)
695             {
696                 Info<< "Copying : " << src/subdirs[i]
697                     << " to " << destFile << endl;
698             }
700             // Dir to Dir.
701             cp(src/subdirs[i], destFile);
702         }
703     }
705     return true;
709 // Create a softlink. destFile should not exist. Returns true if successful.
710 bool Foam::ln(const fileName& src, const fileName& dest)
712     if (Unix::debug)
713     {
714         Info<< "Create softlink from : " << src << " to " << dest
715             << endl;
716     }
718     if (exists(dest))
719     {
720         WarningIn("ln(const fileName&, const fileName&)")
721             << "destination " << dest << " already exists. Not linking."
722             << endl;
723         return false;
724     }
726     if (!exists(src))
727     {
728         WarningIn("ln(const fileName&, const fileName&)")
729             << "source " << src << " does not exist." << endl;
730         return false;
731     }
733     if (symlink(src.c_str(), dest.c_str()) == 0)
734     {
735         return true;
736     }
737     else
738     {
739         WarningIn("ln(const fileName&, const fileName&)")
740             << "symlink from " << src << " to " << dest << " failed." << endl;
741         return false;
742     }
746 // Rename srcFile destFile
747 bool Foam::mv(const fileName& srcFile, const fileName& destFile)
749     if (Unix::debug)
750     {
751         Info<< "Move : " << srcFile << " to " << destFile << endl;
752     }
754     if
755     (
756         (destFile.type() == fileName::DIRECTORY)
757      && (srcFile.type() != fileName::DIRECTORY)
758     )
759     {
760         const fileName destName(destFile/srcFile.name());
762         return rename(srcFile.c_str(), destName.c_str()) == 0;
763     }
764     else
765     {
766         return rename(srcFile.c_str(), destFile.c_str()) == 0;
767     }
771 // Remove a file returning true if successful otherwise false
772 bool Foam::rm(const fileName& file)
774     if (Unix::debug)
775     {
776         Info<< "Removing : " << file << endl;
777     }
779     // Try returning plain file name; if not there, try with .gz
780     if (remove(file.c_str()) == 0)
781     {
782         return true;
783     }
784     else
785     {
786         return remove(string(file + ".gz").c_str()) == 0;
787     }
791 // Remove a dirctory and its contents
792 bool Foam::rmDir(const fileName& directory)
794     if (Unix::debug)
795     {
796         Info<< "rmdir(const fileName&) : "
797             << "removing directory " << directory << endl;
798     }
800     // Pointers to the Unix director system
801     DIR *source;
802     struct dirent *list;
804     // Attempt to open directory and set the structure pointer
805     if ((source = opendir(directory.c_str())) == NULL)
806     {
807         WarningIn("rmdir(const fileName&)")
808             << "cannot open directory " << directory << endl;
810         return false;
811     }
812     else
813     {
814         // Read and parse all the entries in the directory
815         while ((list = readdir(source)) != NULL)
816         {
817             fileName fName(list->d_name);
819             if (fName != "." && fName != "..")
820             {
821                 fileName path = directory/fName;
823                 if (path.type() == fileName::DIRECTORY)
824                 {
825                     if (!rmDir(path))
826                     {
827                         WarningIn("rmdir(const fileName&)")
828                             << "failed to remove directory " << fName
829                             << " while removing directory " << directory
830                             << endl;
832                         closedir(source);
834                         return false;
835                     }
836                 }
837                 else
838                 {
839                     if (!rm(path))
840                     {
841                         WarningIn("rmdir(const fileName&)")
842                             << "failed to remove file " << fName
843                             << " while removing directory " << directory
844                             << endl;
846                         closedir(source);
848                         return false;
849                     }
850                 }
851             }
853         }
855         if (!rm(directory))
856         {
857             WarningIn("rmdir(const fileName&)")
858                 << "failed to remove directory " << directory << endl;
860             closedir(source);
862             return false;
863         }
865         closedir(source);
867         return true;
868     }
872 unsigned int Foam::sleep(const unsigned int s)
874     return ::sleep(s);
878 void Foam::fdClose(const int fd)
880     if (close(fd) != 0)
881     {
882         FatalErrorIn
883         (
884             "fdClose(const int fd)"
885         )   << "close error on " << fd << endl
886             << abort(FatalError);
887     }
891 bool Foam::ping
893     const word& destName,
894     const label destPort,
895     const label timeOut
898     char *serverAddress;
899     struct in_addr *ptr;
900     struct hostent *hostPtr;
901     volatile int sockfd;
902     struct sockaddr_in destAddr;      // will hold the destination addr
903     u_int addr;
905     if ((hostPtr = gethostbyname(destName.c_str())) == NULL)
906     {
907         FatalErrorIn
908         (
909             "Foam::ping(const word&, const label)"
910         )   << "gethostbyname error " << h_errno << " for host " << destName
911             << abort(FatalError);
912     }
914     // Get first of the SLL of addresses
915     serverAddress = *(hostPtr->h_addr_list);
916     ptr = reinterpret_cast<struct in_addr*>(serverAddress);
917     addr = ptr->s_addr;
919     // Allocate socket
920     sockfd = socket(AF_INET, SOCK_STREAM, 0);
921     if (sockfd < 0)
922     {
923         FatalErrorIn
924         (
925             "Foam::ping(const word&, const label)"
926         )   << "socket error"
927             << abort(FatalError);
928     }
930     // Fill sockaddr_in structure with dest address and port
931     memset (reinterpret_cast<char *>(&destAddr), '\0', sizeof(destAddr));
932     destAddr.sin_family = AF_INET;
933     destAddr.sin_port = htons(ushort(destPort));
934     destAddr.sin_addr.s_addr = addr;
937     timer myTimer(timeOut);
939     if (timedOut(myTimer))
940     {
941         // Setjmp from timer jumps back to here
942         fdClose(sockfd);
943         return false;
944     }
946     if
947     (
948         connect
949         (
950             sockfd,
951             reinterpret_cast<struct sockaddr*>(&destAddr),
952             sizeof(struct sockaddr)
953         ) != 0
954     )
955     {
956         // Connection refused. Check if network was actually used or not.
958         int connectErr = errno;
960         fdClose(sockfd);
962         if (connectErr == ECONNREFUSED)
963         {
964             return true;
965         }
966         //perror("connect");
968         return false;
969     }
971     fdClose(sockfd);
973     return true;
977 bool Foam::ping(const word& hostname, const label timeOut)
979     return ping(hostname, 222, timeOut) || ping(hostname, 22, timeOut);
983 int Foam::system(const string& command)
985     return ::system(command.c_str());
989 // ************************************************************************* //