1 /*
2 ** This is the main header file for gentoo. Most source files will include this header,
3 ** since it declares many of the data types that are used. When including this header,
4 ** it should always be the first included file. The preferred order of inclusion is:
5 ** #include "gentoo.h"
6 ** #include <system stuff> (e.g. <stdio.h>, <stdlib.h>, ...)
7 ** #include "more gentoo stuff" (e.g. "fileutil.h", "xmlutil.h", ...)
8 ** #include "me.h" (for a module named "me.c", that is).
9 **
10 ** The reason why this file should be the first included one is that it fixes some
11 ** system-dependent things which need to go before any system headers are included.
12 */
13 
14 #include "config.h"
15 
16 #if !(defined __osf__ && defined __alpha__) && !defined __NetBSD__ && !defined __FreeBSD__ && !defined __DragonFly__ && !defined __sgi
17  #if !defined __EXTENSIONS__
18   #define __EXTENSIONS__
19  #endif
20  #if !defined _POSIX_C_SOURCE
21   #define _POSIX_C_SOURCE	3	/* This is for Solaris. */
22  #endif
23  #define POSIX_C_SOURCE	3
24 #endif				/* !__osf__ && !__alpha */
25 
26 #if defined __osf__ && defined __alpha__		/* On Tru64, this should bring in mknod(). */
27  #define _XOPEN_SOURCE_EXTENDED
28  #define _OSF_SOURCE					/* For MAXNAMLEN on Tru64. */
29 #endif
30 
31 #if !defined _BSD_SOURCE
32  #define _BSD_SOURCE					/* For MAXNAMLEN on Linux. */
33 #endif
34 
35 #include <dirent.h>
36 #include <errno.h>
37 #include <glob.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/mman.h>
43 #include <sys/stat.h>
44 #include <sys/time.h>
45 #include <regex.h>
46 #include <time.h>
47 #include <unistd.h>
48 
49 /* The various BSDs seem to have a lot in common. Let's try and use that,
50 ** and save some typing in various tests below. This should probably all
51 ** be replaced by proper Autoconfed stuff at some point.
52 */
53 #if defined __OpenBSD__ || defined __FreeBSD__ || defined __NetBSD__ || defined __DragonFly__
54 #define GENTOO_ON_BSD
55 #endif
56 
57 /* BSD-specific mounting stuff. */
58 #if defined GENTOO_ON_BSD
59 #include <sys/param.h>
60 #include <sys/mount.h>
61 #endif
62 
63 #undef GTK_ENABLE_BROKEN		/* We can't use autoconf to undefine symbols. */
64 #include <gio/gio.h>
65 #include <gtk/gtk.h>
66 #include <gdk-pixbuf/gdk-pixbuf.h>
67 
68 /* Fix for < Glib 2.20. */
69 #ifndef G_GOFFSET_FORMAT
70 #define G_GOFFSET_FORMAT G_GINT64_FORMAT
71 #endif
72 
73 /* Not all systems' <mman.h> seem to define this. */
74 #if !defined MAP_FAILED
75 #define	MAP_FAILED	((void *) -1)
76 #endif
77 
78 #if !defined MAXNAMLEN			/* Still no MAXNAMLEN? Then make one up. */
79 #define	MAXNAMLEN	255
80 #endif
81 
82 /* ----------------------------------------------------------------------------------------- */
83 
84 #define	RCNAME	"gentoorc"
85 
86 /* ----------------------------------------------------------------------------------------- */
87 
88 /* Sometimes, this does good stuff. I hope. That's about all you can do with GNU tools,
89 ** since actually understanding them requires way more time than I'm willing to spend.
90 */
91 #include "gnu-gettext.h"
92 
93 #if defined ENABLE_NLS
94 /* This provides the _() and N_() macros used to mark strings for translation. */
95 #include <glib/gi18n.h>
96 #else
97 /* Provide transparent definitions if NLS is disabled. */
98 #define	_(str)	str
99 #define	N_(str)	str
100 #endif		/* ENABLE_NLS */
101 
102 /* ----------------------------------------------------------------------------------------- */
103 
104 typedef struct MainInfo		MainInfo;
105 typedef struct DirPane		DirPane;
106 typedef struct CmdSeq		CmdSeq;
107 
108 /* These are various subsystems whose includes we need here, since they define datatypes
109 ** that are needed below. This is a good point to include them, since MainInfo has been
110 ** introduced (above).
111 */
112 #include "buttonlayout.h"
113 #include "keyboard.h"
114 #include "controls.h"
115 #include "iconutil.h"
116 #include "queue.h"
117 #include "cmdarg.h"
118 #include "styles.h"
119 #include "dirhistory.h"
120 #include "window.h"
121 #include "menus.h"
122 #include "sizeutil.h"
123 
124 #define	KEY_NAME_SIZE	(32)
125 
126 #define	CSQ_NAME_SIZE	(32)
127 
128 /* FileType-related constants. */
129 enum {
130 	FT_NAME_SIZE	= (32),
131 	FT_SUFFIX_SIZE	= (32),
132 	FT_NAMERE_SIZE	= (64),
133 	FT_FILERE_SIZE	= (64),
134 
135 	FTFL_REQPERM	= (1<<0),
136 	FTFL_REQSUFFIX	= (1<<1),
137 	FTFL_NAMEMATCH	= (1<<2),
138 	FTFL_NAMEGLOB	= (1<<3),
139 	FTFL_FILEMATCH	= (1<<4),
140 	FTFL_FILEGLOB	= (1<<5),
141 	FTFL_NAMENOCASE	= (1<<6),
142 	FTFL_FILENOCASE	= (1<<7),
143 
144 	FTPM_SETUID	= (1<<0),
145 	FTPM_SETGID	= (1<<1),
146 	FTPM_STICKY	= (1<<2),
147 	FTPM_READ	= (1<<3),
148 	FTPM_WRITE	= (1<<4),
149 	FTPM_EXECUTE	= (1<<5),
150 };
151 
152 typedef struct {			/* Used to map stat() info onto names. */
153 	gchar	name[FT_NAME_SIZE];		/* Human-readable name of filetype (e.g. "GIF image", "MP3 song"). */
154 	mode_t	mode;				/* Type flags, matched against stat()'s mode info. */
155 	guint32	flags;				/* Various flags. */
156 	guint32	perm;				/* Permissions to require. Not orthogonal with mode. */
157 	gchar	suffix[FT_SUFFIX_SIZE];		/* Suffix to require (if FTFL_REQSUFFIX is set). */
158 	gchar	name_re_src[FT_NAMERE_SIZE];	/* Regular expression to match against the name (if FTFL_MATCHNAME). */
159 	regex_t	*name_re;			/* Compiled version of the regular expression. */
160 	gchar	file_re_src[FT_FILERE_SIZE];	/* RE to match against output of 'file' command (if FTFL_MATCHFILE). */
161 	regex_t	*file_re;			/* Again, a compiled version of the regular expression. */
162 	Style	*style;				/* Style to use for items matching this type. */
163 } FType;
164 
165 #define	DP_TITLE_SIZE	(32)
166 #define	DP_FORMAT_SIZE	(16)
167 #define	DP_DATEFMT_SIZE	(32)
168 #define	DP_MAX_COLUMNS	(32)
169 
170 typedef enum {	DPC_NAME, DPC_SIZE, DPC_BLOCKS, DPC_BLOCKSIZE, DPC_MODENUM, DPC_MODESTR,
171 		DPC_NLINK, DPC_UIDNUM, DPC_UIDSTR, DPC_GIDNUM, DPC_GIDSTR, DPC_DEVICE, DPC_DEVMAJ, DPC_DEVMIN,
172 		DPC_ATIME, DPC_MTIME, DPC_CRTIME, DPC_CHTIME,
173 		DPC_TYPE, DPC_ICON,
174 		DPC_URI_NOFILE,
175 		DPC_NUM_TYPES } DPContent;
176 
177 typedef struct {
178 	guint	show_type : 1;			/* Append type-character (from "@ / * | =") to names? */
179 	guint	show_linkname : 1;		/* Append " -> destination" on symbolic links? */
180 } DC_Name;
181 
182 typedef struct {
183 	SzUnit	unit;
184 	guint	ticks : 1;
185 	gchar	tick;
186 	gint	digits;
187 	gchar	dformat[DP_FORMAT_SIZE];	/* Hidden from user, not saved, built by config code. */
188 	guint	dir_show_fs_size : 1;		/* Show filesystem size for directories? */
189 } DC_Size;
190 
191 typedef struct {
192 	gchar	format[DP_FORMAT_SIZE];		/* General numerical formatter (for size, mode, uid, etc). */
193 } DC_Fmt;
194 
195 typedef struct {
196 	gchar	format[DP_DATEFMT_SIZE];	/* A strftime() format specifier. */
197 } DC_Time;
198 
199 typedef union {
200 	DC_Name	name;
201 	DC_Size	size;
202 	DC_Fmt	blocks, blocksize;
203 	DC_Fmt	mode, nlink, uidnum, gidnum, device, devmaj, devmin;
204 	DC_Time	a_time, m_time, cr_time, ch_time;
205 } DpCExtra;
206 
207 typedef struct {
208 	gchar			title[DP_TITLE_SIZE];
209 	DPContent		content;
210 	DpCExtra		extra;		/* Content-specific flags. */
211 	GtkJustification	just;
212 	gint			width;
213 } DpCFmt;
214 
215 typedef enum { DPS_DIRS_FIRST = 0, DPS_DIRS_LAST, DPS_DIRS_MIXED } SortMode;
216 
217 typedef struct {
218 	DPContent	content;		/* The content type we wish to sort on. */
219 	SortMode	mode;			/* Controls placement of directories. */
220 	gboolean	invert;			/* If set, we sort backwards (Z-A). */
221 	gboolean	nocase;			/* Set for case-insensitive string comparisons. Lame! */
222 } DPSort;
223 
224 typedef enum { SBP_IGNORE = 0, SBP_LEFT, SBP_RIGHT } SBarPos;
225 
226 #define	FONT_MAX	128
227 
228 typedef struct {
229 	guint		num_columns;
230 	DpCFmt		format[DP_MAX_COLUMNS];
231 	DPSort		sort;
232 	gchar		def_path[PATH_MAX];
233 	gboolean	path_above;		/* Set to get the path entry above the actual pane. */
234 	gboolean	hide_allowed;		/* Set to enable hiding (default). */
235 	gboolean	scrollbar_always;	/* Set to always show scrollbar, regardless of # of entries. */
236 	gboolean	huge_parent;		/* Set to enable huge, tall, Opus-like parent button. */
237 	SBarPos		sbar_pos;		/* Position of scrollbar. */
238 	gboolean	set_font;		/* Set to override GTK+'s default font. */
239 	gchar		font_name[FONT_MAX];	/* Last-set font name, remains valid even when set_font == FALSE. */
240 	gboolean	rubber_banding;		/* Set to enable GTK+'s "rubberbanding" selection. */
241 } DPFormat;
242 
243 typedef enum { DPORIENT_HORIZ = 0, DPORIENT_VERT } DpOrient;
244 typedef enum { DPSPLIT_FREE = 0,   DPSPLIT_RATIO, DPSPLIT_ABS_LEFT, DPSPLIT_ABS_RIGHT } DpSplit;
245 
246 /* Allow user to control how gentoo should allocate window space between the panes. */
247 typedef struct {
248 	DpOrient	orientation;
249 	DpSplit		mode;
250 	gdouble		value;		/* Parameter interpreted depending on mode. */
251 } DPPaning;
252 
253 typedef struct {
254 	gboolean	select;			/* Remember selections? */
255 	gboolean	save;			/* Save history lists on exit? */
256 } DPHistory;
257 
258 /* ----------------------------------------------------------------------------------------- */
259 
260 /* General command row flags. */
261 enum {
262 	CGF_RUNINBG = (1<<0),		/* Run in command in background? */
263 	CGF_KILLPREV = (1<<1),		/* Kill previous instance of program (only background)? */
264 	CGF_GRABOUTPUT = (1<<2),	/* Capture the output into a special window? */
265 	CGF_SURVIVE = (1<<3)		/* Survive when gentoo quits (only background)? */
266 };
267 
268 /* These flags are for the before- and after-flag fields. */
269 enum {
270 	CBAF_RESCAN_SOURCE = (1<<0),		/* Rescan the source dir pane? */
271 	CBAF_RESCAN_DEST = (1<<1),
272 	CBAF_CD_SOURCE = (1<<2),		/* These save some config work. */
273 	CBAF_CD_DEST = (1<<3),
274 	CBAF_REQSEL_SOURCE = (1<<4),		/* Command won't run if there's no source selection when invoked. */
275 	CBAF_REQSEL_DEST = (1<<5)		/* Command won't run if there's no destination selection when invoked. */
276 };
277 
278 typedef struct {		/* Extra info for external commands. */
279 	guint32	gflags;			/* General flags. */
280 	guint32	baflags[2];		/* Before and after flags. */
281 } CX_Ext;
282 
283 typedef enum {	CRTP_BUILTIN, CRTP_EXTERNAL,
284 		CRTP_NUM_TYPES } CRType;
285 
286 
287 typedef struct {		/* A command "row". */
288 	CRType	type;			/* The type of the row. */
289 	GString	*def;			/* The row definition string. */
290 	guint32	flags;			/* Flags common to all types. */
291 	union {				/* Type-specific row info. */
292 	CX_Ext	external;		/* Extra info for external commands. */
293 	} extra;
294 } CmdRow;
295 
296 #define	CSFLG_REPEAT	(1<<0)		/* Repeat sequence until no selection? */
297 
298 struct CmdSeq {
299 	gchar	name[CSQ_NAME_SIZE];	/* Name of this command sequence, really. */
300 	guint32	flags;			/* Flags for this sequence. */
301 	GList	*rows;			/* List of CmdRow definition rows. */
302 };
303 
304 typedef struct {			/* Information about commands lives here. */
305 	GHashTable	*builtin;		/* Built-in commands (actually CmdDesc structs -- see cmdseq.c). */
306 	GHashTable	*cmdseq;		/* Command sequences. */
307 } CmdInfo;
308 
309 /* ----------------------------------------------------------------------------------------- */
310 
311 #define	BTN_LABEL_SIZE		(32)
312 #define	BTN_TOOLTIP_SIZE	(64)	/* Arbitrary, as always. */
313 
314 typedef struct {
315 	GList	*sheets;			/* List of button sheets. */
316 } ButtonInfo;
317 
318 typedef struct {			/* Options for overwrite-confirmation dialog module. */
319 	guint	show_info : 1;			/* Show info (sizes & dates) for conflicting files? */
320 	gchar	datefmt[DP_DATEFMT_SIZE];	/* How to format dates? */
321 } OptOverwrite;
322 
323 typedef enum { HIDE_NONE, HIDE_DOT, HIDE_REGEXP } HMode;
324 
325 typedef struct {			/* Info about files hidden from user. Not ignored, just hidden. */
326 	HMode	mode;
327 	gchar	hide_re_src[MAXNAMLEN];		/* Regular expression; matches are hidden if mode == HIDE_REGEXP. */
328 	regex_t	*hide_re;			/* Compiled version of the RE. */
329 	guint	no_case : 1;			/* Ignore case in the RE? */
330 } HideInfo;
331 
332 typedef enum {	PTID_ICON = 0, PTID_GTKRC, PTID_FSTAB, PTID_MTAB,
333 		PTID_NUM_PATHS } PathID;
334 
335 typedef struct {				/* Miscellanous paths. */
336 	GString		*path[PTID_NUM_PATHS];		/* Just one GString per path, that's all. */
337 	HideInfo	hideinfo;			/* Info about which files should be hidden. */
338 } PathInfo;
339 
340 typedef struct {			/* Configuration information for dialogs. */
341 	GtkWindowPosition	pos;		/* How should dialogs be positioned? */
342 } DialogInfo;
343 
344 typedef enum {
345 	ERR_DISPLAY_STATUSBAR,
346 	ERR_DISPLAY_TITLEBAR,
347 	ERR_DISPLAY_DIALOG
348 } ErrDisplay;
349 
350 typedef struct {
351 	ErrDisplay	display;		/* How should error (and status messages) be shown? */
352 	gboolean	beep;			/* Do a gdk_beep() on error? */
353 } ErrInfo;
354 
355 typedef struct {
356 	GHashTable	*ignored;		/* Keyed on 'tag', if present ignore the dialog. */
357 } NagInfo;
358 
359 #define	CFLG_CHANGED	(1<<0)		/* Config has changed. Set on "OK", cleared by cfg_save_all(). */
360 
361 typedef struct {			/* Holds all configuration info. */
362 	guint32		flags;
363 	GList		*type;			/* List of types (FType structures). */
364 	StyleInfo	*style;			/* Opaque style container. */
365 	DPFormat	dp_format[2];
366 	DPPaning	dp_paning;		/* Controls how the paned view acts. */
367 	DPHistory	dp_history;		/* History list option. */
368 	OptOverwrite	opt_overwrite;
369 	MenuInfo	*menus;
370 	ButtonInfo	buttons;
371 	ButtonLayout	*buttonlayout;
372 	CmdInfo		commands;
373 	PathInfo	path;
374 	WinInfo		*wininfo;
375 	DialogInfo	dialogs;
376 	CtrlInfo	*ctrlinfo;
377 	ErrInfo		errors;
378 	gboolean	(*dir_filter)(const gchar *name);
379 	NagInfo		nag;
380 } CfgInfo;
381 
382 typedef struct GuiInfo	GuiInfo;
383 
384 typedef struct {
385 	GVfs		*vfs;
386 } VfsInfo;
387 
388 struct MainInfo {				/* gentoo's single most central data structure. */
389 	gchar		**run_commands;		/* From the command line --run option, kept first for initializer in main(). */
390 	VfsInfo		vfs;
391 	CfgInfo		cfg;
392 	GuiInfo		*gui;
393 	IconInfo	*ico;
394 	QueueInfo	*que;
395 };
396 
397 /* -- Directory content data structures -- */
398 
399 /* This is used for complete-as-you-type of paths. */
400 typedef struct {
401 	gchar			prefix[PATH_MAX];	/* The path prefix that the GtkCompletion holds strings for. */
402 	guint			change_sig;		/* Signal for change handler on path entry widget. */
403 	GtkEntryCompletion	*compl;			/* A GTK+ 2.0 completion object, attached to the pane's path entry. */
404 } PathComplete;
405 
406 enum {	DPRF_HAS_SIZE	 = 1 << 0,		/* Set when a row has a "real" size (not set for directories unless GetSize:d). */
407 	DPRF_LINK_EXISTS = 1 << 1,		/* Set when a symlink's target exists. */
408 	DPRF_LINK_TO_DIR = 1 << 2		/* Set when symlink points at (valid) directory. Implies DPRF_LINK_EXISTS. */
409 };
410 
411 typedef struct {			/* A filename, in both on-disk and display formats. */
412 	const gchar	*disk;			/* On-disk name, as read during directory scanning. */
413 	const gchar	*display;		/* Display, as returned by glib (generally, this will be UTF-8). */
414 } DRName;
415 
416 typedef struct {			/* Representation of a single line in a directory (a file, typically). */
417 	DRName		dr_names;		/* Actual filename, in two representations. */
418 	DRName		dr_linknames;		/* Link name, again in two representations. */
419 	struct stat	dr_lstat;		/* From a call to lstat(). */
420 	struct stat	*dr_stat;		/* If link, this holds link target stats. Else, it points at dr_lstat. */
421 	guint32		dr_flags;		/* Misc. flags. */
422 	const FType	*dr_type;		/* Type information. */
423 } DirRow;
424 
425 typedef GtkTreeIter	DirRow2;
426 
427 typedef struct {
428 	guint		num_dirs, num_files;
429 	guint64		num_bytes;
430 } SelInfo;
431 
432 typedef struct {			/* Some trivial file system information. Updated on rescan. */
433 	gboolean	valid;			/* Set if the structure's contents are valid. */
434 	guint64		fs_size;		/* Size of filesystem, in bytes. */
435 	guint64		fs_free;		/* Free bytes in this filesystem. */
436 } FsInfo;
437 
438 #define	URI_MAX		(2000)			/* This should only rarely be used, and hopefully ease out once GIO gets more mature. */
439 
440 typedef struct {
441 	gchar		path[URI_MAX];		/* Contents apply to this path. */
442 	gchar		*pathd;			/* Dynamically allocated display version of the path. Beware! */
443 	GtkListStore	*store;			/* Actual ListStore holding the pane's contents. Insert and clear here. */
444 	GFile		*root;			/* A GFile representing the current location shown. */
445 	gboolean	is_local;		/* Is the root considered local? Used to control 'file' etc. */
446 	guint		num_rows;		/* Number of valid rows. */
447 	guint		tot_dirs, tot_files;	/* Total number of entries in directory. */
448 	guint64		tot_bytes;		/* Sum of all sizes, in bytes. */
449 	struct stat	*stat;			/* Info about link targets. */
450 	gsize		stat_alloc, stat_use;	/* Allocated and used link stat structs. */
451 	SelInfo		sel;
452 	FsInfo		fs;
453 } DirContents;
454 
455 /* -- Main DirPane structure --------------------------------------------------------------- */
456 
457 struct DirPane {
458 	MainInfo	*main;			/* Handy to have around. */
459 	guint		index;			/* Index of *this* pane, in the grand scheme of things. */
460 	GtkWidget	*vbox;
461 	GtkWidget	*notebook;		/* Notebook holding (normally) path widgetry. */
462 	GtkWidget	*parent;		/* The common parent button. */
463 	GtkWidget	*hparent;		/* The "huge" parent button, if enabled in config. */
464 	GtkWidget	*path;			/* GTK+ 2.0 GtkComboBox showing path and path history. */
465 	PathComplete	complete;		/* Information for completing the path. */
466 	GtkWidget	*hide;			/* A toggle button showing (and controlling) hide status. Focus target! */
467 	GtkWidget	*scwin;			/* Scrolling window for clist to live in. */
468 	GtkWidget	*view;			/* GtkTreeView for viewing the pane. */
469 	GtkWidget	*menu_top;		/* The top-level menu, typically shown by right-clicking. */
470 	GtkWidget	*mitem_action;		/* The item in the top-level menu that contains the actions submenu. */
471 	GtkWidget	*menu_action;		/* The menu containing the intersection of all available actions on the selection. */
472 	DirContents	dir;			/* Contents of directory (list of names etc). */
473 	DirHistory	*hist;			/* Historic data about previously visited directories. */
474 	gint		last_row;		/* The last clicked row. */
475 	gint		last_row2;		/* The second last clicked row. */
476 	gint		dbclk_row;		/* The row that was double clicked, or -1. */
477 	guint		sig_sel_changed;	/* Signal for the "changed" event on the view's GtkTreeSelection. */
478 	guint		sig_path_activate;	/* Signal for the "activate" event on path entry combo box. */
479 	guint		sig_path_changed;	/* Signal for the "changed" event on the path entry combo box. */
480 };
481 
482 /* -- Graphic user interface stuff --------------------------------------------------------- */
483 
484 struct GuiInfo {
485 	GtkWidget	*window;
486 	guint		sig_main_configure;
487 	guint		sig_main_delete;
488 	KbdContext	*kbd_ctx;		/* Keyboard context, for shortcuts. */
489 	GtkWidget	*vbox;			/* Vbox that contains entire GUI. */
490 	GtkWidget	*top;			/* A label showing status (selections, free space, etc). */
491 	GtkWidget	*panes;			/* GtkPaned widget holding DirPanes. */
492 	guint		sig_pane_notify;	/* Signal handler ID for notify::position. */
493 	GtkWidget	*middle;		/* A box holding entire middle part. */
494 	GtkWidget	*bottom;		/* Bottom part of GUI. */
495 	DirPane		pane[2];
496 	DirPane		*cur_pane;
497 
498 	gboolean	evt_button_valid;
499 	GdkEventButton	evt_button;
500 };
501 
502 /* ----------------------------------------------------------------------------------------- */
503 
504 /* These are defined in the main "gentoo.c" module, but really shouldn't be. Until they
505 ** get a module of their own, they need to be prototyped like this. :(
506 */
507 extern void	rebuild_top(MainInfo *min);
508 extern void	rebuild_middle(MainInfo *min);
509 extern void	rebuild_bottom(MainInfo *min);
510