2

I want to be able to save to file the argv and environ of a process, and than, at a later time, to be able to fork and exec using the parameters that are saved to file.

The only design I could think of, is to write to file the list of parameters as a long string, but then I need to convert it from string to an array of strings, which is possible but very cumbersome.

Can anyone think of a better way to do it?

Mat
  • 202,337
  • 40
  • 393
  • 406
yaloner
  • 715
  • 2
  • 6
  • 19

2 Answers2

1

My suggestion for the file format

  • the first line is a decimal number N which is equal to argc
  • the next N lines are the argv strings, one string per line
  • then there's another decimal number M which is equal to the number of environment strings
  • the next M lines are the environment strings, one string per line

To read the file back into memory

  • read the first line with getline and convert the number with sscanf
  • malloc an array of N+1 pointers
  • read the next N lines using getline, storing the pointer in the argv array
  • put a NULL pointer at the end of the argv array
  • read the next line with getline and convert the number with sscanf
  • malloc an array of M+1 pointers
  • read the next M lines using getline, storing the pointer in the env array
  • put a NULL pointer at the end of the env array

There are two things to keep in mind when using getline. First, it will automatically malloc the memory for the string. Second, it puts the newline at the end of the string, so you have to remove it.

Sample code that reads the argv strings using getline

int N = 5;
char **argv = malloc( (N + 1) * sizeof(char *) );

char *line;
size_t linecap, length;

for ( int i = 0; i < N; i++ )
{
    line = NULL;            // request that getline allocate memory
    linecap = 0;
    if ( (length = getline( &line, &linecap, fp )) <= 0 )
        exit( 1 );          // file ended prematurely

    line[length-1] = '\0';  // get rid of the pesky newline
    argv[i] = line;
}

argv[N] = NULL;
user3386109
  • 34,287
  • 7
  • 49
  • 68
0

The way I would approach this problem is by writing a binary file with the following structure:

begin file header:

  0x00 :: 0x03 [  4 bytes] number of entries

for each entry n at offset 0x04 + n * 4:

  0x00 :: 0x03 [  4 bytes] string length of entry (including terminating \0)

end file header

after the header, write all entries as strings to the file, including the terminating \0 byte.

To read this file, I would use fopen, fread, fclose to read the array of offsets from the file, and then I would mmap the file, and transform the array of offsets to an array of pointers into the mmapped region.

Portability Note:

If you want to be able to read the file on one architecture and read it on a different one, you will need to

  • make sure you use fixed width datatypes (e.g. uint32_t, uint64_t)
  • decide on a byte order to avoid endianness issues.

so, say, if you wanted to write a uint32_t to a file, without endianness issues you could use

void
write_uint32 (FILE *f, uint32_t v)
{
  unsigned char out[4] = { 0 };
  out[0] = v & 0xff; v >>= 8;
  out[1] = v & 0xff; v >>= 8;
  out[2] = v & 0xff; v >>= 8;
  out[3] = v
  fwrite(out, 1, sizeof(out), f);
}

and to read the same value

uint32_t
read_uint32 (FILE *f)
{
  unsigned char in[4] = { 0 }
  fread(in, 1, sizeof(in), f);
  return in[3] << 24 | in[2] << 16 | in[1] << 8 | in[0];
}
Andreas Grapentin
  • 5,499
  • 4
  • 39
  • 57
  • The mmap solution seems very elegant, but it is the first time I encounter it so I should probably hit the books before asking any further questions... – yaloner Dec 20 '14 at 12:39
  • This is the part that I find unclear: "and then I would `mmap` the file, and transform the array of offsets to an array of pointers into the mmapped region." How exactly do I do it? – yaloner Dec 20 '14 at 17:04
  • @yaloner if you have an array of offsets into a file, and then `mmap` said file, each offset into the file can be mapped to a pointer into the mmapped region by adding the base address to the region that is returned by mmap. – Andreas Grapentin Dec 20 '14 at 18:44
  • still not sure I understand the process of getting a char** as a result. Do you happen to have an example? – yaloner Dec 20 '14 at 19:07
  • I don't understand your question - transforming an array of `long` of offsets into a file to an array of `char*` of pointers into a memory region should be trivial? pseudocode `for i = 0 to max: chars[i] = longs[i] + base` – Andreas Grapentin Dec 20 '14 at 19:11