2 * Create a squashfs filesystem. This is a highly compressed read only
5 * Copyright (c) 2012, 2013, 2014
6 * Phillip Lougher <phillip@squashfs.org.uk>
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 version 2,
11 * or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include <sys/ioctl.h>
41 /* flag whether progressbar display is enabled or not */
42 int display_progress_bar
= FALSE
;
44 /* flag whether the progress bar is temporarily disbled */
45 int temp_disabled
= FALSE
;
48 int cur_uncompressed
= 0, estimated_uncompressed
= 0;
51 pthread_t progress_thread
;
52 pthread_mutex_t progress_mutex
= PTHREAD_MUTEX_INITIALIZER
;
55 static void sigwinch_handler()
57 struct winsize winsize
;
59 if(ioctl(1, TIOCGWINSZ
, &winsize
) == -1) {
60 if(isatty(STDOUT_FILENO
))
61 ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
65 columns
= winsize
.ws_col
;
69 static void sigalrm_handler()
71 rotate
= (rotate
+ 1) % 4;
75 void inc_progress_bar()
81 void dec_progress_bar(int count
)
83 cur_uncompressed
-= count
;
87 void progress_bar_size(int count
)
89 estimated_uncompressed
+= count
;
93 static void progress_bar(long long current
, long long max
, int columns
)
95 char rotate_list
[] = { '|', '/', '-', '\\' };
96 int max_digits
, used
, hashes
, spaces
;
102 max_digits
= floor(log10(max
)) + 1;
103 used
= max_digits
* 2 + 11;
104 hashes
= (current
* (columns
- used
)) / max
;
105 spaces
= columns
- used
- hashes
;
107 if((current
> max
) || (columns
- used
< 0))
111 tty
= isatty(STDOUT_FILENO
);
113 static long long previous
= -1;
115 /* Updating much more frequently than this results in huge
117 if((current
% 100) != 0 && current
!= max
)
119 /* Don't update just to rotate the spinner. */
120 if(current
== previous
)
130 putchar(rotate_list
[rotate
]);
135 printf("] %*lld/%*lld", max_digits
, current
, max_digits
, max
);
136 printf(" %3lld%%", current
* 100 / max
);
141 void enable_progress_bar()
143 pthread_cleanup_push((void *) pthread_mutex_unlock
, &progress_mutex
);
144 pthread_mutex_lock(&progress_mutex
);
145 if(display_progress_bar
)
146 progress_bar(cur_uncompressed
, estimated_uncompressed
, columns
);
147 temp_disabled
= FALSE
;
148 pthread_cleanup_pop(1);
152 void disable_progress_bar()
154 pthread_cleanup_push((void *) pthread_mutex_unlock
, &progress_mutex
);
155 pthread_mutex_lock(&progress_mutex
);
156 if(display_progress_bar
)
158 temp_disabled
= TRUE
;
159 pthread_cleanup_pop(1);
163 void set_progressbar_state(int state
)
165 pthread_cleanup_push((void *) pthread_mutex_unlock
, &progress_mutex
);
166 pthread_mutex_lock(&progress_mutex
);
167 if(display_progress_bar
!= state
) {
168 if(display_progress_bar
&& !temp_disabled
) {
169 progress_bar(cur_uncompressed
, estimated_uncompressed
,
173 display_progress_bar
= state
;
175 pthread_cleanup_pop(1);
179 void *progress_thrd(void *arg
)
181 struct timespec requested_time
, remaining
;
182 struct itimerval itimerval
;
183 struct winsize winsize
;
185 if(ioctl(1, TIOCGWINSZ
, &winsize
) == -1) {
186 if(isatty(STDOUT_FILENO
))
187 ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
191 columns
= winsize
.ws_col
;
192 signal(SIGWINCH
, sigwinch_handler
);
193 signal(SIGALRM
, sigalrm_handler
);
195 itimerval
.it_value
.tv_sec
= 0;
196 itimerval
.it_value
.tv_usec
= 250000;
197 itimerval
.it_interval
.tv_sec
= 0;
198 itimerval
.it_interval
.tv_usec
= 250000;
199 setitimer(ITIMER_REAL
, &itimerval
, NULL
);
201 requested_time
.tv_sec
= 0;
202 requested_time
.tv_nsec
= 250000000;
205 int res
= nanosleep(&requested_time
, &remaining
);
207 if(res
== -1 && errno
!= EINTR
)
208 BAD_ERROR("nanosleep failed in progress thread\n");
210 pthread_mutex_lock(&progress_mutex
);
211 if(display_progress_bar
&& !temp_disabled
)
212 progress_bar(cur_uncompressed
, estimated_uncompressed
,
214 pthread_mutex_unlock(&progress_mutex
);
219 void init_progress_bar()
221 pthread_create(&progress_thread
, NULL
, progress_thrd
, NULL
);
225 void progressbar_error(char *fmt
, ...)
229 pthread_cleanup_push((void *) pthread_mutex_unlock
, &progress_mutex
);
230 pthread_mutex_lock(&progress_mutex
);
232 if(display_progress_bar
&& !temp_disabled
)
233 fprintf(stderr
, "\n");
236 vfprintf(stderr
, fmt
, ap
);
239 pthread_cleanup_pop(1);
243 void progressbar_info(char *fmt
, ...)
247 pthread_cleanup_push((void *) pthread_mutex_unlock
, &progress_mutex
);
248 pthread_mutex_lock(&progress_mutex
);
250 if(display_progress_bar
&& !temp_disabled
)
257 pthread_cleanup_pop(1);