OSDN Git Service

libparted: gpt: rewrite even a 9-partition-entry table properly
[android-x86/external-parted.git] / m4 / o-direct.m4
1 #serial 2
2 # Find a directory in which a disk-simulating file is usable by parted.
3 # The problem is that on systems supporting O_DIRECT, open with O_DIRECT
4 # fails for some file system types (e.g., tmpfs on linux-2.6.21).
5
6 # Copyright (C) 2007-2012 Free Software Foundation, Inc.
7 # This file is free software; the Free Software Foundation
8 # gives unlimited permission to copy and/or distribute it,
9 # with or without modifications, as long as this notice is preserved.
10
11 # From Jim Meyering.
12
13 # Set PARTED_USABLE_TEST_DIR to the name of the first usable directory
14 # from the list below.  If none is usable, set it to the empty string.
15 # Consider $TMPDIR only if it specifies an absolute name, and that
16 # name contains no shell meta-character.  Likewise for $HOME.
17
18 # This code is pretty picky.  The chosen partition must support aligned reads
19 # and writes in blocks of size 512B and 4KB to a file descriptor opened with
20 # O_RDWR|O_DIRECT.  Reiserfs doesn't support 512-byte reads.  On tmpfs,
21 # the open fails.
22
23 # The candidate directories:
24 #   . $HOME $TMPDIR /tmp /var/tmp /dev/shm
25 AC_DEFUN([parted_FIND_USABLE_TEST_DIR],
26 [
27   AC_CACHE_CHECK([for a usable (O_DIRECT-supporting) temporary dir],
28     [parted_cv_func_open_O_DIRECT_temp_dir],
29     [
30       # First of all, if there is no O_DIRECT definition, use ".",
31       # and skip the run-test.
32       AC_EGREP_CPP([frobnozzle], [
33 #include <fcntl.h>
34 #ifdef O_DIRECT
35 frobnozzle
36 #endif
37                   ], pe_have_O_DIRECT=yes, pe_have_O_DIRECT=no)
38       if test $pe_have_O_DIRECT = no; then
39           # With no O_DIRECT definition, "." is fine.
40           pe_cand_dirs=.
41       else
42           pe_cand_dirs=.
43           for pe_dir in "$HOME" "$TMPDIR"; do
44               case $pe_dir in
45               /tmp) ;;
46               /var/tmp) ;;
47               /dev/shm) ;;
48               /*) case $pe_dir in
49                   # Accept $HOME or $TMP only if the value is nice and boring.
50                   *[^/a-zA-Z0-9_.-]*) ;;
51                   *) pe_cand_dirs="$pe_cand_dirs $pe_dir";;
52                   esac
53               esac
54           done
55
56           case $PARTED_TMPDIR in
57               *[^/a-zA-Z0-9_.-]*) ;;
58               *) pe_cand_dirs="$PARTED_TMPDIR $pe_cand_dirs";;
59           esac
60
61           # This is the list of candidate directories.
62           pe_cand_dirs="$pe_cand_dirs /tmp /var/tmp /dev/shm"
63
64           PARTED_CANDIDATE_DIRS=$pe_cand_dirs
65           export PARTED_CANDIDATE_DIRS
66
67           AC_RUN_IFELSE(
68             [AC_LANG_SOURCE(
69               [[
70 #include <sys/types.h>
71 #include <sys/stat.h>
72 #include <fcntl.h>
73 #include <unistd.h>
74 #include <stdlib.h>
75 #include <string.h>
76
77 #define MAX_LOGICAL_BLOCK_SIZE 4096
78 static char g_buf[2 * MAX_LOGICAL_BLOCK_SIZE];
79
80 static inline void *
81 ptr_align (void const *ptr, size_t alignment)
82 {
83   char const *p0 = ptr;
84   char const *p1 = p0 + alignment - 1;
85   return (void *) (p1 - (size_t) p1 % alignment);
86 }
87
88 static int
89 create_input_file (char const *file, char const *buf, size_t n_bytes)
90 {
91   int fd = open (file, O_CREAT | O_WRONLY, 0600);
92   if (fd < 0)
93     return 1;
94   if (write (fd, buf, n_bytes) != n_bytes)
95     {
96       close (fd);
97       return 1;
98     }
99   return !! close (fd);
100 }
101
102 static int
103 try_o_direct (char const *file, size_t block_size)
104 {
105   char *p = ptr_align (g_buf, MAX_LOGICAL_BLOCK_SIZE);
106   int fd;
107
108   if (!(p + block_size < g_buf + sizeof g_buf))
109     return 4;
110
111   fd = open (file, O_RDWR | O_DIRECT);
112   if (fd < 0)
113     return 1;
114
115   if (write (fd, p, block_size) != block_size)
116     return 1;
117
118   if (lseek (fd, 0, SEEK_SET) != 0)
119     return 1;
120
121   if (read (fd, p, block_size) != block_size)
122     return 1;
123
124   return !! close (fd);
125 }
126
127 #undef stpcpy
128 #define stpcpy(a, b) my_stpcpy (a, b)
129 static char *
130 my_stpcpy (char *dest, const char *src)
131 {
132   char *d = dest;
133   const char *s = src;
134   do *d++ = *s; while (*s++ != '\0');
135   return d - 1;
136 }
137
138 /* The base name of the file we'll create in the mkdtemp-returned
139    temporary directory.  */
140 #define BASENAME "x"
141
142 /* Return 0 upon failure, else the 1-based index of the first
143    useful directory name from PARTED_CANDIDATE_DIRS.  */
144 int
145 main ()
146 {
147   char const *env_dirs;
148   char *dirs;
149   char *dir;
150   unsigned int n;
151   int found = 0;
152   size_t dirs_len;
153
154   if ((env_dirs = getenv ("PARTED_CANDIDATE_DIRS")) == NULL)
155     return 0;
156
157   dirs_len = strlen (env_dirs);
158   if ((dirs = strndup (env_dirs, dirs_len)) == NULL)
159     return 0;
160   dir = dirs;
161
162   for (n = 1; ; n++)
163     {
164       size_t dirname_len;
165       char *space;
166
167       /* Skip any leading spaces.  */
168       while (*dir == ' ')
169         ++dir;
170
171       space = strchr (dir, ' ');
172       if (space)
173         {
174           *space = '\0';
175           dirname_len = space - dir;
176         }
177       else
178         {
179           dirname_len = strlen (dir);
180         }
181
182       if (dirname_len != 0)
183         {
184           /* Create an mkdtemp template starting with dir.  */
185           char *tmp;
186           char *endp;
187           char const *base = "partedOD.XXXXXX";
188           /* Allocate enough space not just for the dir name, but
189              also for the name of the file to create within it.  */
190           char *template = malloc (dirname_len + 1 + strlen (base)
191                                    + 1 + strlen (BASENAME) + 1);
192           if (template != NULL
193               && (endp = stpcpy (stpcpy (stpcpy (template, dir), "/"), base))
194               && (tmp = mkdtemp (template)) != NULL)
195             {
196               /* Append "/BASENAME" to create the file name.  */
197               stpcpy (stpcpy (endp, "/"), BASENAME);
198
199               if (create_input_file (tmp, g_buf, sizeof g_buf) == 0
200                   && try_o_direct (tmp, 512) == 0
201                   && try_o_direct (tmp, MAX_LOGICAL_BLOCK_SIZE) == 0)
202                 found = 1;
203
204               unlink (tmp); /* ignore failure */
205               *endp = '\0';
206               rmdir (tmp); /* ignore failure */
207             }
208           free (template);
209         }
210
211       if (found)
212         break;
213
214       dir += dirname_len + 1;
215       if (dirs + dirs_len < dir)
216         {
217           n = 0;
218           break;
219         }
220     }
221   free (dirs);
222
223   return n;
224 }
225               ]])],
226             # If the above program exits with status 0, then
227             # there it found no useful directory.  Use ".".
228             [parted_cv_func_open_O_DIRECT_temp_dir=.],
229
230             # It found one.  The exit status is an index into the list.
231             # We also run this code when the program fails to compile or
232             # to link, as will happen on systems without a mkdtemp function.
233             [pe_err=$?; set _ $pe_cand_dirs; shift
234               eval parted_cv_func_open_O_DIRECT_temp_dir='$'$pe_err],
235
236             # When cross-compiling, use ".".
237             [parted_cv_func_open_O_DIRECT_temp_dir=.]
238             )
239       fi
240     ])
241   PARTED_USABLE_TEST_DIR=$parted_cv_func_open_O_DIRECT_temp_dir
242   AC_SUBST([PARTED_USABLE_TEST_DIR])
243
244   # If the result is ".", don't cache it.  The next user of
245   # the cache may well be running from a different file system.
246   dnl Here, I'm using "$as_unset", which is a non-published (i.e., internal)
247   dnl part of autoconf, but we don't expect its name to change any time soon.
248   dnl and by then, it'll probably be ok to use "unset" all by itself.
249   if test "$parted_cv_func_open_O_DIRECT_temp_dir" = .; then
250     $as_unset parted_cv_func_open_O_DIRECT_temp_dir
251   fi
252 ])