1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2006-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2016-2016 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Kern Sibbald, MMVI
24 */
25 /**
26 * scan.c scan a directory (on a removable file) for a valid
27 * Volume name. If found, open the file for append.
28 */
29
30 #include "include/bareos.h"
31 #include "stored/stored.h"
32 #include "lib/berrno.h"
33
34 namespace storagedaemon {
35
36 /* Forward referenced functions */
37 static bool IsVolumeNameLegal(char* name);
38
39
ScanDirForVolume(DeviceControlRecord * dcr)40 bool Device::ScanDirForVolume(DeviceControlRecord* dcr)
41 {
42 DIR* dp;
43 struct dirent* result;
44 #ifdef USE_READDIR_R
45 struct dirent* entry;
46 #endif
47 int name_max;
48 char* mount_point;
49 VolumeCatalogInfo dcrVolCatInfo, devVolCatInfo;
50 char VolumeName[MAX_NAME_LENGTH];
51 struct stat statp;
52 bool found = false;
53 PoolMem fname(PM_FNAME);
54 bool need_slash = false;
55 int len;
56
57 dcrVolCatInfo = dcr->VolCatInfo; /* structure assignment */
58 devVolCatInfo = VolCatInfo; /* structure assignment */
59 bstrncpy(VolumeName, dcr->VolumeName, sizeof(VolumeName));
60
61 name_max = pathconf(".", _PC_NAME_MAX);
62 if (name_max < 1024) { name_max = 1024; }
63
64 if (device->mount_point) {
65 mount_point = device->mount_point;
66 } else {
67 mount_point = device->device_name;
68 }
69
70 if (!(dp = opendir(mount_point))) {
71 BErrNo be;
72 dev_errno = errno;
73 Dmsg3(29, "scan_dir_for_vol: failed to open dir %s (dev=%s), ERR=%s\n",
74 mount_point, print_name(), be.bstrerror());
75 goto get_out;
76 }
77
78 len = strlen(mount_point);
79 if (len > 0) { need_slash = !IsPathSeparator(mount_point[len - 1]); }
80
81 #ifdef USE_READDIR_R
82 entry = (struct dirent*)malloc(sizeof(struct dirent) + name_max + 1000);
83 while (1) {
84 if ((Readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
85 #else
86 while (1) {
87 result = readdir(dp);
88 if (result == NULL) {
89 #endif
90 dev_errno = EIO;
91 Dmsg2(
92 129,
93 "scan_dir_for_vol: failed to find suitable file in dir %s (dev=%s)\n",
94 mount_point, print_name());
95 break;
96 }
97 if (bstrcmp(result->d_name, ".") || bstrcmp(result->d_name, "..")) {
98 continue;
99 }
100
101 if (!IsVolumeNameLegal(result->d_name)) { continue; }
102 PmStrcpy(fname, mount_point);
103 if (need_slash) { PmStrcat(fname, "/"); }
104 PmStrcat(fname, result->d_name);
105 if (lstat(fname.c_str(), &statp) != 0 || !S_ISREG(statp.st_mode)) {
106 continue; /* ignore directories & special files */
107 }
108
109 /*
110 * OK, we got a different volume mounted. First save the
111 * requested Volume info (dcr) structure, then query if
112 * this volume is really OK. If not, put back the desired
113 * volume name, mark it not in changer and continue.
114 */
115 /* Check if this is a valid Volume in the pool */
116 bstrncpy(dcr->VolumeName, result->d_name, sizeof(dcr->VolumeName));
117 if (!dcr->DirGetVolumeInfo(GET_VOL_INFO_FOR_WRITE)) { continue; }
118 /* This was not the volume we expected, but it is OK with
119 * the Director, so use it.
120 */
121 VolCatInfo = dcr->VolCatInfo; /* structure assignment */
122 found = true;
123 break; /* got a Volume */
124 }
125 #ifdef USE_READDIR_R
126 free(entry);
127 #endif
128 closedir(dp);
129
130 get_out:
131 if (!found) {
132 /* Restore VolumeName we really wanted */
133 bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName));
134 dcr->VolCatInfo = dcrVolCatInfo; /* structure assignment */
135 VolCatInfo = devVolCatInfo; /* structure assignment */
136 }
137 return found;
138 }
139
140 /**
141 * Check if the Volume name has legal characters
142 * If ua is non-NULL send the message
143 */
144 static bool IsVolumeNameLegal(char* name)
145 {
146 int len;
147 const char* p;
148 const char* accept = ":.-_/";
149
150 if (name[0] == '/') { return false; }
151 /* Restrict the characters permitted in the Volume name */
152 for (p = name; *p; p++) {
153 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
154 continue;
155 }
156 return false;
157 }
158 len = strlen(name);
159 if (len >= MAX_NAME_LENGTH) { return false; }
160 if (len == 0) { return false; }
161 return true;
162 }
163
164 } /* namespace storagedaemon */
165