/*
* FsTabEntry.vala
*
* Copyright 2012-2018 Tony George <teejeetech@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/
using TeeJee.Logging;
using TeeJee.FileSystem;
using TeeJee.JsonHelper;
using TeeJee.ProcessHelper;
using TeeJee.GtkHelper;
using TeeJee.System;
using TeeJee.Misc;
public class FsTabEntry : GLib.Object{
public bool is_comment = false;
public bool is_empty_line = false;
public string device_string = "";
public string mount_point = "";
public string type = "";
public string options = "defaults";
public string dump = "0";
public string pass = "0";
public string line = "";
public string device_uuid {
owned get{
if (device_string.down().has_prefix("uuid=")){
return device_string.replace("\"","").replace("'","").split("=")[1];
}
else{
return "";
}
}
set {
device_string = "UUID=%s".printf(value);
}
}
public static Gee.ArrayList<FsTabEntry> read_file(string file_path){
var list = new Gee.ArrayList<FsTabEntry>();
if (!file_exists(file_path)){ return list; }
string text = file_read(file_path);
string[] lines = text.split("\n");
foreach(string line in lines){
var entry = new FsTabEntry();
list.add(entry);
entry.is_comment = line.strip().has_prefix("#");
entry.is_empty_line = (line.strip().length == 0);
if (entry.is_comment){
entry.line = line;
}
else if (entry.is_empty_line){
entry.line = "";
}
else{
entry.line = line;
string[] parts = line.replace("\t"," ").split(" ");
int part_num = -1;
foreach(string part in parts){
if (part.strip().length == 0) { continue; }
switch (++part_num){
case 0:
entry.device_string = part.strip();
break;
case 1:
entry.mount_point = part.strip();
break;
case 2:
entry.type = part.strip();
break;
case 3:
entry.options = part.strip();
break;
case 4:
entry.dump = part.strip();
break;
case 5:
entry.pass = part.strip();
break;
}
}
}
}
return list;
}
public static string write_file(
Gee.ArrayList<FsTabEntry> entries, string file_path,
bool keep_comments_and_empty_lines = false){
string text = "";
if (!keep_comments_and_empty_lines){
text += "# <file system> <mount point> <type> <options> <dump> <pass>\n\n";
}
foreach(var entry in entries){
if (entry.is_comment || entry.is_empty_line){
if (keep_comments_and_empty_lines){
text += "%s\n".printf(entry.line);
}
}
else {
text += "%s\t%s\t%s\t%s\t%s\t%s\n".printf(
entry.device_string, entry.mount_point, entry.type,
entry.options, entry.dump, entry.pass);
}
}
// sort the entries based on mount path
// this is required to ensure that base paths are mounted before child paths
entries.sort((a, b)=>{
return strcmp(a.mount_point, b.mount_point);
});
if (file_exists(file_path)){
file_delete(file_path);
}
file_write(file_path, text);
return text;
}
public string subvolume_name(){
if (options.down().contains("subvol=")){
string txt = options.split("subvol=")[1].split(",")[0].strip();
if (txt.has_prefix("/") && (txt.split("/").length == 2)){
txt = txt.split("/")[1];
}
return txt;
}
else{
return "";
}
}
public bool is_for_system_directory(){
if (mount_point.has_prefix("/mnt")
|| mount_point.has_prefix("/mount")
|| mount_point.has_prefix("/sdcard")
|| mount_point.has_prefix("/cdrom")
|| mount_point.has_prefix("/media")
|| (mount_point == "none")
|| !mount_point.has_prefix("/")
|| (!device_string.has_prefix("/dev/") && !device_string.down().has_prefix("uuid="))){
return false;
}
else{
return true;
}
}
public static FsTabEntry? find_entry_by_mount_point(Gee.ArrayList<FsTabEntry> entries, string mount_path){
foreach(var entry in entries){
if (entry.mount_point == mount_path){
return entry;
}
}
return null;
}
public Device? resolve_device(Gee.ArrayList<CryptTabEntry> crypttab, Gtk.Window? parent_window){
Device dev_fstab = null;
if (device_uuid.length > 0){
dev_fstab = Device.get_device_by_uuid(device_uuid);
}
else{
dev_fstab = Device.get_device_by_name(device_string);
}
if (dev_fstab == null){
/*
Check if the device mentioned in fstab entry is a mapped device.
If it is, then try finding the parent device which may be available on the current system.
Prompt user to unlock it if found.
Note:
Mapped name may be different on running system, or it may be same.
Since it is not reliable, we will try to identify the parent instead of the mapped device.
*/
if (device_string.has_prefix("/dev/mapper/")){
string mapped_name = device_string.replace("/dev/mapper/","");
foreach(var item in crypttab){
if (item.mapped_name == mapped_name){
// we found the entry for the mapped device
device_string = item.device_string;
if (device_uuid.length > 0){
// we have the parent's uuid. get the luks device and prompt user to unlock it.
var dev_luks = Device.get_device_by_uuid(device_uuid);
if (dev_luks != null){
string msg_out, msg_err;
var dev_unlocked = Device.luks_unlock(
dev_luks, "", "", parent_window, out msg_out, out msg_err);
if (dev_unlocked != null){
dev_fstab = dev_unlocked;
}
else{
dev_fstab = dev_luks; // map to parent
}
}
}
else{
// nothing to do: we don't have the parent's uuid
}
break;
}
}
}
}
return dev_fstab;
}
public void append_option(string option){
if (!options.contains(option)){
options += ",%s".printf(option);
}
if(options.has_prefix(",")){
options = options[1:options.length];
}
options = options.strip();
}
public void remove_option(string option){
options = options.replace(option,"").strip();
if(options.has_prefix(",")){
options = options[1:options.length];
}
if (options.has_suffix(",")){
options = options[0:options.length - 1];
}
options = options.strip();
}
}