Trattazione di linkat e openat con O_TMPFILE, con programmi di test ed
[gapil.git] / sources / test_linkat.c
1 /* test_linkat.c
2  * 
3  * Copyright (C) 2019 Simone Piccardi
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /****************************************************************
20  *
21  * Program test_linkat.c: 
22  * Program to test use of linkat with an O_TMPFILE or linking another file 
23  * using AT_EMPTY_PATH or AT_SYMLINK_FOLLOW on /proc/self/fd/N
24  * giving the option to wait to remove source file
25  *
26  * Author: Simone Piccardi
27  * Oct. 2018
28  *
29  * Usage: testlinkat -h give all info's
30  *
31  ****************************************************************/
32 /* 
33  * Include needed headers
34  */
35 #define _GNU_SOURCE
36 #include <errno.h>       /* error definitions and routines */ 
37 #include <stdlib.h>      /* C standard library */
38 #include <unistd.h>      /* unix standard library */
39 #include <stdio.h>       /* standard I/O library */
40 #include <string.h>      /* C strings library */
41 #include <limits.h>
42 #include <libgen.h>      /* needed for dirname e basename */
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <fcntl.h>
46
47
48 /* Help printing routine */
49 void usage(void);
50
51 int main(int argc, char *argv[])
52 {
53 /* 
54  * Variables definition  
55  */
56     int i;
57     int wait=0;
58     char *srcfile = NULL;
59     /*
60      * Input section: decode command line parameters 
61      * Use getopt function
62      */
63     opterr = 0;  /* don't want writing to stderr */
64     while ( (i = getopt(argc, argv, "hw:f:")) != -1) {
65         switch (i) {
66         /* 
67          * Handling options 
68          */ 
69         case 'h':   /* help option */
70             printf("Wrong -h option use\n");
71             usage();
72             return -1;
73             break;
74         case 'w':      /* time to wait in s */
75             wait = strtol(optarg, NULL, 10);    /* convert input */
76             break;
77         case 'f':      /* using a source file */
78             srcfile = optarg;
79             break;
80         case '?':   /* unrecognized options */
81             printf("Unrecognized options -%c\n",optopt);
82             usage();
83         default:    /* should not reached */
84             usage();
85         }
86     }
87     /* ***********************************************************
88      * 
89      *           Options processing completed
90      *
91      *                Main code beginning
92      * 
93      * ***********************************************************/
94     /* There must be 1 remaing parameters */
95     if ( (argc-optind) != 1 )  {
96         printf("From %d arguments, removed %d options\n", argc, optind);
97         usage();
98     }
99     char *path, *dir, *file;
100     char pattern[] = "prova prova prova\n";
101     char outbuff[2048];
102     path = strdup(argv[optind]);
103     file = basename(argv[optind]);
104     dir = dirname(argv[optind]);
105     printf("Destination on dir %s file: %s\n            with path: %s\n",
106            dir, file, path);
107     int fd, newfd;
108     if ( ! srcfile ) {
109         // temp file with O_TMPFILE
110         fd = open(dir, O_TMPFILE|O_RDWR,S_IRUSR|S_IWUSR);
111         if ( fd <= 0 )
112             perror("cannot open TMPFILE");
113         if ( (i = write(fd, pattern, sizeof(pattern))) < 0 )   
114             perror("cannot write on TMPFILE");
115         else
116             printf("saved %d chars on fd %d\n", i, fd);
117     } else {
118         // user provided source
119         printf("source file is %s\n", srcfile);
120         if ( (fd = open(srcfile, O_RDONLY)) < 0 ) {
121             perror("cannot open source");
122             exit(1);
123         }
124         printf("waiting %d second to remove the file\n", wait);
125         sleep(wait);
126     }
127     newfd = open(dir, O_PATH|O_RDWR);
128     int err;
129     err = linkat(fd, "", newfd, file, AT_EMPTY_PATH);
130     if ( err < 0  ) {
131         perror("error on creating TMPFILE with AT_EMPTY_PATH");
132         printf("cannot link fd %d on fd %d/%s with AT_EMPTY_PATH\n",
133                fd, newfd, file);
134         char fdpath[PATH_MAX];
135         snprintf(fdpath, PATH_MAX, "/proc/self/fd/%d", fd);
136         printf("Attempt to use AT_SYMLINK_FOLLOW with path %s\n", fdpath);
137         err = linkat(AT_FDCWD, fdpath, newfd, file, AT_SYMLINK_FOLLOW);
138         if ( err < 0  ) {
139             perror("still error creating TMPFILE");
140             exit(1);
141         } else {
142             printf("Success, fd %d on fd %d/%s created\n", fd, newfd, file);
143         }
144         if ( fchmodat(newfd, file,S_IRUSR|S_IWUSR,0) < 0 )
145             perror("Cannot change permission to new file");
146     }
147     free(path);
148     return 0;
149 }
150 /*
151  * routine to print usage info and exit
152  */
153 void usage(void) {
154     printf("Program testlinkat : test linkat for a file  \n");
155     printf("Create a link to a tempfile or a link to -f indicated file");
156     printf("Usage:\n");
157     printf("  testlinkat [-h] destfilepathname \n");
158     printf("  -h           print this help\n");
159     printf("  -w [N]       wait N seconds\n");
160     printf("  -f [file]    use file as source\n");
161     
162     exit(1);
163 }
164