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