]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/volinfo.c
replace remaining %m printf glibc extension with %s strerror(errno)
[netatalk.git] / libatalk / util / volinfo.c
1 /*
2    This program is free software; you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation; either version 2 of the License, or
5    (at your option) any later version.
6
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15
16    .volinfo file handling, command line utilities
17    copyright Bjoern Fernhomberg, 2004
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif /* HAVE_CONFIG_H */
23
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #ifdef STDC_HEADERS
34 #include <string.h>
35 #endif
36 #include <sys/param.h>
37
38 #include <atalk/adouble.h>
39 #include <atalk/util.h>
40 #include <atalk/logger.h>
41 #include <atalk/volinfo.h>
42 #ifdef CNID_DB
43 #include <atalk/cnid.h>
44 #endif /* CNID_DB*/
45
46 #define MAC_CHARSET 0
47 #define VOL_CHARSET 1
48 #define ADOUBLE_VER 2
49 #define CNIDBACKEND 3
50 #define CNIDDBDHOST 4
51 #define CNIDDBDPORT 5
52 #define CNID_DBPATH 6
53 #define VOLUME_OPTS 7
54 #define VOLCASEFOLD 8
55
56 typedef struct _info_option {
57     const char *name;
58     int type;
59 } _info_option;
60
61 static const _info_option info_options[] = {
62     {"MAC_CHARSET", MAC_CHARSET},
63     {"VOL_CHARSET", VOL_CHARSET},
64     {"ADOUBLE_VER", ADOUBLE_VER},
65     {"CNIDBACKEND", CNIDBACKEND},
66     {"CNIDDBDHOST", CNIDDBDHOST},
67     {"CNIDDBDPORT", CNIDDBDPORT},
68     {"CNID_DBPATH", CNID_DBPATH},
69     {"VOLUME_OPTS", VOLUME_OPTS},
70     {"VOLCASEFOLD", VOLCASEFOLD},
71     {NULL, 0}
72 };
73
74 typedef struct _vol_opt_name {
75     const u_int32_t option;
76     const char      *name;
77 } _vol_opt_name;
78
79 static const _vol_opt_name vol_opt_names[] = {
80     {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
81     {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
82     {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
83     {AFPVOL_RO,         "READONLY"},    /* read-only volume */
84     {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
85     {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
86     {AFPVOL_USEDOTS,    "USEDOTS"},     /* use real dots */
87     {AFPVOL_LIMITSIZE,  "LIMITSIZE"},   /* limit size for older macs */
88     {AFPVOL_MAPASCII,   "MAPASCII"},    /* map the ascii range as well */
89     {AFPVOL_DROPBOX,    "DROPBOX"},     /* dropkludge dropbox support */
90     {AFPVOL_NOFILEID,   "NOFILEID"},    /* don't advertise createid resolveid and deleteid calls */
91     {AFPVOL_NOSTAT,     "NOSTAT"},      /* advertise the volume even if we can't stat() it
92                                          * maybe because it will be mounted later in preexec */
93     {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
94     {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
95     {0, NULL}
96 };
97
98 static const _vol_opt_name vol_opt_casefold[] = {
99     {AFPVOL_MTOUUPPER,  "MTOULOWER"},
100     {AFPVOL_MTOULOWER,  "MTOULOWER"},
101     {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
102     {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
103     {0, NULL}
104 };
105
106 static char* find_in_path( char *path, char *subdir, size_t maxlen)
107 {
108     char        *pos;
109     struct stat st;
110
111     strlcat(path, subdir, maxlen);
112     pos = strrchr(path, '/');
113
114     while ( stat(path, &st) != 0) {
115 #ifdef DEBUG
116         fprintf(stderr, "searching in path %s\n", path);
117 #endif
118         path[pos-path]=0;
119         if ((pos = strrchr(path, '/'))) {
120             path[pos-path]=0;
121             strlcat(path, subdir, maxlen);
122         }
123         else {
124             return NULL;
125         }
126     }
127
128     path[pos-path] = '/';
129     path[pos-path+1] = 0;
130 #ifdef DEBUG
131     fprintf(stderr, "%s path %s\n", subdir, path);
132 #endif
133     return path;
134 }
135
136 static char * make_path_absolute(char *path, size_t bufsize)
137 {
138     struct      stat st;
139     char        savecwd[MAXPATHLEN];
140     char        abspath[MAXPATHLEN];
141     char        *p;
142
143     if (stat(path, &st) != 0) {
144         return NULL;
145     }
146
147     strlcpy (abspath, path, sizeof(abspath));
148
149     if (!S_ISDIR(st.st_mode)) {
150         if (NULL == (p=strrchr(abspath, '/')) )
151             return NULL;
152         *p = '\0';
153     }
154
155     getcwd(savecwd, sizeof(savecwd));
156     if ((chdir(abspath)) < 0)   
157         return NULL;
158
159     getcwd(abspath, sizeof(abspath));
160     chdir (savecwd);
161
162     if (strlen(abspath) > bufsize)
163         return NULL;
164
165     strlcpy(path, abspath, bufsize);
166
167     return path;
168 }
169
170 static char * find_volumeroot(char *path, size_t maxlen)
171 {
172     char *volume = make_path_absolute(path, maxlen);
173         
174     if (volume == NULL)
175        return NULL;
176
177     if (NULL == (find_in_path(volume, "/.AppleDesktop", maxlen)) )
178        return NULL;
179
180     return volume;
181 }
182
183 int vol_load_charsets( struct volinfo *vol)
184 {
185     if ( (charset_t) -1 == ( vol->v_maccharset = add_charset(vol->v_maccodepage)) ) {
186         fprintf( stderr, "Setting codepage %s as Mac codepage failed", vol->v_maccodepage);
187         return (-1);
188     }
189
190     if ( (charset_t) -1 == ( vol->v_volcharset = add_charset(vol->v_volcodepage)) ) {
191         fprintf( stderr, "Setting codepage %s as volume codepage failed", vol->v_volcodepage);
192         return (-1);
193     }
194
195     return 0;
196 }
197
198 static int parse_options (char *buf, int *flags, const _vol_opt_name* options)
199 {
200     char *p, *q;
201     const _vol_opt_name *op;
202
203     q = p = buf; 
204
205     while ( *p != '\0') {
206         if (*p == ' ') {
207             *p = '\0';
208             op = options;
209             for (;op->name; op++) {
210                 if ( !strcmp(op->name, q )) {
211                     *flags |= op->option;
212                     break;
213                 }
214             }
215             q = p+1;
216         }
217         p++;
218     }
219
220     return 0;
221
222             
223
224
225 static int parseline ( char *buf, struct volinfo *vol)
226 {
227     char *value;
228     size_t len;
229     int  option=-1;
230     const _info_option  *p  = &info_options[0];
231
232     if (NULL == ( value = strchr(buf, ':')) )
233         return 1;
234
235     *value = '\0';
236     value++;
237
238     if ( 0 == (len = strlen(value)) )
239         return 0;
240
241     if (value[len-1] == '\n')
242         value[len-1] = '\0';
243
244     for (;p->name; p++) {
245         if ( !strcmp(p->name, buf )) {
246             option=p->type;
247             break;
248         }
249     }
250
251     switch (option) {
252       case MAC_CHARSET:
253         if ((vol->v_maccodepage = strdup(value)) == NULL) {
254             fprintf (stderr, "strdup: %s", strerror(errno));
255             return -1;
256         }
257         break;
258       case VOL_CHARSET:
259         if ((vol->v_volcodepage = strdup(value)) == NULL) {
260             fprintf (stderr, "strdup: %s", strerror(errno));
261             return -1;
262         }
263         break;
264       case CNIDBACKEND:
265         if ((vol->v_cnidscheme = strdup(value)) == NULL) {
266             fprintf (stderr, "strdup: %s", strerror(errno));
267             return -1;
268         }
269         break;
270       case CNIDDBDHOST:
271         if ((vol->v_dbd_host = strdup(value)) == NULL) {
272             fprintf (stderr, "strdup: %s", strerror(errno));
273             return -1;
274         }
275         break;
276       case CNIDDBDPORT:
277         vol->v_dbd_port = atoi(value);
278         break;
279       case CNID_DBPATH:
280         if ((vol->v_dbpath = strdup(value)) == NULL) {
281             fprintf (stderr, "strdup: %s", strerror(errno));
282             return -1;
283         }
284         break;
285       case ADOUBLE_VER:
286         if (strcasecmp(value, "v1") == 0) {
287             vol->v_adouble = AD_VERSION1;
288             vol->ad_path = ad_path;
289         }
290 #if AD_VERSION == AD_VERSION2
291         else if (strcasecmp(value, "v2") == 0) {
292             vol->ad_path = ad_path;
293             vol->v_adouble = AD_VERSION2;
294         }
295         else if (strcasecmp(value, "osx") == 0) {
296             vol->v_adouble = AD_VERSION2_OSX;
297             vol->ad_path = ad_path_osx;
298         }
299 #endif
300         else  {
301             fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
302             return -1;
303         }
304         break;
305       case VOLUME_OPTS:
306         parse_options(value, &vol->v_flags, &vol_opt_names[0]);
307         break;
308       case VOLCASEFOLD:
309         parse_options(value, &vol->v_casefold, &vol_opt_casefold[0]);
310         break;
311       default:
312         fprintf (stderr, "unknown volume information: %s, %s", buf, value);
313         return (-1);
314         break;
315     }
316 #ifdef DEBUG
317     printf ("volume information: %s, %s", buf, value);
318 #endif
319         
320     return 0;
321 }
322     
323
324 int loadvolinfo (char *path, struct volinfo *vol)
325 {
326
327     char   volinfofile[MAXPATHLEN];
328     char   buf[MAXPATHLEN];
329     struct flock lock;
330     int    fd;
331     FILE   *fp;
332
333     if ( !path || !vol)
334         return -1;
335
336     memset(vol, 0, sizeof(struct volinfo));
337     strlcpy(volinfofile, path, sizeof(volinfofile));
338
339     /* volinfo file is in .AppleDesktop */ 
340     if ( NULL == find_volumeroot(volinfofile, sizeof(volinfofile)))
341         return -1;
342
343     if ((vol->v_path = strdup(volinfofile)) == NULL ) {
344         fprintf (stderr, "strdup: %s", strerror(errno));
345         return (-1);
346     }
347     strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
348     strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
349
350     /* open the file read only */
351     if ( NULL == (fp = fopen( volinfofile, "r")) )  {
352         fprintf (stderr, "error opening volinfo (%s): %s", volinfofile, strerror(errno));
353         return (-1);
354     }
355     fd = fileno(fp); 
356
357     /* try to get a read lock */ 
358     lock.l_start  = 0;
359     lock.l_whence = SEEK_SET;
360     lock.l_len    = 0;
361     lock.l_type   = F_RDLCK;
362
363     /* wait for read lock */
364     if (fcntl(fd, F_SETLKW, &lock) < 0) {
365         fclose(fp);
366         return (-1);
367     }
368
369     /* read the file */
370     while (NULL != fgets(buf, sizeof(buf), fp)) {
371         parseline(buf, vol);
372     }
373
374     /* unlock file */
375     lock.l_type = F_UNLCK;
376     fcntl(fd, F_SETLK, &lock);
377
378     fclose(fp);
379     return 0;
380 }