Translated using Weblate (Japanese)
[oweals/luci.git] / modules / luci-mod-system / htdocs / luci-static / resources / view / system / mounts.js
1 'use strict';
2 'require view';
3 'require fs';
4 'require ui';
5 'require uci';
6 'require rpc';
7 'require form';
8
9 var callBlockDevices, callMountPoints, callBlockDetect;
10
11 callBlockDevices = rpc.declare({
12         object: 'luci',
13         method: 'getBlockDevices',
14         expect: { '': {} }
15 });
16
17 callMountPoints = rpc.declare({
18         object: 'luci',
19         method: 'getMountPoints',
20         expect: { result: [] }
21 });
22
23 callBlockDetect = rpc.declare({
24         object: 'luci',
25         method: 'setBlockDetect',
26         expect: { result: false }
27 });
28
29 function device_textvalue(devices, section_id) {
30         var v = (uci.get('fstab', section_id, 'uuid') || '').toLowerCase(),
31             e = Object.keys(devices).filter(function(dev) { return (devices[dev].uuid || '-').toLowerCase() == v })[0];
32
33         if (v) {
34                 this.section.devices[section_id] = devices[e];
35
36                 if (e && devices[e].size)
37                         return E('span', 'UUID: %h (%s, %1024.2mB)'.format(v, devices[e].dev, devices[e].size));
38                 else if (e)
39                         return E('span', 'UUID: %h (%s)'.format(v, devices[e].dev));
40                 else
41                         return E('span', 'UUID: %h (<em>%s</em>)'.format(v, _('not present')));
42         }
43
44         v = uci.get('fstab', section_id, 'label');
45         e = Object.keys(devices).filter(function(dev) { return devices[dev].label == v })[0];
46
47         if (v) {
48                 this.section.devices[section_id] = this.section.devices[section_id] || devices[e];
49
50                 if (e && devices[e].size)
51                         return E('span', 'Label: %h (%s, %1024.2mB)'.format(v, devices[e].dev, devices[e].size));
52                 else if (e)
53                         return E('span', 'Label: %h (%s)'.format(v, devices[e].dev));
54                 else
55                         return E('span', 'Label: %h (<em>%s</em>)'.format(v, _('not present')));
56         }
57
58         v = uci.get('fstab', section_id, 'device');
59         e = Object.keys(devices).filter(function(dev) { return devices[dev].dev == v })[0];
60
61         if (v) {
62                 this.section.devices[section_id] = this.section.devices[section_id] || devices[e];
63
64                 if (e && devices[e].size)
65                         return E('span', '%h (%1024.2mB)'.format(v, devices[e].size));
66                 else if (e)
67                         return E('span', '%h'.format(v));
68                 else
69                         return E('span', '%h (<em>%s</em>)'.format(v, _('not present')));
70         }
71 }
72
73 return view.extend({
74         handleDetect: function(m, ev) {
75                 return callBlockDetect()
76                         .then(L.bind(uci.unload, uci, 'fstab'))
77                         .then(L.bind(m.render, m));
78         },
79
80         handleMountAll: function(m, ev) {
81                 return fs.exec('/sbin/block', ['mount'])
82                         .then(function(res) {
83                                 if (res.code != 0)
84                                         ui.addNotification(null, E('p', _('The <em>block mount</em> command failed with code %d').format(res.code)));
85                         })
86                         .then(L.bind(uci.unload, uci, 'fstab'))
87                         .then(L.bind(m.render, m));
88         },
89
90         handleUmount: function(m, path, ev) {
91                 return fs.exec('/bin/umount', [path])
92                         .then(L.bind(uci.unload, uci, 'fstab'))
93                         .then(L.bind(m.render, m))
94                         .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
95         },
96
97         load: function() {
98                 return Promise.all([
99                         callBlockDevices(),
100                         fs.lines('/proc/filesystems'),
101                         fs.lines('/etc/filesystems'),
102                         L.resolveDefault(fs.stat('/usr/sbin/e2fsck'), null),
103                         L.resolveDefault(fs.stat('/usr/sbin/fsck.f2fs'), null),
104                         L.resolveDefault(fs.stat('/usr/sbin/fsck.fat'), null),
105                         L.resolveDefault(fs.stat('/usr/bin/btrfsck'), null),
106                         L.resolveDefault(fs.stat('/usr/bin/ntfsfix'), null),
107                         uci.load('fstab')
108                 ]);
109         },
110
111         render: function(results) {
112                 var devices = results[0],
113                     procfs = results[1],
114                     etcfs = results[2],
115                     triggers = {},
116                     trigger, m, s, o;
117
118                 var fsck = {
119                         ext2: results[3],
120                         ext3: results[3],
121                         ext4: results[3],
122                         f2fs: results[4],
123                         vfat: results[5],
124                         btrfs: results[6],
125                         ntfs: results[7]
126                 };
127
128                 var filesystems = {};
129
130                 for (var i = 0; i < procfs.length; i++)
131                         if (procfs[i].match(/\S/) && !procfs[i].match(/^nodev\t/))
132                                 filesystems[procfs[i].trim()] = true;
133
134                 for (var i = 0; i < etcfs.length; i++)
135                         if (etcfs[i].match(/\S/))
136                                 filesystems[etcfs[i].trim()] = true;
137
138                 filesystems = Object.keys(filesystems).sort();
139
140
141                 if (!uci.sections('fstab', 'global').length)
142                         uci.add('fstab', 'global');
143
144                 m = new form.Map('fstab', _('Mount Points'));
145
146                 s = m.section(form.TypedSection, 'global', _('Global Settings'));
147                 s.addremove = false;
148                 s.anonymous = true;
149
150                 o = s.option(form.Button, '_detect', _('Generate Config'), _('Find all currently attached filesystems and swap and replace configuration with defaults based on what was detected'));
151                 o.onclick = this.handleDetect.bind(this, m);
152                 o.inputstyle = 'reload';
153
154                 o = s.option(form.Button, '_mountall', _('Mount attached devices'), _('Attempt to enable configured mount points for attached devices'));
155                 o.onclick = this.handleMountAll.bind(this, m);
156                 o.inputstyle = 'reload';
157
158                 o = s.option(form.Flag, 'anon_swap', _('Anonymous Swap'), _('Mount swap not specifically configured'));
159                 o.default = o.disabled;
160                 o.rmempty = false;
161
162                 o = s.option(form.Flag, 'anon_mount', _('Anonymous Mount'), _('Mount filesystems not specifically configured'));
163                 o.default = o.disabled;
164                 o.rmempty = false;
165
166                 o = s.option(form.Flag, 'auto_swap', _('Automount Swap'), _('Automatically mount swap on hotplug'));
167                 o.default = o.enabled;
168                 o.rmempty = false;
169
170                 o = s.option(form.Flag, 'auto_mount', _('Automount Filesystem'), _('Automatically mount filesystems on hotplug'));
171                 o.default = o.enabled;
172                 o.rmempty = false;
173
174                 o = s.option(form.Flag, 'check_fs', _('Check filesystems before mount'), _('Automatically check filesystem for errors before mounting'));
175                 o.default = o.disabled;
176                 o.rmempty = false;
177
178
179                 // Mount status table
180                 o = s.option(form.DummyValue, '_mtab');
181
182                 o.load = function(section_id) {
183                         return callMountPoints().then(L.bind(function(mounts) {
184                                 this.mounts = mounts;
185                         }, this));
186                 };
187
188                 o.render = L.bind(function(view, section_id) {
189                         var table = E('div', { 'class': 'table' }, [
190                                 E('div', { 'class': 'tr table-titles' }, [
191                                         E('div', { 'class': 'th' }, _('Filesystem')),
192                                         E('div', { 'class': 'th' }, _('Mount Point')),
193                                         E('div', { 'class': 'th center' }, _('Available')),
194                                         E('div', { 'class': 'th center' }, _('Used')),
195                                         E('div', { 'class': 'th' }, _('Unmount'))
196                                 ])
197                         ]);
198
199                         var rows = [];
200
201                         for (var i = 0; i < this.mounts.length; i++) {
202                                 var used = this.mounts[i].size - this.mounts[i].free,
203                                     umount = true;
204
205                                 if (/^\/(overlay|rom|tmp(?:\/.+)?|dev(?:\/.+)?|)$/.test(this.mounts[i].mount))
206                                         umount = false;
207
208                                 rows.push([
209                                         this.mounts[i].device,
210                                         this.mounts[i].mount,
211                                         '%1024.2mB / %1024.2mB'.format(this.mounts[i].avail, this.mounts[i].size),
212                                         '%.2f%% (%1024.2mB)'.format(100 / this.mounts[i].size * used, used),
213                                         umount ? E('button', {
214                                                 'class': 'btn cbi-button-remove',
215                                                 'click': ui.createHandlerFn(view, 'handleUmount', m, this.mounts[i].mount),
216                                                 'disabled': this.map.readonly || null
217                                         }, [ _('Unmount') ]) : '-'
218                                 ]);
219                         }
220
221                         cbi_update_table(table, rows, E('em', _('Unable to obtain mount information')));
222
223                         return E([], [ E('h3', _('Mounted file systems')), table ]);
224                 }, o, this);
225
226
227                 // Mounts
228                 s = m.section(form.GridSection, 'mount', _('Mount Points'), _('Mount Points define at which point a memory device will be attached to the filesystem'));
229                 s.modaltitle = _('Mount Points - Mount Entry');
230                 s.anonymous = true;
231                 s.addremove = true;
232                 s.sortable  = true;
233                 s.devices   = {};
234
235                 s.renderHeaderRows = function(/* ... */) {
236                         var trEls = form.GridSection.prototype.renderHeaderRows.apply(this, arguments);
237                         return trEls.childNodes[0];
238                 }
239
240                 s.tab('general', _('General Settings'));
241                 s.tab('advanced', _('Advanced Settings'));
242
243                 o = s.taboption('general', form.Flag, 'enabled', _('Enabled'));
244                 o.rmempty  = false;
245                 o.editable = true;
246
247                 o = s.taboption('general', form.DummyValue, '_device', _('Device'));
248                 o.rawhtml   = true;
249                 o.modalonly = false;
250                 o.write = function() {};
251                 o.remove = function() {};
252                 o.textvalue = device_textvalue.bind(o, devices);
253
254                 o = s.taboption('general', form.Value, 'uuid', _('UUID'), _('If specified, mount the device by its UUID instead of a fixed device node'));
255                 o.modalonly = true;
256                 o.value('', _('-- match by uuid --'));
257
258                 var devs = Object.keys(devices).sort();
259                 for (var i = 0; i < devs.length; i++) {
260                         var dev = devices[devs[i]];
261                         if (dev.uuid && dev.size)
262                                 o.value(dev.uuid, '%s (%s, %1024.2mB)'.format(dev.uuid, dev.dev, dev.size));
263                         else if (dev.uuid)
264                                 o.value(dev.uuid, '%s (%s)'.format(dev.uuid, dev.dev));
265                 }
266
267                 o = s.taboption('general', form.Value, 'label', _('Label'), _('If specified, mount the device by the partition label instead of a fixed device node'));
268                 o.modalonly = true;
269                 o.depends('uuid', '');
270                 o.value('', _('-- match by label --'));
271
272                 for (var i = 0; i < devs.length; i++) {
273                         var dev = devices[devs[i]];
274                         if (dev.label && dev.size)
275                                 o.value(dev.label, '%s (%s, %1024.2mB)'.format(dev.label, dev.dev, dev.size));
276                         else if (dev.label)
277                                 o.value(dev.label, '%s (%s)'.format(dev.label, dev.dev));
278                 }
279
280                 o = s.taboption('general', form.Value, 'device', _('Device'), _('The device file of the memory or partition (<abbr title="for example">e.g.</abbr> <code>/dev/sda1</code>)'));
281                 o.modalonly = true;
282                 o.depends({ uuid: '', label: '' });
283
284                 for (var i = 0; i < devs.length; i++) {
285                         var dev = devices[devs[i]];
286                         if (dev.size)
287                                 o.value(dev.dev, '%s (%1024.2mB)'.format(dev.dev, dev.size));
288                         else
289                                 o.value(dev.dev);
290                 }
291
292                 o = s.taboption('general', form.Value, 'target', _('Mount point'), _('Specifies the directory the device is attached to'));
293                 o.value('/', _('Use as root filesystem (/)'));
294                 o.value('/overlay', _('Use as external overlay (/overlay)'));
295                 o.rmempty = false;
296
297                 o = s.taboption('general', form.DummyValue, '__notice', _('Root preparation'));
298                 o.depends('target', '/');
299                 o.modalonly = true;
300                 o.rawhtml = true;
301                 o.default = '' +
302                         '<p>%s</p>'.format(_('Make sure to clone the root filesystem using something like the commands below:')) +
303                         '<pre>' +
304                                 'mkdir -p /tmp/introot\n' +
305                                 'mkdir -p /tmp/extroot\n' +
306                                 'mount --bind / /tmp/introot\n' +
307                                 'mount /dev/sda1 /tmp/extroot\n' +
308                                 'tar -C /tmp/introot -cvf - . | tar -C /tmp/extroot -xf -\n' +
309                                 'umount /tmp/introot\n' +
310                                 'umount /tmp/extroot\n' +
311                         '</pre>'
312                 ;
313
314                 o = s.taboption('advanced', form.ListValue, 'fstype', _('Filesystem'));
315
316                 o.textvalue = function(section_id) {
317                         var dev = this.section.devices[section_id],
318                             text = this.cfgvalue(section_id) || 'auto';
319
320                         if (dev && dev.type && dev.type != text)
321                                 text += ' (%s)'.format(dev.type);
322
323                         return text;
324                 };
325
326                 o.value('', 'auto');
327
328                 for (var i = 0; i < filesystems.length; i++)
329                         o.value(filesystems[i]);
330
331                 o = s.taboption('advanced', form.Value, 'options', _('Mount options'), _('See "mount" manpage for details'));
332                 o.textvalue = function(section_id) { return this.cfgvalue(section_id) || 'defaults' };
333                 o.placeholder = 'defaults';
334
335                 s.taboption('advanced', form.Flag, 'enabled_fsck', _('Run filesystem check'), _('Run a filesystem check before mounting the device'));
336
337
338                 // Swaps
339                 s = m.section(form.GridSection, 'swap', _('SWAP'), _('If your physical memory is insufficient unused data can be temporarily swapped to a swap-device resulting in a higher amount of usable <abbr title="Random Access Memory">RAM</abbr>. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the <abbr title="Random Access Memory">RAM</abbr>.'));
340                 s.modaltitle = _('Mount Points - Swap Entry');
341                 s.anonymous = true;
342                 s.addremove = true;
343                 s.sortable  = true;
344                 s.devices   = {};
345
346                 s.renderHeaderRows = function(/* ... */) {
347                         var trEls = form.GridSection.prototype.renderHeaderRows.apply(this, arguments);
348                         trEls.childNodes[0].childNodes[1].style.width = '90%';
349                         return trEls.childNodes[0];
350                 }
351
352                 o = s.option(form.Flag, 'enabled', _('Enabled'));
353                 o.rmempty  = false;
354                 o.editable = true;
355
356                 o = s.option(form.DummyValue, '_device', _('Device'));
357                 o.modalonly = false;
358                 o.textvalue = device_textvalue.bind(o, devices);
359
360                 o = s.option(form.Value, 'uuid', _('UUID'), _('If specified, mount the device by its UUID instead of a fixed device node'));
361                 o.modalonly = true;
362                 o.value('', _('-- match by uuid --'));
363
364                 var devs = Object.keys(devices).sort();
365                 for (var i = 0; i < devs.length; i++) {
366                         var dev = devices[devs[i]];
367                         if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/))
368                                 continue;
369
370                         if (dev.uuid && dev.size)
371                                 o.value(dev.uuid, '%s (%s, %1024.2mB)'.format(dev.uuid, dev.dev, dev.size));
372                         else if (dev.uuid)
373                                 o.value(dev.uuid, '%s (%s)'.format(dev.uuid, dev.dev));
374                 }
375
376                 o = s.option(form.Value, 'label', _('Label'), _('If specified, mount the device by the partition label instead of a fixed device node'));
377                 o.modalonly = true;
378                 o.depends('uuid', '');
379                 o.value('', _('-- match by label --'));
380
381                 for (var i = 0; i < devs.length; i++) {
382                         var dev = devices[devs[i]];
383                         if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/))
384                                 continue;
385
386                         if (dev.label && dev.size)
387                                 o.value(dev.label, '%s (%s, %1024.2mB)'.format(dev.label, dev.dev, dev.size));
388                         else if (dev.label)
389                                 o.value(dev.label, '%s (%s)'.format(dev.label, dev.dev));
390                 }
391
392                 o = s.option(form.Value, 'device', _('Device'), _('The device file of the memory or partition (<abbr title="for example">e.g.</abbr> <code>/dev/sda1</code>)'));
393                 o.modalonly = true;
394                 o.depends({ uuid: '', label: '' });
395
396                 for (var i = 0; i < devs.length; i++) {
397                         var dev = devices[devs[i]];
398                         if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/))
399                                 continue;
400
401                         if (dev.size)
402                                 o.value(dev.dev, '%s (%1024.2mB)'.format(dev.dev, dev.size));
403                         else
404                                 o.value(dev.dev);
405                 }
406
407                 return m.render();
408         }
409 });