Operating System - OpenVMS
1753321 Members
6279 Online
108792 Solutions
New Discussion

Re: lstat and case-sensitivity

 
Steven Schweda
Honored Contributor

Re: lstat and case-sensitivity

> LIB$INITIALIZE is in SYS$COMMON:[SYSLIB]STARLET.OLB, which the linker
> processes by default.

   Not much use if you're trying to supply your own.

> You may want to show the full link command and the
> exact linker message.

   No argument there.  As I recall, C++ tends to use/hijack
LIB$INITIALIZE for its own purposes, so, to use it with C++, you need to
create a separate shared image with your own LIB$INITIALIZE, and ask the
linker to get yours, too.  But, as I said, I've never done it.  A Forum
or Web search (for: C++ LIB$INITIALIZE) might find some details.  If you
actually care.

H.Becker
Honored Contributor

Re: lstat and case-sensitivity

..>> LIB$INITIALIZE is in SYS$COMMON:[SYSLIB]STARLET.OLB, which the linker
>> processes by default.

>Not much use if you're trying to supply your own.

Your own what? The OP said,  "undefined lib$initialize". Which may be a real linker message or not. If that undefined symbol is LIB$INITIALIZE, it is defined in SYS$COMMON:[SYSLIB]STARLET.OLB. You can not have your own symbol LIB$INITIALIZE to get the image initialization done. You have to have your own PSECT LIB$INITIALIZE merged into the pre-fabricated wrappers from the object module  LIB$INITIALIZE, which is part of STARLET.OLB.

Edit: Actually, you don't need the symbol LIB$INITIALIZE at all. You only need to include the object module LIB$INITIALIZE.

> ... As I recall, C++ tends to use/hijack
> LIB$INITIALIZE for its own purposes, so, to use it with C++, you need to
> create a separate shared image with your own LIB$INITIALIZE, and ask the
> linker to get yours, too. But, as I said, I've never done it. A Forum
> or Web search (for: C++ LIB$INITIALIZE) might find some details. If you
> actually care.

I wouldn't say hijack. C++ and its RTL (on I64 if I remember correctly) uses the LIB$INITIALIZE mechanism as well. To get your own image initialization done before the RTL's shareable image ones, you have to have a shareable image with your init code which the image activator activates before the C++ RTL. The image activator followes the list of shareable images as the linker sets it up. That is, your link command has to ensure that your (init code in your) shareable image is "in front of" the C++ RTL's one. 

 

Hoff
Honored Contributor

Re: lstat and case-sensitivity

As others have correctly noted, this utterly non-modular and nonsensical and ill-considered "design" of the C run-time library means either defining the logical names ahead of image invocation, or — if you want to use the API — invoking the feature set calls in the initialization PSECT, ahead of the main() call.   (The main() call invokes the C library initialization code, and which is also why you see that "type GO to get to the start of the main program" in the debugger. )

This scheme all makes sense if you know how the OpenVMS image initialization actually works, but pragmaticallt it's a design that's user-hostile and non-modular at best, and some of the alternative user interfaces possible here could have made this vastly easiler and better.

(If you've inferred that I might not be a proponent of this "design", you probably don't know the half of what I think about this particular and fetid heap of vomitus.  This was a Bad Idea when it was built, and the imbroglio has only increased as settings accreted.  But I digress.)

When logging bug reports, posting full details and a reproducer really helps — saves folks from guessing what has happened — and it requires less effort on the part of those that might help you to get to the answer that you want and need.   Attaching a zip here can work nicely too, as that can contain the entirety of the reproducer.

mpradhan
Advisor

Re: lstat and case-sensitivity

OK. First I would like to point out what behavior I see with lstat (this is simple nothing do with case-sensitivity, something I just stumbled upon).

this is cpp program using lstat() and printing ctime, atime, mtime.

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <errno.h>
#include <unixlib.h>

using namespace std;


