Thread: Using the process ID as the name of a file directory

  1. #1
    Registered User
    Join Date
    Jul 2014
    Posts
    15

    Using the process ID as the name of a file directory

    Hello, I need my Unix program to generate a directory with a format like this: "hinesro.<pid>". I have some code that mostly works, except for the directory ends up with a question mark on the end, like this: "hinesro.12345?". I need it to just display the directory without this question mark. Here is my code:

    Code:
    // Using headers sys/types.h, sys/stat.h, unistd.h, and stdio.h
    
    int pid = getpid();
    char prefix[] = "hinesro.";
    char fileName[0];
    sprintf(fileName, "%s%d\n", prefix, pid);
    
    if (stat(fileName, &st) == -1) {
        mkdir(fileName, 0755);
    }
    Thanks in advance.

  2. #2
    Lurker
    Join Date
    Dec 2004
    Posts
    296
    Quote Originally Posted by hinesro View Post
    Hello, I need my Unix program to generate a directory with a format like this: "hinesro.<pid>". I have some code that mostly works, except for the directory ends up with a question mark on the end, like this: "hinesro.12345?". I need it to just display the directory without this question mark. Here is my code:

    Code:
    // Using headers sys/types.h, sys/stat.h, unistd.h, and stdio.h
    
    int pid = getpid();
    char prefix[] = "hinesro.";
    char fileName[0];
    sprintf(fileName, "%s%d\n", prefix, pid);
    
    if (stat(fileName, &st) == -1) {
        mkdir(fileName, 0755);
    }
    Thanks in advance.
    That's because you created a nice little buffer overflow.

    What do you think this

    Code:
    char fileName[0];
    line does?

    Hint, fix so that you have allocated enough room for your string and then use snprintf(3) instead.

    Or you could install that program with root privileges on your machine and give me a shell account and I'll fix it for you... ;-)

  3. #3
    Registered User
    Join Date
    Jul 2014
    Posts
    15
    Thanks, Jimmy. I tried larger buffers and it didn't make a difference. As far as sprintf(3)... what is that 3 parameter and how would my other parameters fit into this call? I'd love to let you fix it but I don't think my University would be too happy

  4. #4
    Registered User
    Join Date
    Jul 2014
    Posts
    15
    I think the problem lies further down where the directory is made. If I do
    Code:
    sprintf(fileName, "%s%d\n", prefix, pid);
    printf("%s", fileName);
    It outputs the correct string without the question mark.

  5. #5
    Lurker
    Join Date
    Dec 2004
    Posts
    296
    Quote Originally Posted by hinesro View Post
    I think the problem lies further down where the directory is made. If I do
    Code:
    sprintf(fileName, "%s%d\n", prefix, pid);
    printf("%s", fileName);
    It outputs the correct string without the question mark.
    You still have the buffer overflow though, writing things out into memory like that is about the worst thing you can do as a programmer.

  6. #6
    Lurker
    Join Date
    Dec 2004
    Posts
    296
    Quote Originally Posted by hinesro View Post
    Thanks, Jimmy. I tried larger buffers and it didn't make a difference. As far as sprintf(3)... what is that 3 parameter and how would my other parameters fit into this call? I'd love to let you fix it but I don't think my University would be too happy
    snprintf(3) is the same as sprintf(3), but the second argument is the size of your buffer. It makes sure you don't write outside your buffer if you use it right.

    Writing outside the buffer like you did is undefined behavior. Anything could happen. It is also a security issue, you should always make sure that you stay inside the buffer.

  7. #7
    Registered User
    Join Date
    Jul 2014
    Posts
    15
    Thanks. I still don't think I'm using it right, even if I set my buffer at 1024 bytes I get the overflow question mark.

    Code:
    char fileName[1024];
    snprintf(fileName, 1024, "%s%d\n", prefix, pid);
    Clearly I'm still doing something wrong. Sorry for my unfamiliarity with C.

  8. #8
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by hinesro View Post
    Code:
    char fileName[1024];
    snprintf(fileName, 1024, "%s%d\n", prefix, pid);
    You're creating a file name with a newline (\n) at end. Whatever you use to look at the directory listing, just shows it as a question mark.

    In Linux, and actually most other POSIXy systems, file and directory names can contain all character values except 0 (\0, the string terminating nul byte) and 47 (/, the separator).

    If prefix is hinesro and pid is 2251, then you can definitely list the file generated by above using e.g.
    Code:
    ls -laF $'hinesro.2251\n'
    using Bash. (The $'string' is just the way you write any string you want in Bash using the same backslash escapes you can use in C.)

    What you want to use is
    Code:
    char fileName[1024];
    int len;
    
    len = snprintf(fileName, sizeof filename, "%s%ld", prefix, (long)pid);
    if (len < 1 || (size_t)len >= sizeof filename) {
        /* Abort; prefix is too long for this buffer! */
        exit(EXIT_FAILURE);
    }

  9. #9
    Registered User
    Join Date
    Jul 2014
    Posts
    15
    Okay, I've gotten it to work by playing around with buffers. I don't fully understand why it works yet, but here is my code:

    Code:
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main(void) {
        int bufSize = 20; 
        int pid = getpid();
        
        char *fileName = malloc(bufSize);
        char *prefix = "hinesro.rooms.";
     
        snprintf(fileName, bufSize, "%s%d", prefix, pid);
        printf("%s\n",fileName);
        
        struct stat st = {0};
        
        if (stat(fileName, &st) == -1) {
            mkdir(fileName, 0755);
        }
        
        return 0; 
    }
    Thanks for all your help! And if I'm still performing any low-level programming blasphemy, feel free to critique

  10. #10
    Registered User
    Join Date
    Jul 2014
    Posts
    15
    Thanks, I can't believe I typed a \n there.

  11. #11
    Registered Superuser nul's Avatar
    Join Date
    Nov 2014
    Location
    Earth
    Posts
    53
    I think a primer on C strings would be a good thing for you to go over, as it seems to be the root of your misunderstanding.

    Strings in C

    Compile the programs and understand what they are doing.

  12. #12
    Lurker
    Join Date
    Dec 2004
    Posts
    296
    Quote Originally Posted by hinesro View Post
    Okay, I've gotten it to work by playing around with buffers. I don't fully understand why it works yet, but here is my code:

    <snip>

    Thanks for all your help! And if I'm still performing any low-level programming blasphemy, feel free to critique
    You should probably use MAXPATHLEN like below, if you are creating filenames.

    Code:
    #include <sys/param.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main(void) {
        int pid = getpid();
    
        char fileName[MAXPATHLEN];
        char *prefix = "hinesro.rooms.";
    
        snprintf(fileName, sizeof(fileName), "%s%d", prefix, pid);
        printf("%s\n",fileName);
    
        struct stat st = {0};
    
        if (stat(fileName, &st) == -1) {
            mkdir(fileName, 0755);
        }
    
        return 0;
    }
    Exactly what are you trying to do though? If you are trying to create a unique temporary file, then I suggest using mkstemp(3) instead.

  13. #13
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Jimmy View Post
    You should probably use MAXPATHLEN like below
    It's not actually a reliable limit. For example, in Linux systems the limit may depend on filesystem. The actual limit for a file in the current directory is pathconf(".", _PC_NAME_MAX);

    On the other hand, if you're using Linux or BSDs, it's easier just to use asprintf():
    Code:
        char *dirname = NULL;
    
        dirname = asprintf("hinesro.rooms.%ld", (long)getpid());
        if (dirname == NULL) {
            fprintf(stderr, "Out of memory.\n");
            exit(EXIT_FAILURE);
        }
    
        if (mkdir(dirname, 0755) == -1) {
            fprintf(stderr, "Cannot create '%s'.\n", dirname);
            exit(EXIT_FAILURE);
        }
    
        fprintf(stdout, "Directory '%s' created successfully.\n", dirname);
        fflush(stdout);
    
        free(dirname);
        dirname = NULL;
    The operating system will complain, if the file/directory name is too long or otherwise unsuitable.

    A directory created and named thus has the property that its creation is atomic even on NFS filesystems, unlike files. That is, if you create such a directory this way, no other machine using the same filesystem has succeeded creating such a directory (unless they or somebody else removed or renamed the directory in between).

    I find the interface to the printf() family of functions a bit annoying, so I often use my own variants using stdargs:
    Code:
    size_t my_print(char **const strptr, size_t *const sizeptr, const char *const format, ...);
    size_t my_cat(char **const strptr, size_t *const sizeptr, const char *const format, ...);
    which basically take the address of the string pointer, the address of the allocated length for the string, and the printf format string and whatever parameters it uses, and returns the length of the resulting (dynamically allocated/reallocated) string, or zero with errno set to nonzero if an actual error occurred; typically ENOMEM. So, basically a cross between snprintf() and getline(). Internally uses strlen(), snprintf() and realloc().

  14. #14
    Lurker
    Join Date
    Dec 2004
    Posts
    296
    Quote Originally Posted by Nominal Animal View Post
    It's not actually a reliable limit. For example, in Linux systems the limit may depend on filesystem. The actual limit for a file in the current directory is pathconf(".", _PC_NAME_MAX);
    You are correct, my bad, I should have read some documentation before posting.

    I still think that the OP is trying to create a temporary file though, so he might actually be looking for mkstemp(3).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 12-06-2012, 02:46 PM
  2. Replies: 6
    Last Post: 04-30-2010, 06:13 PM
  3. file directory.
    By bijan311 in forum C++ Programming
    Replies: 5
    Last Post: 01-21-2010, 05:10 PM
  4. How to tell if its a file or a directory
    By earth_angel in forum C++ Programming
    Replies: 3
    Last Post: 08-19-2005, 11:27 PM
  5. Process sending file descriptors to another process
    By Yasir_Malik in forum C Programming
    Replies: 4
    Last Post: 04-07-2005, 07:36 PM

Tags for this Thread