1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <string.h>
21 #include <sys/types.h>
22 #if defined(__FreeBSD__) || defined(__DragonFly__)
23 #include <sys/param.h>
24 #include <sys/ucred.h>
25 #include <sys/mount.h>
26 #else
27 #include <mntent.h>
28 #include <sys/statfs.h>
29 #endif
30 
31 #include <math.h>
32 
33 #include <cairo-dock.h>
34 
35 #include "applet-struct.h"
36 #include "applet-disk-usage.h"
37 
38 
cd_shortcuts_get_fs_stat(const gchar * cDiskURI,CDDiskUsage * pDiskUsage)39 void cd_shortcuts_get_fs_stat (const gchar *cDiskURI, CDDiskUsage *pDiskUsage)
40 {
41 	static struct statfs sts;
42 	const gchar *cMountPath = (strncmp (cDiskURI, "file://", 7) == 0 ? cDiskURI + 7 : cDiskURI);
43 
44 	if (statfs (cMountPath, &sts) == 0)
45 	{
46 		if (pDiskUsage->iType == 0)
47 			pDiskUsage->iType = sts.f_type;
48 		pDiskUsage->iAvail = (long long)sts.f_bavail * sts.f_bsize;  // Blocs libres pour utilisateurs
49 		pDiskUsage->iFree  = (long long)sts.f_bfree  * sts.f_bsize;  // Blocs libres
50 		pDiskUsage->iTotal = (long long)sts.f_blocks * sts.f_bsize;  // Nombre total de blocs
51 		pDiskUsage->iUsed  = pDiskUsage->iTotal - pDiskUsage->iAvail;
52 		//g_print ("%lld / %lld\n", pDiskUsage->iAvail, pDiskUsage->iTotal);
53 	}
54 	else
55 	{
56 		pDiskUsage->iTotal = 0;
57 		pDiskUsage->iAvail = 0;
58 	}
59 }
60 
_display_disk_usage(Icon * pIcon,GldiContainer * pContainer,CDDiskUsage * pDiskUsage,GldiModuleInstance * myApplet)61 static void _display_disk_usage (Icon *pIcon, GldiContainer *pContainer, CDDiskUsage *pDiskUsage, GldiModuleInstance *myApplet)
62 {
63 	double fValue;
64 	if (pDiskUsage->iTotal != 0 && (pDiskUsage->iPrevAvail == -1 || (double)fabs (pDiskUsage->iPrevAvail - pDiskUsage->iAvail) / pDiskUsage->iTotal > .001))  // .1 % d'ecart ou info encore non renseignee.
65 	{
66 		pDiskUsage->iPrevAvail = pDiskUsage->iAvail;
67 		switch (myConfig.iDisplayType)
68 		{
69 			case CD_SHOW_FREE_SPACE :
70 				fValue = (double) pDiskUsage->iAvail / pDiskUsage->iTotal;
71 				cairo_dock_set_size_as_quick_info (pIcon, pDiskUsage->iAvail);
72 			break ;
73 			case CD_SHOW_USED_SPACE :
74 				fValue = (double) pDiskUsage->iUsed / pDiskUsage->iTotal;
75 				cairo_dock_set_size_as_quick_info (pIcon, pDiskUsage->iUsed);
76 			break ;
77 			case CD_SHOW_FREE_SPACE_PERCENT :
78 				fValue = (double) pDiskUsage->iAvail / pDiskUsage->iTotal;
79 				gldi_icon_set_quick_info_printf (pIcon, "%.1f%%", 100.*fValue);
80 			break ;
81 			case CD_SHOW_USED_SPACE_PERCENT :
82 				fValue = (double) pDiskUsage->iUsed / pDiskUsage->iTotal;
83 				gldi_icon_set_quick_info_printf (pIcon, "%.1f%%", 100.*fValue);
84 			break ;
85 			default:
86 				fValue = CAIRO_DATA_RENDERER_UNDEF_VALUE;
87 			break;
88 		}
89 
90 		if (myConfig.bDrawBar)
91 			cairo_dock_render_new_data_on_icon (pIcon, pContainer, myDrawContext, &fValue);
92 		else  // just trigger the redraw for the quick-info
93 			cairo_dock_redraw_icon (pIcon);
94 	}
95 }
96 
cd_shortcuts_display_disk_usage(Icon * pIcon,GldiModuleInstance * myApplet)97 void cd_shortcuts_display_disk_usage (Icon *pIcon, GldiModuleInstance *myApplet)
98 {
99 	GldiContainer *pContainer = pIcon->pContainer;
100 	g_return_if_fail (pContainer != NULL);
101 	CDDiskUsage *pDiskUsage = CD_APPLET_GET_MY_ICON_DATA (pIcon);
102 	g_return_if_fail (pDiskUsage != NULL);
103 	_display_disk_usage (pIcon, pContainer, pDiskUsage, myApplet);
104 }
105 
_cd_shortcuts_update_disk_usage(GldiModuleInstance * myApplet)106 static gboolean _cd_shortcuts_update_disk_usage (GldiModuleInstance *myApplet)
107 {
108 	CD_APPLET_ENTER;
109 	GldiContainer *pContainer = CD_APPLET_MY_ICONS_LIST_CONTAINER;
110 	CDDiskUsage *pDiskUsage;
111 	Icon *pIcon;
112 	GList *ic;
113 	GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
114 	for (ic = pIconsList; ic != NULL; ic = ic->next)
115 	{
116 		pIcon = ic->data;
117 		if (pIcon->cCommand != NULL)  // skip separators
118 		{
119 			// get data
120 			pDiskUsage = CD_APPLET_GET_MY_ICON_DATA (pIcon);
121 			if (pDiskUsage == NULL)  // not a drive (eg, network or bookmark)
122 			{
123 				/* Drives are listed first, and Home is always the first
124 				 * bookmark (and the only one to have disk data), so if we got a
125 				 * bookmark with no disk data, we can quit the loop.
126 				 */
127 				if (pIcon->iGroup >= (CairoDockIconGroup) CD_BOOKMARK_GROUP)
128 					break;
129 				else
130 					continue;
131 			}
132 			cd_shortcuts_get_fs_stat (pIcon->cCommand, pDiskUsage);
133 
134 			// draw
135 			_display_disk_usage (pIcon, pContainer, pDiskUsage, myApplet);
136 		}
137 	}
138 
139 	if (myDesklet)
140 		cairo_dock_redraw_container (myContainer);
141 
142 	CD_APPLET_LEAVE (TRUE);
143 }
144 
145 
cd_shortcuts_launch_disk_periodic_task(GldiModuleInstance * myApplet)146 void cd_shortcuts_launch_disk_periodic_task (GldiModuleInstance *myApplet)
147 {
148 	if (myConfig.iDisplayType != CD_SHOW_NOTHING && myConfig.bListDrives)
149 	{
150 		if (myData.pDiskTask == NULL)
151 		{
152 			myData.pDiskTask = gldi_task_new (myConfig.iCheckInterval,
153 				(GldiGetDataAsyncFunc) NULL,
154 				(GldiUpdateSyncFunc) _cd_shortcuts_update_disk_usage,
155 				myApplet);
156 		}
157 		gldi_task_launch (myData.pDiskTask);
158 	}
159 }
160 
cd_shortcuts_free_disk_periodic_task(GldiModuleInstance * myApplet)161 void cd_shortcuts_free_disk_periodic_task (GldiModuleInstance *myApplet)
162 {
163 	gldi_task_free (myData.pDiskTask);
164 	myData.pDiskTask = NULL;
165 }
166 
167 
168 
_cd_shortcuts_get_fs_info(const gchar * cDiskURI,GString * sInfo)169 static void _cd_shortcuts_get_fs_info (const gchar *cDiskURI, GString *sInfo)
170 {
171 	const gchar *cMountPath = (strncmp (cDiskURI, "file://", 7) == 0 ? cDiskURI + 7 : cDiskURI);
172 
173 	#if defined(__FreeBSD__) || defined(__DragonFly__)
174 	struct statfs *me;
175 	int i, count = getfsstat(me, NULL, MNT_WAIT);
176 	if (count>0)
177 	{
178 		for (i=0; i<count; i++)
179 		{
180 			if (me->f_mntonname && strcmp (me->f_mntonname, cMountPath) == 0)
181 			{
182 				g_string_append_printf (sInfo, "%s %s\n%s %s\n%s %s\n%s %s",
183 					D_("Mount point:"), me->f_mntonname,
184 					D_("File system:"), me->f_mntfromname,
185 					D_("Device:"), me->f_fstypename,
186 #ifdef __DragonFly__
187 					D_("Mount options:"), "N/I");
188 #else
189 					D_("Mount options:"), me->f_charspare);
190 #endif
191 				// if (me->mnt_freq != 0)
192 				// g_string_append_printf (sInfo, "\nBackup frequency : %d days", me->mnt_freq);
193 				break ;
194 			}
195 		}
196 	}
197 	else
198 	{
199 		cd_warning ("error getfsstat...");
200 		return ;
201 	}
202 	#else
203 	struct mntent *me;
204 	FILE *mtab = setmntent ("/etc/mtab", "r");
205 	if (mtab == NULL)
206 	{
207 		cd_warning ("couldn't open /etc/mtab");
208 		return ;
209 	}
210 
211 	while ((me = getmntent (mtab)) != NULL)
212 	{
213 		if (me->mnt_dir && strcmp (me->mnt_dir, cMountPath) == 0)
214 		{
215 			g_string_append_printf (sInfo, "%s %s\n%s %s\n%s %s\n%s %s",
216 				D_("Mount point:"), me->mnt_dir,
217 				D_("File system:"), me->mnt_type,
218 				D_("Device:"), me->mnt_fsname,
219 				D_("Mount options:"), me->mnt_opts);
220 			if (me->mnt_freq != 0)
221 				g_string_append_printf (sInfo, "\n%s %d %s",
222 					D_("Backup frequency:"), me->mnt_freq, D_("days"));
223 			break ;
224 		}
225 	}
226 
227 	endmntent (mtab);
228 	#endif
229 }
230 
cd_shortcuts_get_disk_info(const gchar * cDiskURI,const gchar * cDiskName)231 gchar *cd_shortcuts_get_disk_info (const gchar *cDiskURI, const gchar *cDiskName)
232 {
233 	GString *sInfo = g_string_new ("");
234 	// on recupere les infos de taille.
235 	CDDiskUsage diskUsage;
236 	memset (&diskUsage, 0, sizeof (CDDiskUsage));
237 	cd_shortcuts_get_fs_stat (cDiskURI, &diskUsage);
238 
239 	// on recupere les infos du file system.
240 	if (diskUsage.iTotal > 0)  // info are available
241 	{
242 		gchar *cFreeSpace = cairo_dock_get_human_readable_size (diskUsage.iAvail);
243 		gchar *cCapacity = cairo_dock_get_human_readable_size (diskUsage.iTotal);
244 		g_string_append_printf (sInfo, "%s %s\n%s %s\n%s %s\n", // added '\n' -> _cd_shortcuts_get_fs_info
245 			D_("Name:"), cDiskName,
246 			D_("Capacity:"), cCapacity,
247 			D_("Free space:"), cFreeSpace);
248 		g_free (cCapacity);
249 		g_free (cFreeSpace);
250 		_cd_shortcuts_get_fs_info (cDiskURI, sInfo);
251 	}
252 	else if (strncmp (cDiskURI, "computer:/", 10) == 0 || strncmp (cDiskURI, "file:/", 6) == 0)  // no info on a local mount point => it's not mounted
253 	{
254 		g_string_append_printf (sInfo, "%s %s\n%s",
255 			D_("Name:"), cDiskName, D_("Not mounted"));
256 	}
257 	else  // not a local mount point => a distant connection
258 	{
259 		g_string_append_printf (sInfo, "%s %s\n%s %s",
260 			D_("Name:"), cDiskName,
261 			D_("URL:"), cDiskURI);
262 	}
263 
264 	gchar *cInfo = sInfo->str;
265 	g_string_free (sInfo, FALSE);
266 	return cInfo;
267 }
268