]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/scan.c
Backport from BEE
[bacula/bacula] / bacula / src / stored / scan.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *
18  *   scan.c scan a directory (on a removable file) for a valid
19  *      Volume name. If found, open the file for append.
20  *
21  *    Kern Sibbald, MMVI
22  *
23  */
24
25 #include "bacula.h"
26 #include "stored.h"
27
28 /* Forward referenced functions */
29 static bool is_volume_name_legal(char *name);
30
31
32 bool DEVICE::scan_dir_for_volume(DCR *dcr)
33 {
34    DIR* dp;
35    struct dirent *entry, *result;
36    int name_max;
37    char *mount_point;
38    VOLUME_CAT_INFO dcrVolCatInfo, devVolCatInfo;
39    char VolumeName[MAX_NAME_LENGTH];
40    struct stat statp;
41    bool found = false;
42    POOL_MEM fname(PM_FNAME);
43    bool need_slash = false;
44    int len;
45
46    dcrVolCatInfo = dcr->VolCatInfo;     /* structure assignment */
47    devVolCatInfo = VolCatInfo;          /* structure assignment */
48    bstrncpy(VolumeName, dcr->VolumeName, sizeof(VolumeName));
49
50    name_max = pathconf(".", _PC_NAME_MAX);
51    if (name_max < 1024) {
52       name_max = 1024;
53    }
54
55    if (device->mount_point) {
56       mount_point = device->mount_point;
57    } else {
58       mount_point = device->device_name;
59    }
60
61    if (!(dp = opendir(mount_point))) {
62       berrno be;
63       dev_errno = errno;
64       Dmsg3(29, "scan_dir_for_vol: failed to open dir %s (dev=%s), ERR=%s\n",
65             mount_point, print_name(), be.bstrerror());
66       goto get_out;
67    }
68
69    len = strlen(mount_point);
70    if (len > 0) {
71       need_slash = !IsPathSeparator(mount_point[len - 1]);
72    }
73    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
74    for ( ;; ) {
75       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
76          dev_errno = EIO;
77          Dmsg2(129, "scan_dir_for_vol: failed to find suitable file in dir %s (dev=%s)\n",
78                mount_point, print_name());
79          break;
80       }
81       if (strcmp(result->d_name, ".") == 0 ||
82           strcmp(result->d_name, "..") == 0) {
83          continue;
84       }
85
86       if (!is_volume_name_legal(result->d_name)) {
87          continue;
88       }
89       pm_strcpy(fname, mount_point);
90       if (need_slash) {
91          pm_strcat(fname, "/");
92       }
93       pm_strcat(fname, result->d_name);
94       if (lstat(fname.c_str(), &statp) != 0 ||
95           !S_ISREG(statp.st_mode)) {
96          continue;                 /* ignore directories & special files */
97       }
98
99       /*
100        * OK, we got a different volume mounted. First save the
101        *  requested Volume info (dcr) structure, then query if
102        *  this volume is really OK. If not, put back the desired
103        *  volume name, mark it not in changer and continue.
104        */
105       /* Check if this is a valid Volume in the pool */
106       bstrncpy(dcr->VolumeName, result->d_name, sizeof(dcr->VolumeName));
107       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
108          continue;
109       }
110       /* This was not the volume we expected, but it is OK with
111        * the Director, so use it.
112        */
113       VolCatInfo = dcr->VolCatInfo;       /* structure assignment */
114       found = true;
115       break;                /* got a Volume */
116    }
117    free(entry);
118    closedir(dp);
119
120 get_out:
121    if (!found) {
122       /* Restore VolumeName we really wanted */
123       bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName));
124       dcr->VolCatInfo = dcrVolCatInfo;     /* structure assignment */
125       VolCatInfo = devVolCatInfo;          /* structure assignment */
126    }
127    Dsm_check(100);
128    return found;
129 }
130
131 /*
132  * Check if the Volume name has legal characters
133  * If ua is non-NULL send the message
134  */
135 static bool is_volume_name_legal(char *name)
136 {
137    int len;
138    const char *p;
139    const char *accept = ":.-_";
140
141    /* Restrict the characters permitted in the Volume name */
142    for (p=name; *p; p++) {
143       if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
144          continue;
145       }
146       return false;
147    }
148    len = strlen(name);
149    if (len >= MAX_NAME_LENGTH) {
150       return false;
151    }
152    if (len == 0) {
153       return false;
154    }
155    return true;
156 }