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