int
main(int argc, char** argv)
{
string sFilePath;
cout << "Enter Path: ";
cin >> sFilePath;
struct stat st;
int iRet(0);

if((iRet = lstat(sFilePath.c_str(), &st)) < 0)
{
cerr << "lstat(" << sFilePath << ") failed, error=" << strerror(errno) << endl;
exit(-1);
}
cout << "ctime: " << asctime(localtime(&st.st_ctime));
cout << "mtime: " << asctime(localtime(&st.st_mtime));
cout << "atime: " << asctime(localtime(&st.st_atime));
exit(0);
}

this is the result using this program.

$ test_stat
Enter Path: dka0:[ssq]out.txt;2
ctime: Tue May 15 17:31:22 2012
mtime: Tue May 15 17:32:52 2012
atime: Tue May 15 17:32:52 2012

and this is dir /full result on the same file

$ dir /full dka0:[ssq]out.txt;2

Directory DKA0:[SSQ]

OUT.TXT;2 File ID: (19005,4,0)
Size: 2/32 Owner: [SYSTEM]
Created: 15-MAY-2012 17:31:22.29
Revised: 15-MAY-2012 17:32:52.87 (1)
Expires: 10-MAR-2017 14:07:20.31
Backup: <No backup recorded>
Effective: <None specified>
Recording: <None specified>
Accessed: 15-MAY-2012 17:31:22.29
Attributes: 15-MAY-2012 17:32:52.87
Modified: 15-MAY-2012 17:31:22.29
Linkcount: 1
File organization: Sequential
Shelved state: Online
Caching attribute: Writethrough
File attributes: Allocation: 32, Extend: 0, Global buffer count: 0
Version limit: 3
Record format: VFC, 2 byte header, maximum 0 bytes, longest 107 bytes
Record attributes: Print file carriage control
RMS attributes: None
Journaling enabled: None
File protection: System:RWED, Owner:RWED, Group:RE, World:
Access Cntrl List: (IDENTIFIER=[150,*],ACCESS=READ)
Client attributes: None

Total of 1 file, 2/32 blocks.
$

 

so this is the lstat() bug that I talked about.

 

Second. I dont really need DEC$ARGV_PARSE_STYLE but I need DEC$EFS_CASE_PRESERVE instead, I think, to instruct lstat() to treat filename case-sensitively.

So this is the lstat() program (same above program silghtly changed) for case-sensitivity test. 

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <errno.h>
#include <unixlib.h>

using namespace std;

#define ENABLE TRUE
#define DISABLE 0

static int set_feature_default(const char *name, int value)
{
int index = decc$feature_get_index(name);;
if (index > 0)
index = decc$feature_set_value (index, 0, value);
return index;
}

static void show_feature_default(const char* name)
{
int index = decc$feature_get_index(name);
if(index > 0)
{
int value = decc$feature_get_value(index, 0);
cout << name << " has value " << value << endl;
}
}


int
main(int argc, char** argv)
{
string sFilePath;
cout << "Enter Path: ";
cin >> sFilePath;
int iCaseSensitive(0);
int prev_value = set_feature_default("DECC$EFS_CASE_PRESERVE", ENABLE);
if(0 != prev_value)
cerr << "Failed to set DECC$EFS_CASE_PRESERVE," << " errno=" << strerror(errno) << endl;
show_feature_default("DECC$EFS_CASE_PRESERVE");
struct stat st;
int iRet(0);

if((iRet = lstat(sFilePath.c_str(), &st)) < 0)
{
cerr << "lstat(" << sFilePath << ") failed, error=" << strerror(errno) << endl;
exit(-1);
}
cout << "ctime: " << asctime(localtime(&st.st_ctime));
cout << "mtime: " << asctime(localtime(&st.st_mtime));
cout << "atime: " << asctime(localtime(&st.st_atime));
exit(0);
}

dir listing on the directory.

$ dir dka0:[ssq]

Directory DKA0:[SSQ]

OUT.SAV;1 out.t;1 OUT.TXT;3 OUT.TXT;2
OUT.TXT;1 out.txt;4 out.txt;3 out.txt;2
OUT_ORIG.SAV;1 out_rest.sav;1 OUT_RESTORE.TXT;1 RESTORE.TXT;1
TESTIDX.ISM;1 This_file^_is_not_OK.txt;1
This_file^%is_not_OK.txt;1 This_file^+is_not_OK.txt;1
This_file^.is_OK.txt;1 This_file^=is_not_OK.txt;1

