1/* 2 Unix SMB/CIFS implementation. 3 replacement routines for broken systems 4 Copyright (C) Andrew Tridgell 1992-1998 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23 void replace_dummy(void); 24 void replace_dummy(void) {} 25 26#ifndef HAVE_FTRUNCATE 27 /******************************************************************* 28ftruncate for operating systems that don't have it 29********************************************************************/ 30 int ftruncate(int f,SMB_OFF_T l) 31{ 32 struct flock fl; 33 34 fl.l_whence = 0; 35 fl.l_len = 0; 36 fl.l_start = l; 37 fl.l_type = F_WRLCK; 38 return fcntl(f, F_FREESP, &fl); 39} 40#endif /* HAVE_FTRUNCATE */ 41 42 43#ifndef HAVE_STRLCPY 44/* like strncpy but does not 0 fill the buffer and always null 45 terminates. bufsize is the size of the destination buffer */ 46 size_t strlcpy(char *d, const char *s, size_t bufsize) 47{ 48 size_t len = strlen(s); 49 size_t ret = len; 50 if (bufsize <= 0) return 0; 51 if (len >= bufsize) len = bufsize-1; 52 memcpy(d, s, len); 53 d[len] = 0; 54 return ret; 55} 56#endif 57 58#ifndef HAVE_STRLCAT 59/* like strncat but does not 0 fill the buffer and always null 60 terminates. bufsize is the length of the buffer, which should 61 be one more than the maximum resulting string length */ 62 size_t strlcat(char *d, const char *s, size_t bufsize) 63{ 64 size_t len1 = strlen(d); 65 size_t len2 = strlen(s); 66 size_t ret = len1 + len2; 67 68 if (len1+len2 >= bufsize) { 69 len2 = bufsize - (len1+1); 70 } 71 if (len2 > 0) { 72 memcpy(d+len1, s, len2); 73 d[len1+len2] = 0; 74 } 75 return ret; 76} 77#endif 78 79#ifndef HAVE_MKTIME 80/******************************************************************* 81a mktime() replacement for those who don't have it - contributed by 82C.A. Lademann <cal@zls.com> 83Corrections by richard.kettlewell@kewill.com 84********************************************************************/ 85 86#define MINUTE 60 87#define HOUR 60*MINUTE 88#define DAY 24*HOUR 89#define YEAR 365*DAY 90 time_t mktime(struct tm *t) 91{ 92 struct tm *u; 93 time_t epoch = 0; 94 int n; 95 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 96 y, m, i; 97 98 if(t->tm_year < 70) 99 return((time_t)-1); 100 101 n = t->tm_year + 1900 - 1; 102 epoch = (t->tm_year - 70) * YEAR + 103 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY; 104 105 y = t->tm_year + 1900; 106 m = 0; 107 108 for(i = 0; i < t->tm_mon; i++) { 109 epoch += mon [m] * DAY; 110 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) 111 epoch += DAY; 112 113 if(++m > 11) { 114 m = 0; 115 y++; 116 } 117 } 118 119 epoch += (t->tm_mday - 1) * DAY; 120 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; 121 122 if((u = localtime(&epoch)) != NULL) { 123 t->tm_sec = u->tm_sec; 124 t->tm_min = u->tm_min; 125 t->tm_hour = u->tm_hour; 126 t->tm_mday = u->tm_mday; 127 t->tm_mon = u->tm_mon; 128 t->tm_year = u->tm_year; 129 t->tm_wday = u->tm_wday; 130 t->tm_yday = u->tm_yday; 131 t->tm_isdst = u->tm_isdst; 132 } 133 134 return(epoch); 135} 136#endif /* !HAVE_MKTIME */ 137 138 139 140#ifndef HAVE_RENAME 141/* Rename a file. (from libiberty in GNU binutils) */ 142 int rename(const char *zfrom, const char *zto) 143{ 144 if (link (zfrom, zto) < 0) 145 { 146 if (errno != EEXIST) 147 return -1; 148 if (unlink (zto) < 0 149 || link (zfrom, zto) < 0) 150 return -1; 151 } 152 return unlink (zfrom); 153} 154#endif /* HAVE_RENAME */ 155 156 157#ifndef HAVE_INNETGR 158#if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT) 159/* 160 * Search for a match in a netgroup. This replaces it on broken systems. 161 */ 162 int innetgr(const char *group,const char *host,const char *user,const char *dom) 163{ 164 char *hst, *usr, *dm; 165 166 setnetgrent(group); 167 while (getnetgrent(&hst, &usr, &dm)) { 168 if (((host == 0) || (hst == 0) || !strcmp(host, hst)) && 169 ((user == 0) || (usr == 0) || !strcmp(user, usr)) && 170 ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) { 171 endnetgrent(); 172 return (1); 173 } 174 } 175 endnetgrent(); 176 return (0); 177} 178#endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */ 179#endif /* HAVE_INNETGR */ 180 181 182 183#ifndef HAVE_INITGROUPS 184/**************************************************************************** 185 some systems don't have an initgroups call 186****************************************************************************/ 187 int initgroups(char *name,gid_t id) 188{ 189#ifndef HAVE_SETGROUPS 190 static int done; 191 if (!done) { 192 DEBUG(1,("WARNING: running without setgroups\n")); 193 done=1; 194 } 195 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ 196 return(0); 197#else /* HAVE_SETGROUPS */ 198 gid_t *grouplst = NULL; 199 int max_gr = groups_max(); 200 int ret; 201 int i,j; 202 struct group *g; 203 char *gr; 204 205 if((grouplst = (gid_t *)malloc(sizeof(gid_t) * max_gr)) == NULL) { 206 DEBUG(0,("initgroups: malloc fail !\n")); 207 return -1; 208 } 209 210 grouplst[0] = id; 211 i = 1; 212 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) { 213 if (g->gr_gid == id) 214 continue; 215 j = 0; 216 gr = g->gr_mem[0]; 217 while (gr && (*gr != (char)NULL)) { 218 if (strcmp(name,gr) == 0) { 219 grouplst[i] = g->gr_gid; 220 i++; 221 gr = (char *)NULL; 222 break; 223 } 224 gr = g->gr_mem[++j]; 225 } 226 } 227 endgrent(); 228 ret = sys_setgroups(i,grouplst); 229 SAFE_FREE(grouplst); 230 return ret; 231#endif /* HAVE_SETGROUPS */ 232} 233#endif /* HAVE_INITGROUPS */ 234 235 236#if (defined(SecureWare) && defined(SCO)) 237/* This is needed due to needing the nap() function but we don't want 238 to include the Xenix libraries since that will break other things... 239 BTW: system call # 0x0c28 is the same as calling nap() */ 240 long nap(long milliseconds) { 241 return syscall(0x0c28, milliseconds); 242 } 243#endif 244 245 246#ifndef HAVE_MEMMOVE 247/******************************************************************* 248safely copies memory, ensuring no overlap problems. 249this is only used if the machine does not have it's own memmove(). 250this is not the fastest algorithm in town, but it will do for our 251needs. 252********************************************************************/ 253 void *memmove(void *dest,const void *src,int size) 254{ 255 unsigned long d,s; 256 int i; 257 if (dest==src || !size) return(dest); 258 259 d = (unsigned long)dest; 260 s = (unsigned long)src; 261 262 if ((d >= (s+size)) || (s >= (d+size))) { 263 /* no overlap */ 264 memcpy(dest,src,size); 265 return(dest); 266 } 267 268 if (d < s) { 269 /* we can forward copy */ 270 if (s-d >= sizeof(int) && 271 !(s%sizeof(int)) && 272 !(d%sizeof(int)) && 273 !(size%sizeof(int))) { 274 /* do it all as words */ 275 int *idest = (int *)dest; 276 int *isrc = (int *)src; 277 size /= sizeof(int); 278 for (i=0;i<size;i++) idest[i] = isrc[i]; 279 } else { 280 /* simplest */ 281 char *cdest = (char *)dest; 282 char *csrc = (char *)src; 283 for (i=0;i<size;i++) cdest[i] = csrc[i]; 284 } 285 } else { 286 /* must backward copy */ 287 if (d-s >= sizeof(int) && 288 !(s%sizeof(int)) && 289 !(d%sizeof(int)) && 290 !(size%sizeof(int))) { 291 /* do it all as words */ 292 int *idest = (int *)dest; 293 int *isrc = (int *)src; 294 size /= sizeof(int); 295 for (i=size-1;i>=0;i--) idest[i] = isrc[i]; 296 } else { 297 /* simplest */ 298 char *cdest = (char *)dest; 299 char *csrc = (char *)src; 300 for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; 301 } 302 } 303 return(dest); 304} 305#endif /* HAVE_MEMMOVE */ 306 307#ifndef HAVE_STRDUP 308/**************************************************************************** 309duplicate a string 310****************************************************************************/ 311 char *strdup(const char *s) 312{ 313 size_t len; 314 char *ret; 315 316 if (!s) return(NULL); 317 318 len = strlen(s)+1; 319 ret = (char *)malloc(len); 320 if (!ret) return(NULL); 321 memcpy(ret,s,len); 322 return(ret); 323} 324#endif /* HAVE_STRDUP */ 325 326#ifdef REPLACE_INET_NTOA 327char *rep_inet_ntoa(struct in_addr ip) 328{ 329 unsigned char *p = (unsigned char *)&ip.s_addr; 330 static char buf[18]; 331 slprintf(buf, 17, "%d.%d.%d.%d", 332 (int)p[0], (int)p[1], (int)p[2], (int)p[3]); 333 return buf; 334} 335#endif /* REPLACE_INET_NTOA */ 336 337#ifndef HAVE_STRTOUL 338#ifndef ULONG_MAX 339#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */ 340#endif 341 342/* 343 * Convert a string to an unsigned long integer. 344 * Taken from libg++ - libiberty code. 345 * 346 * Ignores `locale' stuff. Assumes that the upper and lower case 347 * alphabets and digits are each contiguous. 348 */ 349 unsigned long strtoul(const char *nptr, char **endptr, int base) 350{ 351 const char *s = nptr; 352 unsigned long acc; 353 int c; 354 unsigned long cutoff; 355 int neg = 0, any, cutlim; 356 357 /* 358 * See strtol for comments as to the logic used. 359 */ 360 do { 361 c = *s++; 362 } while (isspace(c)); 363 if (c == '-') { 364 neg = 1; 365 c = *s++; 366 } else if (c == '+') 367 c = *s++; 368 if ((base == 0 || base == 16) && 369 c == '0' && (*s == 'x' || *s == 'X')) { 370 c = s[1]; 371 s += 2; 372 base = 16; 373 } 374 if (base == 0) 375 base = c == '0' ? 8 : 10; 376 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; 377 cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base); 378 for (acc = 0, any = 0;; c = *s++) { 379 if (isdigit(c)) 380 c -= '0'; 381 else if (isalpha(c)) 382 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 383 else 384 break; 385 if (c >= base) 386 break; 387 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 388 any = -1; 389 else { 390 any = 1; 391 acc *= base; 392 acc += c; 393 } 394 } 395 if (any < 0) { 396 acc = ULONG_MAX; 397 errno = ERANGE; 398 } else if (neg) 399 acc = -acc; 400 if (endptr != 0) 401 *endptr = (char *) (any ? s - 1 : nptr); 402 return (acc); 403} 404#endif /* HAVE_STRTOUL */ 405 406#ifndef HAVE_SETLINEBUF 407 int setlinebuf(FILE *stream) 408{ 409 return setvbuf(stream, (char *)NULL, _IOLBF, 0); 410} 411#endif /* HAVE_SETLINEBUF */ 412 413#ifndef HAVE_VSYSLOG 414#ifdef HAVE_SYSLOG 415 void vsyslog (int facility_priority, char *format, va_list arglist) 416{ 417 char *msg = NULL; 418 vasprintf(&msg, format, arglist); 419 if (!msg) 420 return; 421 syslog(facility_priority, "%s", msg); 422 SAFE_FREE(msg); 423} 424#endif /* HAVE_SYSLOG */ 425#endif /* HAVE_VSYSLOG */ 426 427 428#ifndef HAVE_TIMEGM 429/* 430 yes, I know this looks insane, but its really needed. The function in the 431 Linux timegm() manpage does not work on solaris. 432*/ 433 time_t timegm(struct tm *tm) 434{ 435 struct tm tm2, tm3; 436 time_t t; 437 438 tm2 = *tm; 439 440 t = mktime(&tm2); 441 tm3 = *localtime(&t); 442 tm2 = *tm; 443 tm2.tm_isdst = tm3.tm_isdst; 444 t = mktime(&tm2); 445 t -= TimeDiff(t); 446 447 return t; 448} 449#endif 450