2 * util.c miscellaneous utility subroutines for Bacula
8 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public
21 License along with this program; if not, write to the Free
22 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 #include "findlib/find.h"
31 * Various Bacula Utility subroutines
36 * Edit a number with commas, the supplied buffer
37 * must be at least 27 bytes long.
39 char *edit_uint_with_commas(uint64_t val, char *buf)
41 sprintf(buf, "%" lld, val);
42 return add_commas(buf, buf);
45 char *add_commas(char *val, char *buf)
63 for (i=0; i < 3; i++) {
72 /* Convert a string in place to lower case */
78 *str = tolower((int)(*str));
83 /* Convert spaces to non-space character.
84 * This makes scanf of fields containing spaces easier.
87 bash_spaces(char *str)
96 /* Convert non-space characters (0x1) back into spaces */
98 unbash_spaces(char *str)
107 /* Strip any trailing junk from the command */
108 void strip_trailing_junk(char *cmd)
111 p = cmd + strlen(cmd) - 1;
113 /* strip trailing junk from command */
114 while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
118 /* Strip any trailing slashes from a directory path */
119 void strip_trailing_slashes(char *dir)
122 p = dir + strlen(dir) - 1;
124 /* strip trailing slashes */
125 while ((p >= dir) && (*p == '/'))
131 * Returns: 0 on failure (EOF)
133 * new address in passed parameter
135 int skip_spaces(char **msg)
141 while (*p && *p == ' ') {
150 * Returns: 0 on failure (EOF)
152 * new address in passed parameter
154 int skip_nonspaces(char **msg)
161 while (*p && *p != ' ') {
168 /* folded search for string - case insensitive */
170 fstrsch(char *a, char *b) /* folded case search */
172 register char *s1,*s2;
173 register char c1, c2;
177 while (*s1) { /* do it the fast way */
178 if ((*s1++ | 0x20) != (*s2++ | 0x20))
179 return 0; /* failed */
181 while (*a) { /* do it over the correct slow way */
182 if (ISUPPER(c1 = *a)) {
183 c1 = tolower((int)c1);
185 if (ISUPPER(c2 = *b)) {
186 c2 = tolower((int)c2);
198 char *encode_time(time_t time, char *buf)
203 if (localtime_r(&time, &tm)) {
204 n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
205 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
206 tm.tm_hour, tm.tm_min, tm.tm_sec);
211 /***********************************************************************
212 * Encode the mode bits into a 10 character string like LS does
213 ***********************************************************************/
215 char *encode_mode(mode_t mode, char *buf)
219 *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' :
220 S_ISLNK(mode) ? 'l' : '-';
221 *cp++ = mode & S_IRUSR ? 'r' : '-';
222 *cp++ = mode & S_IWUSR ? 'w' : '-';
223 *cp++ = (mode & S_ISUID
224 ? (mode & S_IXUSR ? 's' : 'S')
225 : (mode & S_IXUSR ? 'x' : '-'));
226 *cp++ = mode & S_IRGRP ? 'r' : '-';
227 *cp++ = mode & S_IWGRP ? 'w' : '-';
228 *cp++ = (mode & S_ISGID
229 ? (mode & S_IXGRP ? 's' : 'S')
230 : (mode & S_IXGRP ? 'x' : '-'));
231 *cp++ = mode & S_IROTH ? 'r' : '-';
232 *cp++ = mode & S_IWOTH ? 'w' : '-';
233 *cp++ = (mode & S_ISVTX
234 ? (mode & S_IXOTH ? 't' : 'T')
235 : (mode & S_IXOTH ? 'x' : '-'));
241 extern char *getuser(uid_t uid);
242 extern char *getgroup(gid_t gid);
244 void print_ls_output(char *fname, char *lname, int type, struct stat *statp)
250 p = encode_mode(statp->st_mode, buf);
251 n = sprintf(p, " %2d ", (uint32_t)statp->st_nlink);
253 n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
255 n = sprintf(p, "%8ld ", statp->st_size);
257 p = encode_time(statp->st_ctime, p);
262 if (type == FT_LNK) {
277 int do_shell_expansion(char *name)
279 /* ****FIXME***** this should work for Win32 too */
289 void (*istat)(int), (*qstat)(int);
291 char echout[PATH_MAX + 256];
293 static char meta[] = "~\\$[]*?`'<>\"";
297 /* Check if any meta characters are present */
299 for (i = 0; i < len; i++) {
300 if (strchr(name, meta[i])) {
308 /* If the filename appears to be a DOS filename,
309 convert all backward slashes \ to Unix path
310 separators / and insert a \ infront of spaces. */
312 if (len >= 3 && name[1] == ':' && name[2] == '\\') {
313 for (i=2; i<len; i++)
318 /* Pass string off to the shell for interpretation */
321 switch(pid = fork()) {
327 if ((shellcmd = getenv("SHELL")) == NULL)
328 shellcmd = "/bin/sh";
329 close(1); dup(pfd[1]); /* attach pipes to stdin and stdout */
330 close(2); dup(pfd[1]);
331 for (i = 3; i < 32; i++) /* close everything else */
333 strcpy(echout, "echo "); /* form echo command */
334 strcat(echout, name);
335 execl(shellcmd, shellcmd, "-c", echout, NULL); /* give to shell */
336 exit(127); /* shouldn't get here */
338 default: /* parent */
339 /* read output from child */
340 i = read(pfd[0], echout, sizeof echout);
341 echout[--i] = 0; /* set end of string */
342 /* look for first word or first line. */
344 if (echout[i] == ' ' || echout[i] == '\n')
345 echout[i] = 0; /* keep only first one */
347 istat = signal(SIGINT, SIG_IGN);
348 qstat = signal(SIGQUIT, SIG_IGN);
349 /* wait for child to exit */
350 while ((wpid = wait(&waitstatus)) != pid && wpid != -1)
352 signal(SIGINT, istat);
353 signal(SIGQUIT, qstat);
354 strcpy(name, echout);
358 close(pfd[0]); /* close pipe */
366 #if MSC | MSDOS | __WATCOMC__
368 char prefix[100], *env, *getenv();
370 /* Home directory reference? */
371 if (*name == '~' && (env=getenv("HOME"))) {
372 strcpy(prefix, env); /* copy HOME directory name */
373 name++; /* skip over ~ in name */
374 strcat(prefix, name);
375 name--; /* get back to beginning */
376 strcpy(name, prefix); /* move back into name */