Total of 18 files.
$

note above, only out.txt;4 exits but both out.txt;2 and OUT.TXT;2 exist. Now trying this program 

$ test_stat
Enter Path: dka0:[ssq]out.txt;4
DECC$EFS_CASE_PRESERVE has value 1
lstat(dka0:[ssq]out.txt;4) failed, error=no such file or directory
$ test_stat
Enter Path: dka0:[ssq]out.txt;2
DECC$EFS_CASE_PRESERVE has value 1
ctime: Tue May 15 17:31:22 2012
mtime: Tue May 15 17:32:52 2012
atime: Tue May 15 17:32:52 2012

$ test_stat
Enter Path: dka0:[ssq]OUT.TXT;2
DECC$EFS_CASE_PRESERVE has value 1
ctime: Tue May 15 17:31:22 2012
mtime: Tue May 15 17:32:52 2012
atime: Tue May 15 17:32:52 2012
$

 

Also note that these are on IA64, we dont have Alpha or VAX. 

 

Rationale on why I am doing this - In my program (the real bigger one), I have a vital place where I need to do a lstat() on a file to grab some attributes (I am primarily a UNIX programmer making some code transition to OpenVMS, hence UNIX C-api come handy to me always). This is where it came to my notice that lstat() always fails when the volume has case-sensitivity enabled and there is a file with lower case only. Also, to note, that a subsequent sys$open() on the same full actually works. 

mpradhan
Advisor

Re: lstat and case-sensitivity

this is the full link command

$ CXXLINK/exe=test_stat.exe test_stat.obj,SYS$SHARE:STARLET.OLB
%ILINK-E-INVLDHDR, invalid ELF header; field 'ehdr$b_ei_mag0' has invalid value %X09
module: <unassigned>
file: SYS$COMMON:[SYSLIB]STARLET.OLB;1
%ILINK-W-NUDFSYMS, 1 undefined symbol:
%ILINK-I-UDFSYM, int lib$initialize()
%ILINK-W-USEUNDEF, undefined symbol int lib$initialize() referenced
source code name: "lib$initialize()"
section: .sdata
offset: %X0000000000000010
module: TEST_STAT
file: DNFS1:[cxunix.source.CommClient.ClProxyConnAPI.Client.backup]TEST_STAT.OBJ;32

the highlighted line is what I am curious about. 

 

H.Becker
Honored Contributor

Re: lstat and case-sensitivity

> $ CXXLINK/exe=test_stat.exe test_stat.obj,SYS$SHARE:STARLET.OLB

> %ILINK-E-INVLDHDR, invalid ELF header; field 'ehdr$b_ei_mag0' has invalid value %X09

Without any qualifier, the linker expects object files as arguments. STARLET.OLB is an object library. If you want to resolve from a library, you need to add the /LIBRARY qualifier to the object library. However, as already mentioned, this object library is already processed, by default. You may end up with "%ILINK-W-MULDEF" warning messages.

On the other hand, you are using CXXLINK, which does some postprocessing on the VMS linker output: something like "%ILINK-I-UDFSYM, LIB$INITIALIZE__XV" is converted to "%ILINK-I-UDFSYM, int lib$initialize()" - these examples are taken from Alpha, so the mangled name on I64 may be slightly different.. The linker resolves mangled names, CXXLINK hides these names and shows the demangled names. Essentially you have an unresolved symbol like "LIB$INITIALIZE__XV", which is not defined in any object module in STARLET.OLB, as the wanted, real name in that library and its module is "LIB$INITIALIZE." In other words, you need to wrap the "extern int lib$initialize();" with `extern "C" {  ...  }.'

For many VMS programmers, referencing the symbol LIB$INITIALIZE is just more convenient - as STARLET.OLB is searched by default for that symbol, than explicitly including the needed object module with a linker command string like "SYS$SHARE:STARLET/LIB/INCL=LIB$INITIALIZE".