1 /* devices.c */
2
3 /*
4 Copyright (C) 2005 Jean-Baptiste jb_dul@yahoo.com
5 Copyright (C) 2005-2008 Fabian Nowak timystery@arcor.de.
6 Copyright (C) 2009,2012 Landry Breuil <landry@xfce.org>
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later
12 version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <fstab.h>
29 #include <glib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 /* WEXITSTATUS */
34 #include <sys/types.h>
35 #ifdef HAVE_GETMNTENT
36 #include <mntent.h>
37 #include <sys/vfs.h>
38 #elif defined (HAVE_GETMNTINFO)
39 #include <sys/param.h>
40 #include <sys/mount.h>
41 #else
42 #error no getmntent/getmntinfo ? send patches !
43 #endif
44
45 #include <libxfce4panel/xfce-panel-plugin.h>
46 #include <libxfce4util/libxfce4util.h>
47 #include <libxfce4ui/libxfce4ui.h>
48
49 #include "devices.h"
50
51 /* declare that one here to appease -Werror */
52 t_mount_info * mount_info_new_from_stat (struct statfs * pstatfs, char * mnt_type, char * mnt_dir);
53
54 #define KB 1024
55 #define MB 1048576
56 #define GB 1073741824
57
58 #define MTAB "/etc/mtab"
59
60
61 /**
62 * Return a string containing a size expressed in KB, MB or GB and the unit
63 * it is expressed in.
64 *
65 * @param size: Size in bytes
66 * @return Formatted output, e.g. "1.5 GB"
67 */
68 char *
get_size_human_readable(float size)69 get_size_human_readable (float size)
70 {
71 if (size < KB) return g_strdup_printf (_("%.1f B"), size);
72 if (size < MB) return g_strdup_printf (_("%.1f KB"), size/KB);
73 if (size < GB) return g_strdup_printf (_("%.1f MB"), size/MB);
74 return g_strdup_printf (_("%.1f GB"), size/GB);
75 }
76
77
78 void
mount_info_print(t_mount_info * mount_info)79 mount_info_print(t_mount_info * mount_info)
80 {
81 if (mount_info != NULL)
82 {
83 printf (_("size: %g\n"), mount_info->size);
84 printf (_("used size: %g\n") ,mount_info->used);
85 printf (_("available size: %g\n"), mount_info->avail);
86 printf (_("percentage used: %d\n"), mount_info->percent);
87 printf (_("file system type: %s\n"), mount_info->type);
88 printf (_("actual mount point: %s\n"), mount_info->mounted_on);
89 }
90 return ;
91 }
92
93
94 t_mount_info *
mount_info_new(float size,float used,float avail,unsigned int percent,char * type,char * mounted_on)95 mount_info_new (float size, float used, float avail,
96 unsigned int percent, char * type, char * mounted_on)
97 {
98 t_mount_info * mount_info;
99
100 /* check superfluous, as already done in mount_info_new_from_stat */
101 /* if ( type != NULL && mounted_on != NULL ) // && size != 0 )
102 { */
103 mount_info = g_new0(t_mount_info,1);
104 mount_info->size = size;
105 mount_info->used = used;
106 mount_info->avail = avail;
107 mount_info->percent = percent;
108 mount_info->type = g_strdup(type);
109 mount_info->mounted_on = g_strdup(mounted_on);
110 return mount_info;
111 /* }
112 return NULL; */
113 }
114
115
116 /**
117 * Creates a new struct t_mount_info from a struct statfs data.
118 */
119 t_mount_info *
mount_info_new_from_stat(struct statfs * pstatfs,char * mnt_type,char * mnt_dir)120 mount_info_new_from_stat (struct statfs * pstatfs,
121 char * mnt_type,
122 char * mnt_dir)
123 {
124 t_mount_info * mount_info ;
125 float size; /* total size of device */
126 float used; /* used size of device */
127 float avail; /* Available size of device */
128 unsigned int percent ; /* percentage used */
129
130 TRACE("Entering mount_info_new_from_stat");
131
132 if (pstatfs!=NULL && mnt_type!=NULL && mnt_dir!=NULL)
133 {
134 /* compute sizes in bytes */
135 size = (float) pstatfs->f_bsize * (float) pstatfs->f_blocks;
136 used = (float) pstatfs->f_bsize
137 * ( (float) pstatfs->f_blocks - (float) pstatfs->f_bfree );
138 avail = (float) pstatfs->f_bsize * (float) pstatfs->f_bavail;
139 percent = ( (float) pstatfs->f_blocks - (float) pstatfs->f_bavail ) * 100
140 / (float) pstatfs->f_blocks;
141
142 /* create new t_mount_info */
143 mount_info = mount_info_new (size, used, avail, percent, mnt_type,
144 mnt_dir);
145 return mount_info;
146 }
147 TRACE("Leaving mount_info_new_from_stat with NULL");
148 return NULL;
149
150 }
151
152
153 void
mount_info_free(t_mount_info ** mount_info)154 mount_info_free(t_mount_info * * mount_info)
155 {
156 if (*mount_info != NULL)
157 {
158 g_free ((*mount_info)->mounted_on);
159 g_free ((*mount_info)->type);
160 g_free ((*mount_info));
161 *mount_info = NULL ;
162 }
163 return;
164 }
165
166
167 void
disk_print(t_disk * pdisk)168 disk_print (t_disk * pdisk)
169 {
170 if (pdisk != NULL)
171 {
172 printf (_("disk: %s\n"),pdisk->device);
173 printf (_("mount point: %s\n"), pdisk->mount_point);
174
175 if (pdisk->mount_info != NULL)
176 mount_info_print (pdisk->mount_info);
177 else printf (_("not mounted\n"));
178 }
179 return;
180 }
181
182 char *
shorten_disk_name(const char * dev,guint len)183 shorten_disk_name (const char *dev, guint len)
184 {
185 char *r, *lastchars, *firstchars;
186 if (strncmp(dev, "LABEL=", 6)==0)
187 {
188 r = g_strdup(dev+6*sizeof(char));
189 }
190 else if (strlen(dev)>len) // len cannot be set lower than 9
191 {
192 // we want at least 5 characters at the end so that trimmed UUIDs are still readable
193 lastchars = (char *) (dev + strlen(dev) - 5);
194 firstchars = malloc ((len-5-3)*sizeof(char)); // 3 additional ones for the three dots
195 firstchars = strndup(dev, len-5-3);
196 r = malloc ((len+1)*sizeof(char));
197 snprintf (r, len+1, "%s...%s", firstchars, lastchars);
198 }
199 else
200 r = g_strdup (dev);
201
202 return r;
203 }
204
205 t_disk *
disk_new(const char * dev,const char * mountpoint,gint len)206 disk_new (const char * dev, const char * mountpoint, gint len)
207 {
208 t_disk * pdisk;
209
210 TRACE("Entering disk_new");
211
212 if ( dev != NULL && mountpoint != NULL)
213 {
214 pdisk = g_new0 (t_disk,1);
215 pdisk->device_short = shorten_disk_name (dev, len);
216 pdisk->device = g_strdup(dev);
217 pdisk->mount_point = g_strdup (mountpoint);
218 pdisk->mount_info = NULL;
219
220 return pdisk ;
221 }
222
223 TRACE("Leaving disk_new with NULL");
224 return NULL;
225 }
226
227
228 void
disk_free(t_disk ** pdisk)229 disk_free(t_disk **pdisk)
230 {
231 if (*pdisk !=NULL)
232 {
233 g_free ((*pdisk)->device);
234 g_free ((*pdisk)->device_short);
235 g_free ((*pdisk)->mount_point);
236 mount_info_free (&((*pdisk)->mount_info));
237 g_free(*pdisk);
238 *pdisk = NULL;
239 }
240 return;
241 }
242
243
244 /**
245 * Return exit status of the mount command
246 */
247 void
disk_mount(t_disk * pdisk,char * on_mount_cmd,char * mount_command,gboolean eject)248 disk_mount (t_disk *pdisk, char *on_mount_cmd, char* mount_command, gboolean eject)
249 {
250 gchar *tmp = NULL, *cmd = NULL;
251 gchar *output = NULL, *erroutput = NULL;
252 int exit_status = 0;
253 GError *error = NULL;
254 gboolean val;
255
256 if (pdisk != NULL)
257 {
258 DBG("disk_mount: dev=%s, mountpoint=%s, mount_command=%s, on_mount_cmd=%s, eject=%d", pdisk->device, pdisk->mount_point, mount_command, on_mount_cmd, eject);
259 if (eject) {
260 #ifdef __OpenBSD__
261 /* hack: on OpenBSD, eject(1) -t expects cd0/cd1 (or rcd0c/rcd1c), if passed /dev/cdXa it will spit 'No medium found' */
262 tmp = g_strstr_len(pdisk->device, strlen(pdisk->device), "/dev/cd");
263 if (tmp) {
264 cmd = g_strconcat ("eject -t cd", tmp + 7, NULL);
265 /* remove chars after cdX */
266 cmd[12] = '\0';
267 tmp = NULL;
268 }
269 else
270 cmd = g_strconcat ("eject -t ", pdisk->device, NULL);
271 #else
272 cmd = g_strconcat ("eject -t ", pdisk->device, NULL);
273 #endif
274 val = g_spawn_command_line_sync (cmd, &output, &erroutput, &exit_status, &error);
275 DBG("cmd: '%s', returned %d, exit_status=%d", cmd, val, exit_status);
276 if (val == FALSE || exit_status != 0)
277 goto out;
278 g_free(cmd);
279 cmd = NULL;
280 }
281 deviceprintf (&tmp, mount_command, pdisk->device);
282 mountpointprintf (&cmd, tmp, pdisk->mount_point);
283 /* cmd contains mount_command device mount_point */
284 val = g_spawn_command_line_sync (cmd, &output, &erroutput, &exit_status, &error);
285 DBG("cmd: '%s', returned %d, exit_status=%d", cmd, val, exit_status);
286 if (val == FALSE || exit_status != 0)
287 {
288 /* show error message if smth failed */
289 //xfce_dialog_show_error (NULL, error, "%s %s %d, %s %s", _("Mount Plugin:\n\nError executing command."),
290 //_("Return value:"), WEXITSTATUS(exit_status), _("\nError was:"), erroutput);
291 //xfce_dialog_show_error (NULL, error, _("Failed to mount device \"%s\"."), pdisk->device);
292 xfce_message_dialog (NULL,
293 _("Xfce 4 Mount Plugin"),
294 "dialog-error",
295 _("Failed to mount device:"),
296 pdisk->device,
297 "gtk-ok",
298 GTK_RESPONSE_OK,
299 NULL);
300 goto out;
301 }
302
303 if (on_mount_cmd != NULL && strlen(on_mount_cmd)!=0) {
304 g_free(tmp);
305 tmp = NULL;
306 g_free(cmd);
307 cmd = NULL;
308 deviceprintf(&tmp, on_mount_cmd, pdisk->device);
309 mountpointprintf(&cmd, tmp, pdisk->mount_point);
310 val = g_spawn_command_line_async (cmd, &error);
311 DBG("cmd: '%s', returned %d", cmd, val);
312 /* show error message if smth failed */
313 if (val == FALSE)
314 //xfce_dialog_show_error (NULL, error, _("Error executing on-mount command \"%s\"."), on_mount_cmd);
315 xfce_message_dialog (NULL,
316 _("Xfce 4 Mount Plugin"),
317 "dialog-error",
318 _("Error executing on-mount command:"),
319 on_mount_cmd,
320 "gtk-ok",
321 GTK_RESPONSE_OK,
322 NULL);
323
324 }
325 out:
326 g_free(cmd);
327 if (tmp)
328 g_free(tmp);
329 }
330 }
331
332
333 /**
334 * Return exit status of the umount command.
335 */
336 void
disk_umount(t_disk * pdisk,char * umount_command,gboolean show_message_dialog,gboolean eject)337 disk_umount (t_disk *pdisk, char* umount_command, gboolean show_message_dialog, gboolean eject)
338 {
339 gchar *tmp = NULL, *cmd = NULL;
340 gchar *output = NULL, *erroutput = NULL;
341 int exit_status = 0;
342 GError *error = NULL;
343 gboolean val;
344
345 if (pdisk != NULL)
346 {
347
348 DBG("disk_umount: dev=%s, mountpoint=%s, umount_command=%s, show_message_dialog=%d, eject=%d, type=%s", pdisk->device, pdisk->mount_point, umount_command, show_message_dialog, eject, pdisk->mount_info->type);
349 #if !defined(__FreeBSD__) || !defined(__DragonFly__)
350 if (strstr(pdisk->mount_info->type, "fuse."))
351 deviceprintf(&tmp, "fusermount -u %m", pdisk->device);
352 else
353 #endif
354 deviceprintf(&tmp, umount_command, pdisk->device);
355
356 mountpointprintf(&cmd, tmp, pdisk->mount_point);
357 /* cmd contains umount_command device mount_point */
358 val = g_spawn_command_line_sync (cmd, &output, &erroutput, &exit_status, &error);
359 DBG("cmd: '%s', returned %d, exit_status=%d", cmd, val, exit_status);
360 if (val == FALSE || exit_status != 0)
361 goto out;
362
363 if (eject) {
364 g_free(cmd);
365 cmd = NULL;
366 cmd = g_strconcat ("eject ", pdisk->device, NULL);
367 val = g_spawn_command_line_sync (cmd, &output, &erroutput, &exit_status, &error);
368 DBG("cmd: '%s', returned %d, exit_status=%d", cmd, val, exit_status);
369 }
370
371 out:
372 g_free(cmd);
373 if (tmp)
374 g_free(tmp);
375 /* show error message if smth failed */
376 if (val == FALSE || exit_status != 0)
377 //xfce_dialog_show_error (NULL, error, "%s %s %d, %s %s", _("Mount Plugin: Error executing command."),
378 //_("Returned"), WEXITSTATUS(exit_status), _("error was"), erroutput);
379 //xfce_dialog_show_error (NULL, error, _("Failed to umount device \"%s\"."), pdisk->device);
380 xfce_message_dialog (NULL,
381 _("Xfce 4 Mount Plugin"),
382 "dialog-error",
383 _("Failed to umount device:"),
384 pdisk->device,
385 "gtk-ok",
386 GTK_RESPONSE_OK,
387 NULL);
388
389 if (show_message_dialog && !eject && val == TRUE && exit_status == 0)
390 //xfce_dialog_show_info (NULL, NULL, _("The device \"%s\" should be removable safely now."), pdisk->device);
391 xfce_message_dialog (NULL,
392 _("Xfce 4 Mount Plugin"),
393 "dialog-information",
394 _("The device should be removable safely now:"),
395 pdisk->device,
396 "gtk-ok",
397 GTK_RESPONSE_OK,
398 NULL);
399 if (show_message_dialog && disk_check_mounted(pdisk->device))
400 //xfce_dialog_show_error (NULL, NULL, _("An error occurred. The device \"%s\" should not be removed!"), pdisk->device);
401 xfce_message_dialog (NULL,
402 _("Xfce 4 Mount Plugin"),
403 "dialog-error",
404 _("An error occurred. The device should not be removed:"),
405 pdisk->device,
406 "gtk-ok",
407 GTK_RESPONSE_OK,
408 NULL);
409 }
410 }
411
412 /**
413 * Checks whether the pdisk is already inserted with a similar path with more
414 * or less slashes.
415 * @param pdisks Pointer to disks array
416 * @param pdisk Pointer to new disk to lateron insert into pdisks
417 * @return true if device or mount point does already exist, false otherwise
418 */
419 gboolean
device_or_mountpoint_exists(GPtrArray * pdisks,t_disk * pdisk)420 device_or_mountpoint_exists (GPtrArray * pdisks, t_disk * pdisk)
421 {
422 gboolean returnValue = FALSE;
423 guint i;
424 t_disk *disk;
425 int stringlength1, stringlength2, stringlength3, stringlength4;
426
427 stringlength1 = strlen(pdisk->device);
428 stringlength3 = strlen(pdisk->mount_point);
429
430 for (i=0; i < pdisks->len ; i++)
431 {
432 disk = (t_disk *) (g_ptr_array_index(pdisks,i));
433 stringlength2 = strlen(disk->device);
434 stringlength4 = strlen(disk->mount_point);
435
436 if (stringlength1==stringlength2+1 && pdisk->device[stringlength1-1]=='/' && strncmp(pdisk->device, disk->device, stringlength2)==0 )
437 {
438 returnValue = TRUE;
439 break;
440 }
441 else if (stringlength2==stringlength1+1 && disk->device[stringlength2-1]=='/' && strncmp(pdisk->device, disk->device, stringlength1)==0 )
442 {
443 returnValue = TRUE;
444 break;
445 }
446 else if (stringlength3==stringlength4+1 && pdisk->mount_point[stringlength3-1]=='/' && strncmp(pdisk->mount_point, disk->mount_point, stringlength4)==0 )
447 {
448 returnValue = TRUE;
449 break;
450 }
451 else if (stringlength4==stringlength3+1 && disk->mount_point[stringlength4-1]=='/' && strncmp(pdisk->mount_point, disk->mount_point, stringlength3)==0 )
452 {
453 returnValue = TRUE;
454 break;
455 }
456 }
457
458 return returnValue;
459 }
460
461 /**
462 * Fill a GPtrArray with pointers on struct t_disk containing infos on devices
463 * and theoretical mount point. used setfsent() and getfsent(),
464 * now uses setmntent() and getmntent() and enmntent().
465 * @param include_NFSs whether to include network file systems
466 * @return GPtrArray *pdisks containing elements to be displayed
467 */
468 GPtrArray *
disks_new(gboolean include_NFSs,gboolean * showed_fstab_dialog,gint length)469 disks_new (gboolean include_NFSs, gboolean *showed_fstab_dialog, gint length)
470 {
471 GPtrArray * pdisks; /* to be returned */
472 t_disk * pdisk;
473 struct fstab *pfstab;
474 gboolean has_valid_mount_device;
475
476 pdisks = g_ptr_array_new();
477
478 /* open fstab */
479 if (setfsent()!=1)
480 {
481 /* popup notification dialog */
482 if (! (*showed_fstab_dialog) ) {
483 //dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
484 //GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
485 //_("Your /etc/fstab could not be read. This will severely degrade the plugin's abilities."));
486
487 xfce_message_dialog (NULL,
488 _("Xfce 4 Mount Plugin"),
489 "dialog-info",
490 _("Your /etc/fstab could not be read. This will severely degrade the plugin's abilities."),
491 NULL,
492 "gtk-ok",
493 GTK_RESPONSE_OK,
494 NULL);
495 /* gtk_dialog_run (GTK_DIALOG (dialog)); */
496 //g_signal_connect (dialog, "response",
497 //G_CALLBACK (gtk_widget_destroy), dialog);
498 //gtk_widget_show (dialog);
499 *showed_fstab_dialog = TRUE;
500 }
501
502 return pdisks; /* on error return empty pdisks */
503 }
504
505
506 for (pfstab = getfsent(); pfstab!=NULL; pfstab = getfsent())
507 {
508 has_valid_mount_device =
509 g_str_has_prefix(pfstab->fs_spec, "/dev/") || g_str_has_prefix(pfstab->fs_spec, "UUID=") || g_str_has_prefix(pfstab->fs_spec, "LABEL=");
510
511 if (include_NFSs)
512 has_valid_mount_device = has_valid_mount_device |
513 g_str_has_prefix(pfstab->fs_vfstype, "fuse") |
514 g_str_has_prefix(pfstab->fs_vfstype, "shfs") |
515 g_str_has_prefix(pfstab->fs_vfstype, "nfs") |
516 g_str_has_prefix(pfstab->fs_vfstype, "cifs") |
517 g_str_has_prefix(pfstab->fs_vfstype, "smbfs");
518
519 if ( has_valid_mount_device &&
520 g_str_has_prefix(pfstab->fs_file, "/") ) {
521 pdisk = disk_new (pfstab->fs_spec, pfstab->fs_file, length);
522 pdisk->dc = disk_classify (pfstab->fs_spec, pfstab->fs_file);
523 if (!device_or_mountpoint_exists(pdisks, pdisk))
524 g_ptr_array_add (pdisks , pdisk);
525
526 }
527
528 } /* end for */
529
530 endfsent(); /* close file */
531
532 return pdisks;
533 }
534
535
536 /**
537 * Free a GPtrArray containing pointer on struct t_disk elements
538 */
539 void
disks_free(GPtrArray ** pdisks)540 disks_free (GPtrArray ** pdisks)
541 {
542 unsigned int i ;
543 t_disk * pdisk ;
544
545 if (pdisks != NULL && *pdisks != NULL)
546 {
547 for (i=0; i < (*pdisks)->len ; i++)
548 {
549 pdisk = (t_disk *) (g_ptr_array_index((*pdisks),i));
550 disk_free (&pdisk) ;
551 }
552 g_ptr_array_free ((*pdisks), TRUE);
553 (*pdisks) = NULL ;
554 }
555 }
556
557
558 /**
559 * Print a GPtrArray containing pointer on struct t_disk elements
560 */
561 void
disks_print(GPtrArray * pdisks)562 disks_print (GPtrArray * pdisks)
563 {
564 unsigned int i ;
565 for (i=0; i < pdisks->len ; i++)
566 {
567 disk_print (g_ptr_array_index(pdisks, i));
568 }
569 return ;
570
571 }
572
573
574 /**
575 * Removes specfied device from array.
576 * @return true on success, else false.
577 */
578 gboolean
disks_remove_device(GPtrArray * pdisks,char * device)579 disks_remove_device (GPtrArray * pdisks, char *device)
580 {
581 unsigned int i;
582 gpointer p=NULL;
583 gboolean removedEntries = FALSE;
584 char *exclude_device;
585 size_t device_len;
586
587 for (i=0; i < pdisks->len ; i++)
588 {
589 exclude_device = ((t_disk *) g_ptr_array_index(pdisks, i))->device;
590 if ( strcmp ( exclude_device,
591 device )==0 )
592 {
593 p = g_ptr_array_remove_index(pdisks, i);
594 if (p!=NULL)
595 removedEntries = TRUE;
596 }
597
598 device_len = strlen(device);
599
600 if ( device[device_len-1]=='*' &&
601 strncmp ( exclude_device,
602 device, device_len-1 )==0 )
603 {
604 p = g_ptr_array_remove_index(pdisks, i);
605 if (p!=NULL)
606 removedEntries = TRUE;
607 }
608 }
609
610 return removedEntries;
611 }
612
613
614 /**
615 * Removes specfied mount point from array.
616 * @return true on success, else false.
617 */
618 gboolean
disks_remove_mountpoint(GPtrArray * pdisks,char * mountp)619 disks_remove_mountpoint (GPtrArray * pdisks, char *mountp)
620 {
621 gboolean removedEntries = FALSE;
622 unsigned int i;
623 gpointer p=NULL;
624 char *exclude_mp;
625 size_t mountp_len;
626
627 for (i=0; i < pdisks->len ; i++)
628 {
629 exclude_mp = ((t_disk *) g_ptr_array_index(pdisks, i))->mount_point;
630
631 if (strcmp ( exclude_mp,
632 mountp)==0)
633 {
634 DBG("REMOVED %s @ %i %s", mountp, i, exclude_mp);
635 p = g_ptr_array_remove_index(pdisks, i);
636 if (p!=NULL)
637 removedEntries = TRUE;
638 }
639
640 mountp_len = strlen(mountp);
641
642 if ( mountp[mountp_len-1]=='*' &&
643 strncmp ( exclude_mp,
644 mountp, mountp_len-1 )==0 )
645 {
646 DBG("removed %s @ %i %s", mountp, i, exclude_mp);
647 p = g_ptr_array_remove_index(pdisks, i);
648 if (p!=NULL)
649 removedEntries = TRUE;
650 }
651 }
652
653 return removedEntries;
654 }
655
656
657 /**
658 * @return a pointer on FIRST struct t_disk containing char * device as
659 * device field; if not found return NULL.
660 */
661 t_disk *
disks_search(GPtrArray * pdisks,char * mount_point)662 disks_search (GPtrArray * pdisks, char * mount_point)
663 {
664 unsigned int i ;
665
666 for (i=0; i < pdisks->len ; i++)
667 {
668 if (g_ascii_strcasecmp (
669 ((t_disk *) g_ptr_array_index(pdisks, i))->mount_point,
670 mount_point
671 )==0 ) return g_ptr_array_index (pdisks, i);
672 }
673 return NULL;
674 }
675
676
677 /**
678 * Remove struct t_mount_info from a GPtrArray containing
679 * struct t_disk * elements.
680 * @param pdisks Array of t_mount_info
681 */
682 void
disks_free_mount_info(GPtrArray * pdisks)683 disks_free_mount_info(GPtrArray * pdisks)
684 {
685 unsigned int i ;
686
687 for (i=0; i < pdisks->len ; i++)
688 {
689 mount_info_free( &(((t_disk*)g_ptr_array_index(pdisks,i))->mount_info)) ;
690 }
691 return ;
692
693 }
694
695
696 /**
697 * Searches array for device and mountpoint. Returns TRUE if found.
698 */
699 gboolean
exclude_filesystem(GPtrArray * excluded_FSs,gchar * mountpoint,gchar * device)700 exclude_filesystem (GPtrArray *excluded_FSs, gchar *mountpoint, gchar *device)
701 {
702 unsigned int i;
703 gchar *excluded_FS_i;
704 size_t excluded_FS_i_len = 0;
705
706 TRACE("Entering exclude_filesystems");
707
708 g_assert(excluded_FSs != NULL);
709
710 for (i=0; i < excluded_FSs->len; i++)
711 {
712 excluded_FS_i = (gchar *) g_ptr_array_index(excluded_FSs, i);
713 DBG("Comparing %s and %s to %s", mountpoint, device, excluded_FS_i);
714 if (g_ascii_strcasecmp (
715 excluded_FS_i, mountpoint)==0
716 ||
717 g_ascii_strcasecmp (
718 excluded_FS_i, device)==0
719 )
720 return TRUE;
721
722 excluded_FS_i_len = strlen(excluded_FS_i);
723
724 if ((excluded_FS_i[excluded_FS_i_len-1]=='*') &&
725 (g_ascii_strncasecmp (
726 excluded_FS_i, mountpoint, excluded_FS_i_len-1)==0
727 ||
728 g_ascii_strncasecmp (
729 excluded_FS_i, device, excluded_FS_i_len-1)==0
730 ))
731 return TRUE;
732 }
733
734 TRACE("Leaving exclude_filesystems with FALSE");
735
736 return FALSE;
737 }
738
739
740 /**
741 * Refreshes t_mount_info infos in a GPtrArray containing
742 * struct t_disk * elements.
743 */
744 void
disks_refresh(GPtrArray * pdisks,GPtrArray * excluded_FSs,gint length)745 disks_refresh(GPtrArray * pdisks, GPtrArray *excluded_FSs, gint length)
746 {
747 /* using getmntent/getmntinfo to get filesystems mount information */
748
749 #ifdef HAVE_GETMNTENT
750 FILE * fmtab = NULL; /* file /etc/mtab */
751 struct mntent * pmntent = NULL; /* struct for mnt info */
752 #elif defined (HAVE_GETMNTINFO)
753 int i, nb_mounted_fs = 0;
754 #endif
755 struct statfs * pstatfs = NULL;
756 gboolean exclude = FALSE;
757
758 t_mount_info * mount_info;
759 t_disk * pdisk ;
760
761 TRACE("Entering disks_refresh");
762
763 /* remove t_mount_info for all devices */
764 disks_free_mount_info (pdisks);
765
766 #ifdef HAVE_GETMNTENT
767 /* allocate new struct statfs */
768 pstatfs = g_new0 (struct statfs, 1);
769
770 /* open file */
771 fmtab = setmntent (MTAB, "r"); /* mtab file */
772 #elif defined (HAVE_GETMNTINFO)
773 /* get mounted fs */
774 nb_mounted_fs = getmntinfo(&pstatfs,MNT_WAIT);
775 #endif
776
777 /* start looking for mounted devices */
778 #ifdef HAVE_GETMNTENT
779 for (pmntent=getmntent(fmtab); pmntent!=NULL; pmntent=getmntent(fmtab)) {
780
781 DBG (" have entry: %s on %s", pmntent->mnt_fsname, pmntent->mnt_dir );
782
783 statfs (pmntent->mnt_dir, pstatfs);
784 #elif defined (HAVE_GETMNTINFO)
785 for (i = 0; i < nb_mounted_fs ; i++) {
786 DBG (" have entry: %s on %s : type %s", pstatfs[i].f_mntfromname, pstatfs[i].f_mntonname, pstatfs[i].f_fstypename );
787 #endif
788
789 /* if we got the stat and the block number is non-zero */
790
791 /* get pointer on disk from pdisks */
792 /* CHANGED to reflect change in disk_search */
793 #ifdef HAVE_GETMNTENT
794 pdisk = disks_search (pdisks, pmntent->mnt_dir);
795 #elif defined (HAVE_GETMNTINFO)
796 pdisk = disks_search (pdisks, pstatfs[i].f_mntonname);
797 #endif
798 if (excluded_FSs!=NULL)
799 #ifdef HAVE_GETMNTENT
800 exclude = exclude_filesystem (excluded_FSs, pmntent->mnt_dir, pmntent->mnt_fsname);
801 #elif defined (HAVE_GETMNTINFO)
802 exclude = exclude_filesystem (excluded_FSs, pstatfs[i].f_mntonname, pstatfs[i].f_mntfromname);
803 #endif
804
805 if (pdisk == NULL) { /* if disk is not found in pdisks */
806
807 /* create a new struct t_disk and add it to pdisks */
808 /* test for mnt_dir==none or neither block device nor NFS or system device */
809 if ( exclude ||
810 #ifdef HAVE_GETMNTENT
811 g_ascii_strcasecmp(pmntent->mnt_dir, "none") == 0 ||
812 g_str_has_prefix(pmntent->mnt_fsname, "gvfs-fuse-daemon") ||
813 !(g_str_has_prefix(pmntent->mnt_fsname, "/dev/") ||
814 g_str_has_prefix(pmntent->mnt_type, "fuse") ||
815 g_str_has_prefix(pmntent->mnt_type, "nfs") ||
816 g_str_has_prefix(pmntent->mnt_type, "smbfs") ||
817 g_str_has_prefix(pmntent->mnt_type, "cifs") ||
818 g_str_has_prefix(pmntent->mnt_type, "shfs")
819 ) ||
820 g_str_has_prefix(pmntent->mnt_dir, "/sys/")
821 #elif defined (HAVE_GETMNTINFO)
822 /* TODO: add support for more fs types on BSD */
823 g_ascii_strcasecmp(pstatfs[i].f_mntonname, "none") == 0 ||
824 !(g_str_has_prefix(pstatfs[i].f_mntfromname, "/dev/") ||
825 g_str_has_prefix(pstatfs[i].f_fstypename, "nfs") ||
826 g_str_has_prefix(pstatfs[i].f_fstypename, "mfs")
827 )
828 #endif
829 ) continue;
830
831 /* else have valid entry reflecting block device or NFS */
832 #ifdef HAVE_GETMNTENT
833 pdisk = disk_new (pmntent->mnt_fsname, pmntent->mnt_dir, length);
834 pdisk->dc = disk_classify (pmntent->mnt_fsname, pmntent->mnt_dir);
835 #elif defined (HAVE_GETMNTINFO)
836 pdisk = disk_new (pstatfs[i].f_mntfromname, pstatfs[i].f_mntonname, length);
837 pdisk->dc = disk_classify (pstatfs[i].f_mntfromname, pstatfs[i].f_mntonname);
838 #endif
839 g_ptr_array_add (pdisks, pdisk);
840 }
841
842 /* create new t_mount_info */
843 #ifdef HAVE_GETMNTENT
844 mount_info = mount_info_new_from_stat (pstatfs, pmntent->mnt_type,
845 pmntent->mnt_dir);
846 #elif defined (HAVE_GETMNTINFO)
847 mount_info = mount_info_new_from_stat (&pstatfs[i], pstatfs[i].f_fstypename,
848 pstatfs[i].f_mntonname);
849 #endif
850 /* add it to pdisk */
851 pdisk->mount_info = mount_info ;
852
853 } /* end for */
854
855 #ifdef HAVE_GETMNTENT
856 g_free (pstatfs);
857 endmntent (fmtab); /* close file */
858 #endif
859
860 return;
861 }
862
863
864 t_deviceclass
865 disk_classify (char *device, char *mountpoint)
866 {
867 t_deviceclass dc = UNKNOWN;
868
869 /* Note: Since linux-2.6.19, you cannot distinguish between scsi/removable
870 * drives by sdX and hard disks by hdY, since hdY is replaced by sdY.
871 */
872 if (strstr(device, "/dev")==NULL) { /* remote or unknown */
873 if (strstr(device, "nfs") || strstr(device, "smbfs")
874 || strstr(device, "shfs") || strstr(device, "cifs") || strstr(device, "fuse")) {
875 dc = REMOTE;
876 }
877 }
878 /* it needs to be said _here_ that BSDs use cd0, cd1 etc., so we hope cd* works for cdrw, cdrom and cd0,1,... nd no other devices */
879 else if ( strstr(device, "cd")
880 || strstr(device, "dvd") || strstr(mountpoint, "cd") || strstr(mountpoint, "dvd")) {
881 dc = CD_DVD;
882 }
883 else if ( strstr(mountpoint, "usr") || strstr(mountpoint, "var")
884 || strstr(mountpoint, "home") || strcmp(mountpoint, "/")==0 ) {
885 dc = HARDDISK;
886 }
887
888 else if ( strstr(mountpoint, "media") || strstr(mountpoint, "usb") ) {
889 dc = REMOVABLE;
890 }
891
892 return dc;
893 }
894
895
896 gboolean
897 disk_check_mounted (const char *disk)
898 {
899 #ifdef HAVE_GETMNTENT
900 FILE *fmtab = NULL; /* file /etc/mtab */
901 struct mntent *pmntent = NULL; /* struct for mnt info */
902 #elif defined (HAVE_GETMNTINFO)
903 struct statfs * pstatfs = NULL;
904 int i, nb_mounted_fs = 0;
905 #endif
906 gboolean retval = FALSE;
907
908 #ifdef HAVE_GETMNTENT
909 /* open file */
910 fmtab = setmntent (MTAB, "r"); /* mtab file */
911 #elif defined (HAVE_GETMNTINFO)
912 /* get mounted fs */
913 nb_mounted_fs = getmntinfo(&pstatfs,MNT_WAIT);
914 #endif
915
916 /* start looking for mounted devices */
917 #ifdef HAVE_GETMNTENT
918 for (pmntent=getmntent(fmtab); pmntent!=NULL; pmntent=getmntent(fmtab))
919 #elif defined (HAVE_GETMNTINFO)
920 for (i = 0; i < nb_mounted_fs ; i++)
921 #endif
922 {
923 #ifdef HAVE_GETMNTENT
924 if (strcmp(pmntent->mnt_dir, disk)==0 ||
925 strcmp(pmntent->mnt_fsname, disk)==0 )
926 #elif defined (HAVE_GETMNTINFO)
927 if (strcmp(pstatfs[i].f_mntonname, disk)==0 ||
928 strcmp(pstatfs[i].f_mntfromname, disk)==0 )
929 #endif
930 {
931 retval = TRUE;
932 break;
933 }
934 }
935
936 #ifdef HAVE_GETMNTENT
937 endmntent (fmtab); /* close file */
938 #endif
939
940 return retval;
941 }
942